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
php/modules/Invite.php
php/modules/Invoice.php
php/modules/Manager.php
php/modules/Members.php
php/modules/Pager.php
php/modules/Payment.php
php/modules/Player.php
......@@ -35,6 +36,7 @@ php/modules/Start.php
php/modules/Stock.php
php/modules/Summary.php
php/modules/Turner.php
php/modules/Usb.php
php/modules/Viewanalytics.php
php/modules/Workgroup.php
php/modules/Writer.php
......@@ -56,6 +58,7 @@ js/dobrado.indieauth.js
js/dobrado.invite.js
js/dobrado.invoice.js
js/dobrado.manager.js
js/dobrado.members.js
js/dobrado.pager.js
js/dobrado.payment.js
js/dobrado.player.js
......@@ -75,6 +78,7 @@ js/dobrado.start.js
js/dobrado.stock.js
js/dobrado.summary.js
js/dobrado.turner.js
js/dobrado.usb.js
js/dobrado.viewanalytics.js
js/dobrado.writer.js
js/dobrado.xero.js
......@@ -95,6 +99,7 @@ js/source/dobrado.indieauth.js
js/source/dobrado.invite.js
js/source/dobrado.invoice.js
js/source/dobrado.manager.js
js/source/dobrado.members.js
js/source/dobrado.pager.js
js/source/dobrado.payment.js
js/source/dobrado.player.js
......@@ -114,6 +119,7 @@ js/source/dobrado.start.js
js/source/dobrado.stock.js
js/source/dobrado.summary.js
js/source/dobrado.turner.js
js/source/dobrado.usb.js
js/source/dobrado.viewanalytics.js
js/source/dobrado.writer.js
js/source/dobrado.xero.js
......
......@@ -557,6 +557,36 @@ class Detail extends Base {
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) {
$mysqli = connect_db();
$query = 'UPDATE user_detail SET '.$field.' = "'.$value.'" WHERE '.
......
......@@ -83,7 +83,9 @@ class Grid extends Base {
'"",".slick-cell.selected","background-color","#f0f0f0"',
'"",".slick-cell > input[type=text]","border","none"',
'"",".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);
}
......
......@@ -28,20 +28,21 @@ class Stock extends Base {
$us_action = isset($_POST['action']) ? $_POST['action'] : '';
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 === 'editMultiple') return $this->EditMultiple();
if ($us_action === 'remove') return $this->RemoveProduct();
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 === 'listAllAdjustments') return $this->ListAllAdjustments();
if ($us_action === 'saveAdjustment') return $this->SaveAdjustment();
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 === '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'];
}
......@@ -61,12 +62,10 @@ class Stock extends Base {
}
public function Content($id) {
$content = '';
$base = '';
$extra_pricing = '';
$default_group = $this->user->group;
$purchase_group = isset($_SESSION['purchase-group']) ?
$_SESSION['purchase-group'] : '';
$content = '<p class="stock-display-group">';
// Display a group select if this user has created invite groups.
$invite = new Invite($this->user, $this->owner);
$created = $invite->Created();
......@@ -74,7 +73,7 @@ class Stock extends Base {
if (in_array($purchase_group, $created)) {
$this->user->group = $purchase_group;
}
$content .= '<p class="stock-display-group">Displaying stock for '.
$content .= 'Displaying stock for '.
'<select id="stock-group-select">'.
'<option value="'.$default_group.'">'.
$this->Substitute('group-name', '', '', $default_group).'</option>';
......@@ -88,116 +87,215 @@ class Stock extends Base {
$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') !== '') {
$base = 'Base ';
$base = 'Cost ';
$extra_pricing .= '<div class="form-spacing">'.
'<label for="stock-wholesale-input">Wholesale Price:</label>'.
'<input id="stock-wholesale-input" type="text" maxlength="12">'.
'</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') !== '') {
$base = 'Base ';
$base = 'Cost ';
$extra_pricing .= '<div class="form-spacing">'.
'<label for="stock-retail-input">Retail Price:</label>'.
'<input id="stock-retail-input" type="text" maxlength="12">'.
'</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 = '';
if ($this->Substitute('stock-order-available') === 'true') {
$order_available = 'Available to order';
$purchase_available = '<div class="form-spacing">'.
$purchase_available_column = '';
if ($order_available) {
$order_label = 'Available to Order';
$order_column_label = 'Order Availability';
$purchase_available = '<div class="form-spacing hidden">'.
'<label for="stock-purchase-available-input">'.
'Available to purchase:</label>'.
'Available to Purchase:</label>'.
'<input id="stock-purchase-available-input" type="checkbox">'.
'</div>';
}
$taxable = $this->Substitute('stock-taxable');
if ($taxable !== '') {
$taxable = '<div class="form-spacing">'.
$purchase_available_column =
'<input type="checkbox" id="stock-column-purchaseAvailable">'.
'<label for="stock-column-purchaseAvailable">Purchase Availability'.
'</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">'.
$taxable.':</label>'.
$taxable_label.':</label>'.
'<input id="stock-taxable-input" type="checkbox">'.
'</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_column = '';
if ($this->Substitute('stock-show-composite') === 'true') {
$composite = '<div class="form-spacing">'.
'<label for="stock-composite-input">Composite item:</label>'.
$composite = '<div class="form-spacing hidden">'.
'<label for="stock-composite-input">Composite Item:</label>'.
'<input id="stock-composite-input" type="checkbox">'.
'</div>';
}
$quantity = '';
$quantity_dialog = '';
if ($this->Substitute('stock-track-quantity') === 'true') {
$quantity = '<div class="form-spacing">'.
'<label for="stock-total-quantity-input">Total Quantity:</label>'.
'<input id="stock-total-quantity-input" readonly="readonly" '.
'type="text"> '.
'<button class="adjust">adjust</button>'.
'</div>'.
'<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">'.
$composite_column = '<input type="checkbox" id="stock-column-composite">'.
'<label for="stock-column-composite">Composite Status</label>';
$checkbox_options .= '<option value="composite">Composite Item</option>';
}
$bulk = '';
$bulk_column = '';
if ($this->Substitute('stock-bulk') === 'true') {
$bulk = '<div class="form-spacing hidden">'.
'<label for="stock-bulk-input">Bulk Item:</label>'.
'<input id="stock-bulk-input" type="checkbox">'.
'</div>';
$quantity_dialog = '<div class="stock-quantity-dialog hidden">'.
'<a href="#" class="stock-move-link">Click here to move stock</a>'.
'<div class="stock-move hidden"><b>Move to:</b>'.
'<div class="form-spacing">'.
'<label for="stock-move-name-input">Product:</label>'.
'<input id="stock-move-name-input" type="text">'.
'</div>'.
'<div class="form-spacing">'.
'<label for="stock-move-user-input">Supplier:</label>'.
'<input id="stock-move-user-input" type="text">'.
'</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>'.
$bulk_column = '<input type="checkbox" id="stock-column-bulk">'.
'<label for="stock-column-bulk">Bulk Status</label>';
$checkbox_options .= '<option value="bulk">Bulk Item</option>';
}
$cart = '';
$cart_column = '';
if ($this->Substitute('stock-cart') === 'true') {
$cart = '<div class="form-spacing hidden">'.
'<label for="stock-cart-input">Copy to Cart:</label>'.
'<input id="stock-cart-input" type="checkbox">'.
'</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') ?
'<button class="stock-add-supplier">add supplier</button>' : '';
$checkbox_options .= '<option value="hidden">Hidden</option>';
$content .= '<form id="stock-form">'.
'<button id="stock-form-pop-out">pop out form</button>'.
'<div class="form-spacing">'.
'<label for="stock-import-file">Import:</label>'.
'<input id="stock-import-file" type="file">'.
'<button class="stock-import-help" title="help">help</button>'.
'</div>'.
'<div class="form-spacing">'.
'<label for="stock-user-input">Supplier:</label>'.
'<input id="stock-user-input" type="text" maxlength="50">'.
list($quantity, $quantity_columns, $quantity_dialog) =
$this->TrackQuantity();
$add_supplier = $this->GroupMember('admin', 'admin') ?
'<button id="stock-add-supplier">Add Supplier</button>' : '';
$content .= '<div id="stock-buttons">'.
'<button id="stock-import-help" title="help">Help</button>'.
'<button id="stock-open-product-form">Open product form</button>'.
'<label for="stock-show-import">Import</label>'.
'<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.
'<button id="stock-form-next">Next</button>'.
'</div>'.
'<div class="form-spacing">'.
'<label for="stock-name-input">Product:</label>'.
'<input id="stock-name-input" type="text" maxlength="100">'.
'</div>'.
'<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">'.
'<option value="none"></option>'.
'<option value="each">each</option>'.
......@@ -205,10 +303,9 @@ class Stock extends Base {
'<option value="g">grams</option>'.
'<option value="L">litre</option>'.
'<option value="variable">as marked</option>'.
'<option value="adjusted">adjust each</option>'.
'<option value="adjusted">random weight</option>'.
'</select>'.
'</div>'.
$quantity.
'<div class="form-spacing">'.
'<label for="stock-size-input">Pack Size:</label>'.
'<input id="stock-size-input" type="text" maxlength="12">'.
......@@ -226,36 +323,54 @@ class Stock extends Base {
'<input id="stock-category-input" type="text" maxlength="100">'.
'</div>'.
'<div class="form-spacing">'.
'<label for="stock-growing-input">Grower:</label>'.
'<input id="stock-growing-input" type="text" maxlength="200">'.
'<label for="stock-description-textarea">Description:</label>'.
'<textarea id="stock-description-textarea"></textarea>'.
'</div>'.
$image_input.
'<div class="form-spacing">'.
'<label for="stock-order-available-input">'.$order_available.
':</label>'.
'<label for="stock-grower-input">Grower:</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">'.
'</div>'.
$purchase_available.
'<div class="form-spacing">'.
'<div class="form-spacing hidden">'.
'<label for="stock-supplier-available-input">'.
'Available from suppliers:</label>'.
'Available from Supplier:</label>'.
'<input id="stock-supplier-available-input" type="checkbox">'.
'</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="remove">remove</button>'.
'</form>'.
'<div class="stock-info">'.
'<span class="stock-new-available"></span>'.
'<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 class="stock-import-info">'.
$this->Substitute('stock-import-info').
'</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;
$this->user->group = $default_group;
......@@ -361,6 +476,8 @@ class Stock extends Base {
'wholesale_price DECIMAL(8,2) NOT NULL,'.
'retail_price DECIMAL(8,2) NOT NULL,'.
'category VARCHAR(100),'.
'description TEXT,'.
'image VARCHAR(200),'.
'grower VARCHAR(200),'.
'order_available TINYINT(1),'.
'purchase_available TINYINT(1),'.
......@@ -369,6 +486,9 @@ class Stock extends Base {
'quantity DECIMAL(8,3) NOT NULL,'.
'composite TINYINT(1) NOT NULL,'.
'track TINYINT(1),'.
'bulk TINYINT(1),'.
'hidden TINYINT(1),'.
'cart TINYINT(1),'.
'PRIMARY KEY(name, user)'.
') ENGINE=MyISAM';
if (!$mysqli->query($query)) {
......@@ -383,6 +503,8 @@ class Stock extends Base {
'wholesale_price DECIMAL(8,2) NOT NULL,'.
'retail_price DECIMAL(8,2) NOT NULL,'.
'category VARCHAR(100),'.
'description TEXT,'.
'image VARCHAR(200),'.
'grower VARCHAR(200),'.
'order_available TINYINT(1),'.
'purchase_available TINYINT(1),'.
......@@ -391,6 +513,9 @@ class Stock extends Base {
'quantity DECIMAL(8,3) NOT NULL,'.
'composite TINYINT(1) NOT NULL,'.
'track TINYINT(1),'.
'bulk TINYINT(1),'.
'hidden TINYINT(1),'.
'cart TINYINT(1),'.
'action ENUM("edit", "remove"),'.
'modified_by VARCHAR(50),'.
'timestamp INT(10) UNSIGNED NOT NULL,'.
......@@ -445,6 +570,17 @@ class Stock extends Base {
if (!$mysqli->query($query)) {
$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 '.
'first need to have created accounts for each of your suppliers. If you '.
......@@ -457,16 +593,15 @@ class Stock extends Base {
'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 '.
'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 '.
'availability check boxes in the form to update their status. When '.
'changing multiple items at once, only the fields in the form that you '.
'enter values for will be updated. The rest will keep the existing '.
'values for each item.</p>'.
'<b>shift</b> or <b>ctrl</b> to select multiple items, and the form '.
'will open automatically for you. When changing multiple items at once, '.
'only the fields in the form that you enter values for will be updated. '.
'The rest will keep the existing values for each item.</p>'.
'<p><b>Hidden Products</b><br><br>Sometimes the availability lists from '.
'suppliers contain more products than you\'re interested in. You can '.
'hide these products by giving them a category of <b>hidden</b>. You '.
'can always access them again later by clicking the '.
'<b>show hidden</b> button.</p>'.
'hide these products using the <b>Hidden</b> checkbox option. You '.
'can always access them again later by clicking the <b>Edit columns</b> '.
'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 '.
'prices can be listed in the import file (they must be on consecutive '.
'lines). These products can be listed separately by clicking the '.
......@@ -480,17 +615,16 @@ class Stock extends Base {
'available. One is for products from a single supplier, the other '.
'contains products from multiple suppliers. The format for the first '.
'file is <i>comma separated values</i> with the first entry being the '.
'header row:<br>Product,Description,Quantity,Pack Size,Unit,Unit Price,'.
'Total,GST,Grower</p>'.
'header row:<br>Name,Description,Quantity,Size,Unit,UnitPrice,Total,'.
'Taxable,Grower,Category</p>'.
'<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 '.
'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>'.
'you pick the username for the supplier <i>before importing</i>.</p>'.
'<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 '.
'username in the form when importing. To see the format required, you '.
'can use the export button on the page.</p>';
'username in the form when importing. The header row for this format '.
'is:<br>Name,User,Description,Quantity,Price,Wholesale,Retail,Size,Unit,'.
'Taxable,Grower,Category,Available,PurchaseAvailable,SupplierAvailable'.
'</p>';
$template = ['"stock-taxable","","Attracts GST"',
'"stock-not-taxable","","Exempt from GST"',
......@@ -500,28 +634,51 @@ class Stock extends Base {
$this->AddTemplate($template);
$site_style = ['"","#stock-form","background-color","#eeeeee"',
'"","#stock-form","border","1px solid #aaaaaa"',
'"","#stock-form","border-radius","2px"',
'"","#stock-form","padding","5px"',
'"","#stock-form label","width","14em"',
$site_style = ['"","#stock-form label","width","14em"',
'"","#stock-form label[for=stock-alternative]",'.
'"width","auto"',
'"","#stock-form label[for=stock-alternative]",'.
'"float","none"',
'"","#stock-form label[for=stock-alternative]",'.
'"margin-left","5px"',
'"",".stock-add-supplier","margin-left","5px"',
'"","label[for=stock-track-input]","float","none"',
'"","label[for=stock-track-input]","margin-left","5px"',
'"","#stock-form .submit","float","right"',
'"",".stock-show-all","margin-left","0.4em"',
'"",".stock-export-data","margin-left","100px"',
'"",".stock-quantity-dialog .export","float","right"',
'"",".stock-adjust","margin-top","15px"',
'"",".stock-info","padding","5px"',
'"",".stock-info > button","margin-left","10px"',
'"","#stock-form-pop-out","float","right"'];
'"",".stock-price-info","float","right"',
'"",".stock-price-info","font-size","0.9em"',
'"",".stock-price-info","color","#555555"',
'"",".stock-price-info","margin-top","5px"',
'"",".stock-price-info a","color","#555555"',
'"","#stock-group-select-button","width","180px"',
'"","#stock-buttons","margin-bottom","5px"',
'"","#stock-open-product-form","float","right"',
'"","#stock-import-help","float","right"',
'"","#stock-import-wrapper","display","inline-block"',
'"","#stock-import-supplier-button","width","150px"',
'"","#stock-import-file","max-width","240px"',
'"","#stock-download","float","right"',
'"","#stock-profiles-button","float","right"',
'"","#stock-profiles-button","width","110px"',
'"","#stock-column-display","padding-top","10px"',
'"","#stock-column-display","display","none"',
'"","#stock-column-left","float","left"',
'"","#stock-column-wrapper","overflow","hidden"',
'"","#stock-column-wrapper","float","left"',
'"","#stock-columns","transition","margin-left 1s"',
'"","#stock-column-right","float","right"',
'"","#stock-clear","clear","both"',
'"","#stock-form-buttons","display","flex"',
'"","#stock-form-buttons","justify-content","space-between"',
'"","#stock-form-buttons","margin-bottom","10px"',
'"","#stock-profile-add","margin-left","10px"',
'"",".stock-profile-remove","margin-right","10px"'];
$this->AddSiteStyle($site_style);
return $this->Dependencies(['invite', 'purchase']);
return $this->Dependencies(['detail', 'invite', 'purchase']);
}
public function Placement() {
......@@ -573,21 +730,109 @@ class Stock extends Base {
public function Update() {
$mysqli = connect_db();
$query = 'CREATE TABLE IF NOT EXISTS stock_order_price ('.
$query = 'ALTER TABLE stock ADD COLUMN description TEXT AFTER category';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 1: '.$mysqli->error);
}
$query = 'ALTER TABLE stock ADD COLUMN image VARCHAR(200) AFTER '.
'description';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 2: '.$mysqli->error);
}
$query = 'ALTER TABLE stock ADD COLUMN bulk TINYINT(1) AFTER track';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 3: '.$mysqli->error);
}
$query = 'ALTER TABLE stock ADD COLUMN hidden TINYINT(1) AFTER bulk';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 4: '.$mysqli->error);
}
$query = 'ALTER TABLE stock ADD COLUMN cart TINYINT(1) AFTER hidden';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 5: '.$mysqli->error);
}
$query = 'ALTER TABLE stock_history ADD COLUMN description TEXT AFTER '.
'category';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 6: '.$mysqli->error);
}
$query = 'ALTER TABLE stock_history ADD COLUMN image VARCHAR(200) AFTER '.
'description';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 7: '.$mysqli->error);
}
$query = 'ALTER TABLE stock_history ADD COLUMN bulk TINYINT(1) AFTER '.
'track';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 8: '.$mysqli->error);
}
$query = 'ALTER TABLE stock_history ADD COLUMN hidden TINYINT(1) AFTER '.
'bulk';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 9: '.$mysqli->error);
}
$query = 'ALTER TABLE stock_history ADD COLUMN cart TINYINT(1) AFTER '.
'hidden';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 10: '.$mysqli->error);
}
$query = 'UPDATE stock SET description = "", image = "", bulk = 0, '.
'hidden = 0, cart = 0';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 11: '.$mysqli->error);
}
$query = 'UPDATE stock SET hidden = 1 WHERE category = "hidden"';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 12: '.$mysqli->error);
}
$query = 'UPDATE stock SET category = "" WHERE category = "hidden"';
if (!$mysqli->query($query)) {
$this->Log('Stock->Update 13: '.$mysqli->error);
}
$query = 'CREATE TABLE IF NOT EXISTS stock_column_profile ('.
'name VARCHAR(100) NOT NULL,'.