Commit 89240382 authored by Malcolm Blaney's avatar Malcolm Blaney

Stock module rewrite for inline grid editing. Refactored column

editing code from Members module to generic version in the Grid
module. This is now also used by the Stock module. New SupplierOnly
function in Detail module which is used to create a supplier select
which is used when importing supplier lists in the Stock module.
parent 6e9ea53a
Pipeline #11482353 passed with stage
in 2 minutes and 10 seconds
...@@ -16,6 +16,7 @@ php/modules/Indieauth.php ...@@ -16,6 +16,7 @@ php/modules/Indieauth.php
php/modules/Invite.php php/modules/Invite.php
php/modules/Invoice.php php/modules/Invoice.php
php/modules/Manager.php php/modules/Manager.php
php/modules/Members.php
php/modules/Pager.php php/modules/Pager.php
php/modules/Payment.php php/modules/Payment.php
php/modules/Player.php php/modules/Player.php
...@@ -35,6 +36,7 @@ php/modules/Start.php ...@@ -35,6 +36,7 @@ php/modules/Start.php
php/modules/Stock.php php/modules/Stock.php
php/modules/Summary.php php/modules/Summary.php
php/modules/Turner.php php/modules/Turner.php
php/modules/Usb.php
php/modules/Viewanalytics.php php/modules/Viewanalytics.php
php/modules/Workgroup.php php/modules/Workgroup.php
php/modules/Writer.php php/modules/Writer.php
...@@ -56,6 +58,7 @@ js/dobrado.indieauth.js ...@@ -56,6 +58,7 @@ js/dobrado.indieauth.js
js/dobrado.invite.js js/dobrado.invite.js
js/dobrado.invoice.js js/dobrado.invoice.js
js/dobrado.manager.js js/dobrado.manager.js
js/dobrado.members.js
js/dobrado.pager.js js/dobrado.pager.js
js/dobrado.payment.js js/dobrado.payment.js
js/dobrado.player.js js/dobrado.player.js
...@@ -75,6 +78,7 @@ js/dobrado.start.js ...@@ -75,6 +78,7 @@ js/dobrado.start.js
js/dobrado.stock.js js/dobrado.stock.js
js/dobrado.summary.js js/dobrado.summary.js
js/dobrado.turner.js js/dobrado.turner.js
js/dobrado.usb.js
js/dobrado.viewanalytics.js js/dobrado.viewanalytics.js
js/dobrado.writer.js js/dobrado.writer.js
js/dobrado.xero.js js/dobrado.xero.js
...@@ -95,6 +99,7 @@ js/source/dobrado.indieauth.js ...@@ -95,6 +99,7 @@ js/source/dobrado.indieauth.js
js/source/dobrado.invite.js js/source/dobrado.invite.js
js/source/dobrado.invoice.js js/source/dobrado.invoice.js
js/source/dobrado.manager.js js/source/dobrado.manager.js
js/source/dobrado.members.js
js/source/dobrado.pager.js js/source/dobrado.pager.js
js/source/dobrado.payment.js js/source/dobrado.payment.js
js/source/dobrado.player.js js/source/dobrado.player.js
...@@ -114,6 +119,7 @@ js/source/dobrado.start.js ...@@ -114,6 +119,7 @@ js/source/dobrado.start.js
js/source/dobrado.stock.js js/source/dobrado.stock.js
js/source/dobrado.summary.js js/source/dobrado.summary.js
js/source/dobrado.turner.js js/source/dobrado.turner.js
js/source/dobrado.usb.js
js/source/dobrado.viewanalytics.js js/source/dobrado.viewanalytics.js
js/source/dobrado.writer.js js/source/dobrado.writer.js
js/source/dobrado.xero.js js/source/dobrado.xero.js
......
...@@ -557,6 +557,36 @@ class Detail extends Base { ...@@ -557,6 +557,36 @@ class Detail extends Base {
return $reminder_time < time() + (86400 * 14); return $reminder_time < time() + (86400 * 14);
} }
public function SupplierOnly() {
$suppliers = [];
$organiser = new Organiser($this->user, $this->owner);
$query = 'SELECT users.user, first, last FROM users LEFT JOIN user_detail '.
'ON users.user = user_detail.user WHERE supplier_only = 1 AND '.
$organiser->GroupQuery();
$mysqli = connect_db();
if ($result = $mysqli->query($query)) {
while ($user_detail = $result->fetch_assoc()) {
$user = $user_detail['user'];
$name = $user_detail['first'];
$last = $user_detail['last'];
if ($name === '') {
$name = $user;
}
else if ($last !== '') {
$name .= ' '.$last;
}
$suppliers[$user] = $name;
}
$result->close();
}
else {
$this->Log('Detail->SupplierOnly: '.$mysqli->error);
}
$mysqli->close();
return $suppliers;
}
public function UpdateField($user, $field, $value) { public function UpdateField($user, $field, $value) {
$mysqli = connect_db(); $mysqli = connect_db();
$query = 'UPDATE user_detail SET '.$field.' = "'.$value.'" WHERE '. $query = 'UPDATE user_detail SET '.$field.' = "'.$value.'" WHERE '.
......
...@@ -83,7 +83,9 @@ class Grid extends Base { ...@@ -83,7 +83,9 @@ class Grid extends Base {
'"",".slick-cell.selected","background-color","#f0f0f0"', '"",".slick-cell.selected","background-color","#f0f0f0"',
'"",".slick-cell > input[type=text]","border","none"', '"",".slick-cell > input[type=text]","border","none"',
'"",".slick-cell > input[type=text]","width","100%"', '"",".slick-cell > input[type=text]","width","100%"',
'"",".slick-cell > input[type=text]","height","100%"']; '"",".slick-cell > input[type=text]","height","100%"',
'"","button.long-text-save","float","right"',
'"","button.long-text-save","margin-left","10px"'];
$this->AddSiteStyle($site_style); $this->AddSiteStyle($site_style);
} }
......
...@@ -28,20 +28,21 @@ class Stock extends Base { ...@@ -28,20 +28,21 @@ class Stock extends Base {
$us_action = isset($_POST['action']) ? $_POST['action'] : ''; $us_action = isset($_POST['action']) ? $_POST['action'] : '';
if ($us_action === 'list') return $this->AllData(); if ($us_action === 'list') return $this->AllData();
if ($us_action === 'save') return $this->Save();
if ($us_action === 'download') return $this->Download();
if ($us_action === 'edit') return $this->EditProduct(); if ($us_action === 'edit') return $this->EditProduct();
if ($us_action === 'editMultiple') return $this->EditMultiple(); if ($us_action === 'editMultiple') return $this->EditMultiple();
if ($us_action === 'remove') return $this->RemoveProduct(); if ($us_action === 'remove') return $this->RemoveProduct();
if ($us_action === 'import') return $this->ImportData(); if ($us_action === 'import') return $this->ImportData();
if ($us_action === 'exportAll') return $this->Export();
if ($us_action === 'exportAvailable') return $this->Export(true);
if ($us_action === 'listAlternatives') return $this->AllData([], true);
if ($us_action === 'listAdjustments') return $this->ListAdjustments(); if ($us_action === 'listAdjustments') return $this->ListAdjustments();
if ($us_action === 'listAllAdjustments') return $this->ListAllAdjustments(); if ($us_action === 'listAllAdjustments') return $this->ListAllAdjustments();
if ($us_action === 'saveAdjustment') return $this->SaveAdjustment(); if ($us_action === 'saveAdjustment') return $this->SaveAdjustment();
if ($us_action === 'exportAdjustments') return $this->ExportAdjustments(); if ($us_action === 'exportAdjustments') return $this->ExportAdjustments();
if ($us_action === 'showHidden') return $this->AllData([], false, true);
if ($us_action === 'updateGroup') return $this->UpdateGroup(); if ($us_action === 'updateGroup') return $this->UpdateGroup();
if ($us_action === 'changeGroup') return $this->ChangeGroup(); if ($us_action === 'changeGroup') return $this->ChangeGroup();
if ($us_action === 'changeProfile') return $this->ChangeProfile();
if ($us_action === 'addProfile') return $this->AddProfile();
if ($us_action === 'removeProfile') return $this->RemoveProfile();
return ['error' => 'Unknown action']; return ['error' => 'Unknown action'];
} }
...@@ -61,12 +62,10 @@ class Stock extends Base { ...@@ -61,12 +62,10 @@ class Stock extends Base {
} }
public function Content($id) { public function Content($id) {
$content = '';
$base = '';
$extra_pricing = '';
$default_group = $this->user->group; $default_group = $this->user->group;
$purchase_group = isset($_SESSION['purchase-group']) ? $purchase_group = isset($_SESSION['purchase-group']) ?
$_SESSION['purchase-group'] : ''; $_SESSION['purchase-group'] : '';
$content = '<p class="stock-display-group">';
// Display a group select if this user has created invite groups. // Display a group select if this user has created invite groups.
$invite = new Invite($this->user, $this->owner); $invite = new Invite($this->user, $this->owner);
$created = $invite->Created(); $created = $invite->Created();
...@@ -74,7 +73,7 @@ class Stock extends Base { ...@@ -74,7 +73,7 @@ class Stock extends Base {
if (in_array($purchase_group, $created)) { if (in_array($purchase_group, $created)) {
$this->user->group = $purchase_group; $this->user->group = $purchase_group;
} }
$content .= '<p class="stock-display-group">Displaying stock for '. $content .= 'Displaying stock for '.
'<select id="stock-group-select">'. '<select id="stock-group-select">'.
'<option value="'.$default_group.'">'. '<option value="'.$default_group.'">'.
$this->Substitute('group-name', '', '', $default_group).'</option>'; $this->Substitute('group-name', '', '', $default_group).'</option>';
...@@ -88,116 +87,215 @@ class Stock extends Base { ...@@ -88,116 +87,215 @@ class Stock extends Base {
$this->Substitute('group-name', '', '', $group).'</option>'; $this->Substitute('group-name', '', '', $group).'</option>';
} }
} }
$content .= '</select></p>'; $content .= '</select>';
}
$order_available = $this->Substitute('stock-order-available') === 'true';
if ($order_available) {
$current = 'purchase';
$switch = 'order';
if (isset($_GET['price']) && $_GET['price'] === 'order') {
$current = 'order';
$switch = 'purchase';
}
$content .= '<span class="stock-price-info">'.
'Viewing '.$current.' price. (<a href="'.$this->Url('price='.$switch).
'">Switch to '.$switch.' price</a>)</span>';
$_SESSION['stock-price'] = $current;
} }
$content .= '</p>';
$base = '';
$extra_pricing = '';
$extra_pricing_columns = '';
if ($this->Substitute('stock-wholesale-percent') !== '') { if ($this->Substitute('stock-wholesale-percent') !== '') {
$base = 'Base '; $base = 'Cost ';
$extra_pricing .= '<div class="form-spacing">'. $extra_pricing .= '<div class="form-spacing">'.
'<label for="stock-wholesale-input">Wholesale Price:</label>'. '<label for="stock-wholesale-input">Wholesale Price:</label>'.
'<input id="stock-wholesale-input" type="text" maxlength="12">'. '<input id="stock-wholesale-input" type="text" maxlength="12">'.
'</div>'; '</div>';
$extra_pricing_columns .=
'<input type="checkbox" id="stock-column-wholesale">'.
'<label for="stock-column-wholesale">Wholesale Price</label>';
} }
if ($this->Substitute('stock-retail-percent') !== '') { if ($this->Substitute('stock-retail-percent') !== '') {
$base = 'Base '; $base = 'Cost ';
$extra_pricing .= '<div class="form-spacing">'. $extra_pricing .= '<div class="form-spacing">'.
'<label for="stock-retail-input">Retail Price:</label>'. '<label for="stock-retail-input">Retail Price:</label>'.
'<input id="stock-retail-input" type="text" maxlength="12">'. '<input id="stock-retail-input" type="text" maxlength="12">'.
'</div>'; '</div>';
$extra_pricing_columns .=
'<input type="checkbox" id="stock-column-retail">'.
'<label for="stock-column-retail">Retail Price</label>';
}
$image_input = '';
$image_column = '';
if ($this->Substitute('stock-display-images') === 'true') {
$image_column = '<input type="checkbox" id="stock-column-image">'.
'<label for="stock-column-image">Image</label>';
$image_input = '<div class="form-spacing">'.
'<label for="stock-image-input">Image:</label>'.
'<input id="stock-image-input" type="text" maxlength="200">'.
'</div>';
} }
$order_available = 'Available to members';
$order_label = 'Available to Members';
$order_column_label = 'Member Availability';
// The checkboxes in the product form are hidden so that user can select
// which options they want to update, without changing all of them.
// (Note that the value of these options must match the checkbox id.)
$checkbox_options = '<option value="">Select a field...</option>'.
'<option value="order-available">'.$order_label.'</option>';
$purchase_available = ''; $purchase_available = '';
if ($this->Substitute('stock-order-available') === 'true') { $purchase_available_column = '';
$order_available = 'Available to order'; if ($order_available) {
$purchase_available = '<div class="form-spacing">'. $order_label = 'Available to Order';
$order_column_label = 'Order Availability';
$purchase_available = '<div class="form-spacing hidden">'.
'<label for="stock-purchase-available-input">'. '<label for="stock-purchase-available-input">'.
'Available to purchase:</label>'. 'Available to Purchase:</label>'.
'<input id="stock-purchase-available-input" type="checkbox">'. '<input id="stock-purchase-available-input" type="checkbox">'.
'</div>'; '</div>';
} $purchase_available_column =
$taxable = $this->Substitute('stock-taxable'); '<input type="checkbox" id="stock-column-purchaseAvailable">'.
if ($taxable !== '') { '<label for="stock-column-purchaseAvailable">Purchase Availability'.
$taxable = '<div class="form-spacing">'. '</label>';
$checkbox_options = '<option value="">Select a field...</option>'.
'<option value="order-available">'.$order_label.'</option>'.
'<option value="purchase-available">Available to Purchase</option>';
}
$checkbox_options .=
'<option value="supplier-available">Available from Supplier</option>';
$taxable = '';
$taxable_column = '';
$taxable_label = $this->Substitute('stock-taxable');
if ($taxable_label !== '') {
$taxable = '<div class="form-spacing hidden">'.
'<label for="stock-taxable-input">'. '<label for="stock-taxable-input">'.
$taxable.':</label>'. $taxable_label.':</label>'.
'<input id="stock-taxable-input" type="checkbox">'. '<input id="stock-taxable-input" type="checkbox">'.
'</div>'; '</div>';
$taxable_column = '<input type="checkbox" id="stock-column-taxable">'.
'<label for="stock-column-taxable">Tax Status</label>';
$checkbox_options .=
'<option value="taxable">'.$taxable_label.'</option>';
} }
$composite = ''; $composite = '';
$composite_column = '';
if ($this->Substitute('stock-show-composite') === 'true') { if ($this->Substitute('stock-show-composite') === 'true') {
$composite = '<div class="form-spacing">'. $composite = '<div class="form-spacing hidden">'.
'<label for="stock-composite-input">Composite item:</label>'. '<label for="stock-composite-input">Composite Item:</label>'.
'<input id="stock-composite-input" type="checkbox">'. '<input id="stock-composite-input" type="checkbox">'.
'</div>'; '</div>';
} $composite_column = '<input type="checkbox" id="stock-column-composite">'.
$quantity = ''; '<label for="stock-column-composite">Composite Status</label>';
$quantity_dialog = ''; $checkbox_options .= '<option value="composite">Composite Item</option>';
if ($this->Substitute('stock-track-quantity') === 'true') { }
$quantity = '<div class="form-spacing">'. $bulk = '';
'<label for="stock-total-quantity-input">Total Quantity:</label>'. $bulk_column = '';
'<input id="stock-total-quantity-input" readonly="readonly" '. if ($this->Substitute('stock-bulk') === 'true') {
'type="text"> '. $bulk = '<div class="form-spacing hidden">'.
'<button class="adjust">adjust</button>'. '<label for="stock-bulk-input">Bulk Item:</label>'.
'</div>'. '<input id="stock-bulk-input" type="checkbox">'.
'<div class="form-spacing">'.
'<label for="stock-new-quantity-input">New Quantity:</label>'.
'<input id="stock-new-quantity-input" type="text">'.
'</div>'.
'<div class="form-spacing">'.
'<label for="stock-track-input">Track:</label>'.
'<input id="stock-track-input" type="checkbox">'.
'</div>'; '</div>';
$quantity_dialog = '<div class="stock-quantity-dialog hidden">'. $bulk_column = '<input type="checkbox" id="stock-column-bulk">'.
'<a href="#" class="stock-move-link">Click here to move stock</a>'. '<label for="stock-column-bulk">Bulk Status</label>';
'<div class="stock-move hidden"><b>Move to:</b>'. $checkbox_options .= '<option value="bulk">Bulk Item</option>';
'<div class="form-spacing">'. }
'<label for="stock-move-name-input">Product:</label>'. $cart = '';
'<input id="stock-move-name-input" type="text">'. $cart_column = '';
'</div>'. if ($this->Substitute('stock-cart') === 'true') {
'<div class="form-spacing">'. $cart = '<div class="form-spacing hidden">'.
'<label for="stock-move-user-input">Supplier:</label>'. '<label for="stock-cart-input">Copy to Cart:</label>'.
'<input id="stock-move-user-input" type="text">'. '<input id="stock-cart-input" type="checkbox">'.
'</div>'.
'</div>'.
'<div class="stock-adjust">'.
'<div class="form-spacing">'.
'<label for="stock-quantity-adjust-input">Total Quantity:'.
'</label>'.
'<input id="stock-quantity-adjust-input" type="text">'.
'</div>'.
'<div class="form-spacing">'.
'<label for="stock-quantity-reason-input">Reason for adjustment:'.
'</label><br>'.
'<textarea id="stock-quantity-reason-input"></textarea>'.
'</div>'.
'</div>'.
'<button class="submit">submit</button>'.
'<hr>'.
'<button class="show-all">show all</button>'.
'<button class="export">export</button>'.
'<div class="stock-adjustment-grid"></div>'.
'</div>'; '</div>';
$cart_column = '<input type="checkbox" id="stock-column-cart">'.
'<label for="stock-column-cart">Cart Status</label>';
$checkbox_options .= '<option value="cart">Copy to Cart</option>';
} }
$add_supplier = $this->GroupMember('admin', 'admin') ? $checkbox_options .= '<option value="hidden">Hidden</option>';
'<button class="stock-add-supplier">add supplier</button>' : '';
$content .= '<form id="stock-form">'. list($quantity, $quantity_columns, $quantity_dialog) =
'<button id="stock-form-pop-out">pop out form</button>'. $this->TrackQuantity();
'<div class="form-spacing">'. $add_supplier = $this->GroupMember('admin', 'admin') ?
'<label for="stock-import-file">Import:</label>'. '<button id="stock-add-supplier">Add Supplier</button>' : '';
'<input id="stock-import-file" type="file">'.
'<button class="stock-import-help" title="help">help</button>'. $content .= '<div id="stock-buttons">'.
'</div>'. '<button id="stock-import-help" title="help">Help</button>'.
'<div class="form-spacing">'. '<button id="stock-open-product-form">Open product form</button>'.
'<label for="stock-user-input">Supplier:</label>'. '<label for="stock-show-import">Import</label>'.
'<input id="stock-user-input" type="text" maxlength="50">'. '<input id="stock-show-import" type="checkbox">'.
'<span id="stock-import-wrapper">'.$this->SupplierSelect().
'<input id="stock-import-file" type="file"></span>'.
'</div>'.
'<input type="checkbox" id="stock-show-columns">'.
'<label for="stock-show-columns">Edit columns</label>'.
'<input type="checkbox" id="stock-wide-grid">'.
'<label for="stock-wide-grid">Wide grid</label>'.
'<button id="stock-download">Download</button> '.
'<select id="stock-profiles">'.
'<option value="">Profiles</option>'.
$this->CustomProfiles().
'<option value="available">Export Available</option>'.
'<option value="all">Export All</option>'.
'<option value="edit">Edit...</option>'.
'</select> '.
'<div id="stock-column-display">'.
'<button id="stock-column-left">left</button>'.
'<div id="stock-column-wrapper"><div id="stock-columns">'.
'<input type="checkbox" id="stock-column-supplier">'.
'<label for="stock-column-supplier">Supplier</label>'.
'<input type="checkbox" id="stock-column-unit">'.
'<label for="stock-column-unit">Unit</label>'.
'<input type="checkbox" id="stock-column-unitPrice">'.
'<label for="stock-column-unitPrice">Unit Price</label>'.
$quantity_columns.
'<input type="checkbox" id="stock-column-size">'.
'<label for="stock-column-size">Pack Size</label>'.
'<input type="checkbox" id="stock-column-alternative">'.
'<label for="stock-column-alternative">Alternative</label>'.
'<input type="checkbox" id="stock-column-price">'.
'<label for="stock-column-price">'.$base.'Price</label>'.
$extra_pricing_columns.
'<input type="checkbox" id="stock-column-category">'.
'<label for="stock-column-category">Category</label>'.
'<input type="checkbox" id="stock-column-description">'.
'<label for="stock-column-description">Description</label>'.
$image_column.
'<input type="checkbox" id="stock-column-grower">'.
'<label for="stock-column-grower">Grower</label>'.
'<input type="checkbox" id="stock-column-available">'.
'<label for="stock-column-available">'.$order_column_label.
'</label>'.
$purchase_available_column.
'<input type="checkbox" id="stock-column-supplierAvailable">'.
'<label for="stock-column-supplierAvailable">'.
'Supplier Availability</label>'.
$taxable_column.$composite_column.$bulk_column.$cart_column.
'<input type="checkbox" id="stock-column-hidden">'.
'<label for="stock-column-hidden">Hidden Status</label>'.
'</div></div>'.
'<button id="stock-column-right">right</button>'.
'</div><div id="stock-clear"></div>'.
'<form id="stock-form">'.
'<div id="stock-form-buttons">'.
'<button id="stock-form-previous">Previous</button>'.
'<button id="stock-form-clear">New Product</button>'.
$add_supplier. $add_supplier.
'<button id="stock-form-next">Next</button>'.
'</div>'. '</div>'.
'<div class="form-spacing">'. '<div class="form-spacing">'.
'<label for="stock-name-input">Product:</label>'. '<label for="stock-name-input">Product:</label>'.
'<input id="stock-name-input" type="text" maxlength="100">'. '<input id="stock-name-input" type="text" maxlength="100">'.
'</div>'. '</div>'.
'<div class="form-spacing">'. '<div class="form-spacing">'.
'<label for="stock-unit-select">Units:</label>'. '<label for="stock-user-input">Supplier:</label>'.
'<input id="stock-user-input" type="text" maxlength="50">'.
'</div>'.
$quantity.
'<div class="form-spacing">'.
'<label for="stock-unit-select">Unit:</label>'.
'<select id="stock-unit-select">'. '<select id="stock-unit-select">'.
'<option value="none"></option>'. '<option value="none"></option>'.
'<option value="each">each</option>'. '<option value="each">each</option>'.
...@@ -205,10 +303,9 @@ class Stock extends Base { ...@@ -205,10 +303,9 @@ class Stock extends Base {
'<option value="g">grams</option>'. '<option value="g">grams</option>'.
'<option value="L">litre</option>'. '<option value="L">litre</option>'.
'<option value="variable">as marked</option>'. '<option value="variable">as marked</option>'.
'<option value="adjusted">adjust each</option>'. '<option value="adjusted">random weight</option>'.
'</select>'. '</select>'.
'</div>'. '</div>'.
$quantity.
'<div class="form-spacing">'. '<div class="form-spacing">'.
'<label for="stock-size-input">Pack Size:</label>'. '<label for="stock-size-input">Pack Size:</label>'.
'<input id="stock-size-input" type="text" maxlength="12">'. '<input id="stock-size-input" type="text" maxlength="12">'.
...@@ -226,36 +323,54 @@ class Stock extends Base { ...@@ -226,36 +323,54 @@ class Stock extends Base {
'<input id="stock-category-input" type="text" maxlength="100">'. '<input id="stock-category-input" type="text" maxlength="100">'.
'</div>'. '</div>'.
'<div class="form-spacing">'. '<div class="form-spacing">'.
'<label for="stock-growing-input">Grower:</label>'. '<label for="stock-description-textarea">Description:</label>'.
'<input id="stock-growing-input" type="text" maxlength="200">'. '<textarea id="stock-description-textarea"></textarea>'.
'</div>'. '</div>'.
$image_input.
'<div class="form-spacing">'. '<div class="form-spacing">'.
'<label for="stock-order-available-input">'.$order_available. '<label for="stock-grower-input">Grower:</label>'.
':</label>'. '<input id="stock-grower-input" type="text" maxlength="200">'.
'</div>'.
'<div class="form-spacing">'.
'<label for="stock-checkbox-select">Update:</label>'.
'<select id="stock-checkbox-select">'.$checkbox_options.'</select>'.
'</div>'.
'<div class="form-spacing hidden">'.
'<label for="stock-order-available-input">'.
$order_label.':</label>'.
'<input id="stock-order-available-input" type="checkbox">'. '<input id="stock-order-available-input" type="checkbox">'.
'</div>'. '</div>'.
$purchase_available. $purchase_available.
'<div class="form-spacing">'. '<div class="form-spacing hidden">'.
'<label for="stock-supplier-available-input">'. '<label for="stock-supplier-available-input">'.
'Available from suppliers:</label>'. 'Available from Supplier:</label>'.
'<input id="stock-supplier-available-input" type="checkbox">'. '<input id="stock-supplier-available-input" type="checkbox">'.
'</div>'. '</div>'.
$taxable.$composite. $taxable.$composite.$bulk.$cart.
'<div class="form-spacing hidden">'.
'<label for="stock-hidden-input">Hidden:</label>'.
'<input id="stock-hidden-input" type="checkbox">'.
'</div>'.
'<button class="submit">submit</button>'. '<button class="submit">submit</button>'.
'<button class="remove">remove</button>'. '<button class="remove">remove</button>'.
'</form>'. '</form>'.
'<div class="stock-info">'. '<div class="stock-info">'.
'<span class="stock-new-available"></span>'. '<span class="stock-new-available"></span>'.
'<button class="stock-list-all hidden">show all</button>'. '<button class="stock-list-all hidden">show all</button>'.
'<button class="stock-list-alternative">'.
'show products with alternative</button>'.
'<button class="stock-export-available">export available</button>'.
'<button class="stock-export-all">export all</button>'.
'<button class="stock-show-hidden">show hidden</button>'.
'</div>'. '</div>'.
'<div class="stock-import-info">'. '<div class="stock-import-info">'.
$this->Substitute('stock-import-info'). $this->Substitute('stock-import-info').
'</div>'. '</div>'.
'<div class="stock-profile-dialog hidden">'.
'<p>The currently selected columns will be saved as a profile, '.
'please provide a name so that it can be added to the menu:</p>'.
'<div class="form-spacing">'.
'<label for="stock-profile-input">Profile Name:</label>'.
'<input id="stock-profile-input" type="text">'.
'<button id="stock-profile-add">add</button>'.
'</div>'.
$this->CustomProfiles('remove').
'</div>'.
$quantity_dialog; $quantity_dialog;
$this->user->group = $default_group; $this->user->group = $default_group;
...@@ -361,6 +476,8 @@ class Stock extends Base { ...@@ -361,6 +476,8 @@ class Stock extends Base {
'wholesale_price DECIMAL(8,2) NOT NULL,'. 'wholesale_price DECIMAL(8,2) NOT NULL,'.
'retail_price DECIMAL(8,2) NOT NULL,'. 'retail_price DECIMAL(8,2) NOT NULL,'.
'category VARCHAR(100),'. 'category VARCHAR(100),'.
'description TEXT,'.
'image VARCHAR(200),'.
'grower VARCHAR(200),'. 'grower VARCHAR(200),'.
'order_available TINYINT(1),'. 'order_available TINYINT(1),'.
'purchase_available TINYINT(1),'. 'purchase_available TINYINT(1),'.
...@@ -369,6 +486,9 @@ class Stock extends Base { ...@@ -369,6 +486,9 @@ class Stock extends Base {
'quantity DECIMAL(8,3) NOT NULL,'. 'quantity DECIMAL(8,3) NOT NULL,'.
'composite TINYINT(1) NOT NULL,'. 'composite TINYINT(1) NOT NULL,'.
'track TINYINT(1),'. 'track TINYINT(1),'.
'bulk TINYINT(1),'.
'hidden TINYINT(1),'.
'cart TINYINT(1),'.
'PRIMARY KEY(name, user)'. 'PRIMARY KEY(name, user)'.
') ENGINE=MyISAM'; ') ENGINE=MyISAM';
if (!$mysqli->query($query)) { if (!$mysqli->query($query)) {
...@@ -383,6 +503,8 @@ class Stock extends Base { ...@@ -383,6 +503,8 @@ class Stock extends Base {
'wholesale_price DECIMAL(8,2) NOT NULL,'. 'wholesale_price DECIMAL(8,2) NOT NULL,'.
'retail_price DECIMAL(8,2) NOT NULL,'. 'retail_price DECIMAL(8,2) NOT NULL,'.
'category VARCHAR(100),'. 'category VARCHAR(100),'.
'description TEXT,'.
'image VARCHAR(200),'.
'grower VARCHAR(200),'. 'grower VARCHAR(200),'.
'order_available TINYINT(1),'. 'order_available TINYINT(1),'.
'purchase_available TINYINT(1),'. 'purchase_available TINYINT(1),'.
...@@ -391,6 +513,9 @@ class Stock extends Base { ...@@ -391,6 +513,9 @@ class Stock extends Base {
'quantity DECIMAL(8,3) NOT NULL,'. 'quantity DECIMAL(8,3) NOT NULL,'.
'composite TINYINT(1) NOT NULL,'. 'composite TINYINT(1) NOT NULL,'.
'track TINYINT(1),'. 'track TINYINT(1),'.
'bulk TINYINT(1),'.
'hidden TINYINT(1),'.
'cart TINYINT(1),'.
'action ENUM("edit", "remove"),'. 'action ENUM("edit", "remove"),'.
'modified_by VARCHAR(50),'. 'modified_by VARCHAR(50),'.
'timestamp INT(10) UNSIGNED NOT NULL,'. 'timestamp INT(10) UNSIGNED NOT NULL,'.
...@@ -445,6 +570,17 @@ class Stock extends Base { ...@@ -445,6 +570,17 @@ class Stock extends Base {
if (!$mysqli->query($query)) { if (!$mysqli->query($query)) {
$this->Log('Stock->Install 6: '.$mysqli->error); $this->Log('Stock->Install 6: '.$mysqli->error);
} }
$query = 'CREATE TABLE IF NOT EXISTS stock_column_profile ('.
'name VARCHAR(100) NOT NULL,'.
'value VARCHAR(100) NOT NULL,'.
'user VARCHAR(50) NOT NULL,'.
'columns TEXT NOT NULL,'.
'sort_columns TEXT NOT NULL,'.
'PRIMARY KEY(name, user)'.
') ENGINE=MyISAM';
if (!$mysqli->query($query)) {
$this->Log('Stock->Install 7: '.$mysqli->error);
}
$us_info = '<p><b>Using Import</b><br><br>To use the import function you '. $us_info = '<p><b>Using Import</b><br><br>To use the import function you '.
'first need to have created accounts for each of your suppliers. If you '. 'first need to have created accounts for each of your suppliers. If you '.
...@@ -457,16 +593,15 @@ class Stock extends Base { ...@@ -457,16 +593,15 @@ class Stock extends Base {
'full list of products by clicking the <b>show all</b> button.</p>'. 'full list of products by clicking the <b>show all</b> button.</p>'.
'<p><b>Availability</b><br><br>Next you can update if any products '. '<p><b>Availability</b><br><br>Next you can update if any products '.
'should be made available to your members. You can hold down '. 'should be made available to your members. You can hold down '.
'<b>shift</b> or <b>ctrl</b> to select multiple items, then use the '. '<b>shift</b> or <b>ctrl</b> to select multiple items, and the form '.
'availability check boxes in the form to update their status. When '. 'will open automatically for you. When changing multiple items at once, '.
'changing multiple items at once, only the fields in the form that you '. 'only the fields in the form that you enter values for will be updated. '.
'enter values for will be updated. The rest will keep the existing '. 'The rest will keep the existing values for each item.</p>'.
'values for each item.</p>'.
'<p><b>Hidden Products</b><br><br>Sometimes the availability lists from '. '<p><b>Hidden Products</b><br><br>Sometimes the availability lists from '.
'suppliers contain more products than you\'re interested in. You can '. 'suppliers contain more products than you\'re interested in. You can '.
'hide these products by giving them a category of <b>hidden</b>. You '. 'hide these products using the <b>Hidden</b> checkbox option. You '.
'can always access them again later by clicking the '. 'can always access them again later by clicking the <b>Edit columns</b> '.
'<b>show hidden</b> button.</p>'. 'button and then the <b>Hidden Status</b> button to show all.</p>'.
'<p><b>Alternatives</b><br><br>Products with alternative pack sizes and '. '<p><b>Alternatives</b><br><br>Products with alternative pack sizes and '.
'prices can be listed in the import file (they must be on consecutive '. 'prices can be listed in the import file (they must be on consecutive '.
'lines). These products can be listed separately by clicking the '. 'lines). These products can be listed separately by clicking the '.
...@@ -480,17 +615,16 @@ class Stock extends Base { ...@@ -480,17 +615,16 @@ class Stock extends Base {
'available. One is for products from a single supplier, the other '. 'available. One is for products from a single supplier, the other '.
'contains products from multiple suppliers. The format for the first '. 'contains products from multiple suppliers. The format for the first '.
'file is <i>comma separated values</i> with the first entry being the '. 'file is <i>comma separated values</i> with the first entry being the '.
'header row:<br>Product,Description,Quantity,Pack Size,Unit,Unit Price,'. 'header row:<br>Name,Description,Quantity,Size,Unit,UnitPrice,Total,'.
'Total,GST,Grower</p>'. 'Taxable,Grower,Category</p>'.
'<p>Note that the supplier is not listed here. When using this format '. '<p>Note that the supplier is not listed here. When using this format '.
'you pick the username for the supplier <i>before importing</i>. You '. 'you pick the username for the supplier <i>before importing</i>.</p>'.
'can also optionally use the Description field to import Category, '.
'which is otherwise not imported. (To do this, set '.
'<b>stock-description-category</b> to true in your site templates.)</p>'.
'<p>The second import format is also <i>csv</i>, however since it '. '<p>The second import format is also <i>csv</i>, however since it '.
'contains the usernames of your suppliers, you don\'t need to select a '.