Compare commits

..

5 Commits

Author SHA1 Message Date
Bernd Bestel
dc530c80aa Released version 0.4.0 2017-04-18 21:33:44 +02:00
Bernd Bestel
6aaaa2073b Add possibility to have multiple barcodes per product 2017-04-18 21:15:45 +02:00
Bernd Bestel
4f0dc818f6 Make product overview a little bit smaller on large screens 2017-04-18 20:05:02 +02:00
Bernd Bestel
3ed6c9b28a Add a quantity unit conversion hint on product form 2017-04-18 19:54:51 +02:00
Bernd Bestel
2b8c672279 Form validation and barcode input handling improvements 2017-04-17 16:53:16 +02:00
15 changed files with 285 additions and 115 deletions

View File

@@ -72,7 +72,11 @@ class GrocyDbMigrator
{
if ($pdo->query("SELECT COUNT(*) FROM migrations WHERE migration = $migrationId")->fetchColumn() == 0)
{
$pdo->exec(utf8_encode($sql));
if ($pdo->exec(utf8_encode($sql)) === false)
{
throw new Exception($pdo->errorInfo());
}
$pdo->exec('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')');
}
}

View File

@@ -4,7 +4,7 @@ class GrocyDemoDataGenerator
{
public static function PopulateDemoData(PDO $pdo)
{
$pdo->exec(utf8_encode("
$sql = "
UPDATE locations SET name = 'Vorratskammer', description = '' WHERE id = 1;
INSERT INTO locations (name) VALUES ('S<><53>igkeitenschrank');
INSERT INTO locations (name) VALUES ('Konvervenschrank');
@@ -19,6 +19,11 @@ class GrocyDemoDataGenerator
INSERT INTO stock (product_id, amount, best_before_date, stock_id) VALUES (3, 5, date('now', '+180 day'), '".uniqid()."');
INSERT INTO stock (product_id, amount, best_before_date, stock_id) VALUES (4, 5, date('now', '+180 day'), '".uniqid()."');
INSERT INTO stock (product_id, amount, best_before_date, stock_id) VALUES (5, 5, date('now', '+25 day'), '".uniqid()."');
"));
";
if ($pdo->exec(utf8_encode($sql)) === false)
{
throw new Exception($pdo->errorInfo());
}
}
}

View File

@@ -5,7 +5,7 @@ class GrocyLogicStock
public static function GetCurrentStock()
{
$db = Grocy::GetDbConnectionRaw();
return $db->query('SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date from stock GROUP BY product_id ORDER BY MIN(best_before_date) DESC')->fetchAll(PDO::FETCH_OBJ);
return $db->query('SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date from stock GROUP BY product_id ORDER BY MIN(best_before_date) ASC')->fetchAll(PDO::FETCH_OBJ);
}
public static function GetProductDetails(int $productId)
@@ -63,7 +63,7 @@ class GrocyLogicStock
$amount -= $stockEntry->amount;
$stockEntry->delete();
}
else //Stock entry amount is > than need amount -> split the stock entry resp. update the amount
else //Stock entry amount is > than needed amount -> split the stock entry resp. update the amount
{
$consumptionRow = $db->consumptions()->createRow(array(
'product_id' => $stockEntry->product_id,

View File

@@ -14,6 +14,8 @@
"datatables.net-bs": "2.1.1",
"datatables.net-responsive": "2.1.1",
"datatables.net-responsive-bs": "2.1.1",
"jquery-timeago": "1.5.4"
"jquery-timeago": "1.5.4",
"toastr": "2.1.3",
"tagmanager": "3.0.2"
}
}

View File

@@ -2,9 +2,7 @@
class Grocy
{
private static $DbConnection;
private static $DbConnectionRaw;
/**
* @return PDO
*/
@@ -33,6 +31,7 @@ class Grocy
return self::$DbConnectionRaw;
}
private static $DbConnection;
/**
* @return LessQL\Database
*/
@@ -50,4 +49,15 @@ class Grocy
{
return file_exists(__DIR__ . '/data/demo.txt');
}
private static $InstalledVersion;
public static function GetInstalledVersion()
{
if (self::$InstalledVersion == null)
{
self::$InstalledVersion = file_get_contents(__DIR__ . '/version.txt');
}
return self::$InstalledVersion;
}
}

View File

@@ -104,4 +104,8 @@
.timeago-contextual {
font-style: italic;
font-size: 0.8em;
}
}
.disabled {
pointer-events: none;
}

View File

@@ -1 +1 @@
0.2.0
0.4.0

View File

@@ -10,14 +10,26 @@
spoiled = 1;
}
Grocy.FetchJson('/api/stock/consume-product/' + jsonForm.product_id + '/' + jsonForm.amount + '?spoiled=' + spoiled,
function(result)
Grocy.FetchJson('/api/stock/get-product-details/' + jsonForm.product_id,
function (productDetails)
{
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#amount').val(1);
$('#consumption-form').validator('validate');
Grocy.FetchJson('/api/stock/consume-product/' + jsonForm.product_id + '/' + jsonForm.amount + '?spoiled=' + spoiled,
function(result)
{
toastr.success('Removed ' + jsonForm.amount + ' ' + productDetails.quantity_unit_stock.name + ' of ' + productDetails.product.name + ' from stock');
$('#amount').val(1);
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#consumption-form').validator('validate');
},
function(xhr)
{
console.error(xhr);
}
);
},
function(xhr)
{
@@ -47,6 +59,24 @@ $('#product_id').on('change', function(e)
Grocy.EmptyElementWhenMatches('#selected-product-last-purchased-timeago', 'NaN years ago');
Grocy.EmptyElementWhenMatches('#selected-product-last-used-timeago', 'NaN years ago');
if ((productStatistics.stock_amount || 0) === 0)
{
$('#product_id').val('');
$('#product_id_text_input').val('');
$('#product_id_text_input').addClass('has-error');
$('#product_id_text_input').parent('.input-group').addClass('has-error');
$('#product_id_text_input').closest('.form-group').addClass('has-error');
$('#product-error').text('This product is not in stock.');
$('#product-error').show();
}
else
{
$('#product_id_text_input').removeClass('has-error');
$('#product_id_text_input').parent('.input-group').removeClass('has-error');
$('#product_id_text_input').closest('.form-group').removeClass('has-error');
$('#product-error').hide();
}
},
function(xhr)
{
@@ -58,23 +88,26 @@ $('#product_id').on('change', function(e)
$(function()
{
$('.datepicker').datepicker(
{
format: 'yyyy-mm-dd',
startDate: '-3d',
todayHighlight: true,
autoclose: true,
calendarWeeks: true,
orientation: 'bottom auto'
});
$('.datepicker').val(moment().format('YYYY-MM-DD'));
$('.datepicker').trigger('change');
$('.combobox').combobox({ appendId: '_text_input' });
$('#amount').val(1);
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#consumption-form').validator();
$('#consumption-form').validator('validate');
$('#consumption-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#consumption-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
});

View File

@@ -1,22 +1,16 @@
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Record consumption</h1>
<h1 class="page-header">Consumption</h1>
<form id="consumption-form">
<div class="form-group">
<label for="product_id">Product</label>
<select class="form-control combobox" id="product_id" name="product_id" required>
<label for="product_id">Product&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<select data-instockproduct="instockproduct" class="form-control combobox" id="product_id" name="product_id" required>
<option value=""></option>
<?php foreach ($products as $product) : ?>
<option value="<?php echo $product->id; ?>"><?php echo $product->name; ?></option>
<option value="<?php echo $product->id; ?>"><?php echo $product->name; ?><?php if (!empty($product->barcode)) echo ' [' . $product->barcode . ']'; ?></option>
<?php endforeach; ?>
</select>
<div class="input-group date">
<input type="text" class="form-control" id="barcode" name="barcode" />
<div class="input-group-addon">
<i class="fa fa-barcode"></i>
</div>
</div>
<div class="help-block with-errors"></div>
<div id="product-error" class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="amount">Amount</label>
@@ -32,7 +26,7 @@
</form>
</div>
<div class="col-sm-3 col-md-3 main well">
<div class="col-sm-6 col-md-5 col-lg-3 main well">
<h3>Product overview <strong><span id="selected-product-name"></span></strong></h3>
<h4><strong>Stock quantity unit:</strong> <span id="selected-product-stock-qu-name"></span></h4>

View File

@@ -1,4 +1,7 @@
$(function()
{
$('#current-stock-table').DataTable({ 'paging': false });
$('#current-stock-table').DataTable({
'paging': false,
'order': [[2, 'asc']]
});
});

View File

@@ -11,16 +11,18 @@
<title><?php echo $title; ?> | grocy</title>
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="/bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
<link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css" rel="stylesheet" />
<link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css" rel="stylesheet" />
<link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css" rel="stylesheet" />
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css" rel="stylesheet" />
<link href="/style.css" rel="stylesheet" />
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/bower_components/font-awesome/css/font-awesome.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<link href="/style.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/grocy.js"></script>
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/grocy.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
</head>
<body>
@@ -93,7 +95,7 @@
<br />
Created with passion since 2017
<br />
Version <?php echo file_get_contents('version.txt'); ?>
Version <?php echo Grocy::GetInstalledVersion(); ?>
<br />
Life runs on code
<br />
@@ -108,21 +110,23 @@
</div>
</div>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="/bower_components/bootbox/bootbox.js"></script>
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js"></script>
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
<script src="/bower_components/moment/min/moment.min.js"></script>
<script src="/bower_components/bootstrap-validator/dist/validator.min.js"></script>
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js"></script>
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js"></script>
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js"></script>
<script src="/bower_components/jquery-timeago/jquery.timeago.js"></script>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootbox/bootbox.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/moment/min/moment.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-validator/dist/validator.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
<?php if (file_exists(__DIR__ . '/' . str_replace('.php', '.js', $contentPage))) : ?>
<script src="/views/<?php echo str_replace('.php', '.js', $contentPage); ?>"></script>
<script src="/views/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . Grocy::GetInstalledVersion(); ?>"></script>
<?php endif; ?>
<?php if (file_exists(__DIR__ . '/../data/add_before_end_body.html')) include __DIR__ . '/../data/add_before_end_body.html' ?>

View File

@@ -32,7 +32,47 @@
$(function()
{
$('#barcode-taginput').tagsManager({
'hiddenTagListName': 'barcode',
'tagsContainer': '#barcode-taginput-container'
});
if (Grocy.EditMode === 'edit')
{
Grocy.FetchJson('/api/get-object/products/' + Grocy.EditObjectId,
function (product)
{
if (product.barcode.length > 0)
{
product.barcode.split(',').forEach(function(item)
{
$('#barcode-taginput').tagsManager('pushTag', item);
});
}
},
function(xhr)
{
console.error(xhr);
}
);
}
$('#qu_factor_purchase_to_stock').trigger('change');
$('#name').focus();
$('#product-form').validator();
$('#product-form').validator('validate');
});
$('.input-group-qu').on('change', function(e)
{
var factor = $('#qu_factor_purchase_to_stock').val();
if (factor > 1)
{
$('#qu-conversion-info').text('This means 1 ' + $("#qu_id_purchase option:selected").text() + ' purchased will be converted into ' + (1 * factor).toString() + ' ' + $("#qu_id_stock option:selected").text() + ' in stock.');
$('#qu-conversion-info').show();
}
else
{
$('#qu-conversion-info').hide();
}
});

View File

@@ -13,19 +13,15 @@
<input type="text" class="form-control" required id="name" name="name" value="<?php if ($mode == 'edit') echo $product->name; ?>">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="barcode">Barcode</label>
<div class="input-group date">
<input type="text" class="form-control" id="barcode" name="barcode" value="<?php if ($mode == 'edit') echo $product->barcode; ?>">
<div class="input-group-addon">
<i class="fa fa-barcode"></i>
</div>
</div>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea class="form-control" rows="2" id="description" name="description"><?php if ($mode == 'edit') echo $product->description; ?></textarea>
</div>
<div class="form-group tm-group">
<label for="barcode-taginput">Barcode(s)</label>
<input type="text" class="form-control tm-input" id="barcode-taginput" placeholder="Add (scan) a barcode here to add one...">
<div id="barcode-taginput-container"></div>
</div>
<div class="form-group">
<label for="location_id">Location</label>
<select required class="form-control" id="location_id" name="location_id">
@@ -37,7 +33,7 @@
</div>
<div class="form-group">
<label for="qu_id_purchase">Quantity unit purchase</label>
<select required class="form-control" id="qu_id_purchase" name="qu_id_purchase">
<select required class="form-control input-group-qu" id="qu_id_purchase" name="qu_id_purchase">
<?php foreach ($quantityunits as $quantityunit) : ?>
<option <?php if ($mode == 'edit' && $quantityunit->id == $product->qu_id_purchase) echo 'selected="selected"'; ?> value="<?php echo $quantityunit->id; ?>"><?php echo $quantityunit->name; ?></option>
<?php endforeach; ?>
@@ -46,7 +42,7 @@
</div>
<div class="form-group">
<label for="qu_id_stock">Quantity unit stock</label>
<select required class="form-control" id="qu_id_stock" name="qu_id_stock">
<select required class="form-control input-group-qu" id="qu_id_stock" name="qu_id_stock">
<?php foreach ($quantityunits as $quantityunit) : ?>
<option <?php if ($mode == 'edit' && $quantityunit->id == $product->qu_id_stock) echo 'selected="selected"'; ?> value="<?php echo $quantityunit->id; ?>"><?php echo $quantityunit->name; ?></option>
<?php endforeach; ?>
@@ -55,9 +51,10 @@
</div>
<div class="form-group">
<label for="qu_factor_purchase_to_stock">Factor purchase to stock quantity unit</label>
<input required min="1" type="number" class="form-control" id="qu_factor_purchase_to_stock" name="qu_factor_purchase_to_stock" value="<?php if ($mode == 'edit') echo $product->qu_factor_purchase_to_stock; else echo '1'; ?>">
<input required min="1" type="number" class="form-control input-group-qu" id="qu_factor_purchase_to_stock" name="qu_factor_purchase_to_stock" value="<?php if ($mode == 'edit') echo $product->qu_factor_purchase_to_stock; else echo '1'; ?>">
<div class="help-block with-errors"></div>
</div>
<p id="qu-conversion-info" class="help-block text-muted"></p>
<button id="save-product-button" type="submit" class="btn btn-default">Save</button>
</form>
</div>

View File

@@ -3,26 +3,28 @@
e.preventDefault();
var jsonForm = $('#purchase-form').serializeJSON();
delete jsonForm.barcode;
Grocy.FetchJson('/api/get-object/products/' + jsonForm.product_id,
function(product)
Grocy.FetchJson('/api/stock/get-product-details/' + jsonForm.product_id,
function (productDetails)
{
jsonForm.amount = jsonForm.amount * product.qu_factor_purchase_to_stock;
jsonForm.amount = jsonForm.amount * productDetails.product.qu_factor_purchase_to_stock;
Grocy.FetchJson('/api/helper/uniqid',
function (uniqidResponse)
function(uniqidResponse)
{
jsonForm.amount = jsonForm.amount * product.qu_factor_purchase_to_stock;
jsonForm.stock_id = uniqidResponse.uniqid;
Grocy.PostJson('/api/add-object/stock', jsonForm,
function(result)
{
toastr.success('Added ' + jsonForm.amount + ' ' + productDetails.quantity_unit_stock.name + ' of ' + productDetails.product.name + ' to stock');
$('#amount').val(1);
$('#best_before_date').val('');
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#amount').val(1);
$('#purchase-form').validator('validate');
},
function(xhr)
@@ -51,16 +53,16 @@ $('#product_id').on('change', function(e)
if (productId)
{
Grocy.FetchJson('/api/stock/get-product-details/' + productId,
function(productStatistics)
function(productDetails)
{
$('#selected-product-name').text(productStatistics.product.name);
$('#selected-product-stock-amount').text(productStatistics.stock_amount || '0');
$('#selected-product-stock-qu-name').text(productStatistics.quantity_unit_stock.name);
$('#selected-product-purchase-qu-name').text(productStatistics.quantity_unit_purchase.name);
$('#selected-product-last-purchased').text((productStatistics.last_purchased || 'never').substring(0, 10));
$('#selected-product-last-purchased-timeago').text($.timeago(productStatistics.last_purchased || ''));
$('#selected-product-last-used').text((productStatistics.last_used || 'never').substring(0, 10));
$('#selected-product-last-used-timeago').text($.timeago(productStatistics.last_used || ''));
$('#selected-product-name').text(productDetails.product.name);
$('#selected-product-stock-amount').text(productDetails.stock_amount || '0');
$('#selected-product-stock-qu-name').text(productDetails.quantity_unit_stock.name);
$('#selected-product-purchase-qu-name').text(productDetails.quantity_unit_purchase.name);
$('#selected-product-last-purchased').text((productDetails.last_purchased || 'never').substring(0, 10));
$('#selected-product-last-purchased-timeago').text($.timeago(productDetails.last_purchased || ''));
$('#selected-product-last-used').text((productDetails.last_used || 'never').substring(0, 10));
$('#selected-product-last-used-timeago').text($.timeago(productDetails.last_used || ''));
Grocy.EmptyElementWhenMatches('#selected-product-last-purchased-timeago', 'NaN years ago');
Grocy.EmptyElementWhenMatches('#selected-product-last-used-timeago', 'NaN years ago');
@@ -78,20 +80,98 @@ $(function()
$('.datepicker').datepicker(
{
format: 'yyyy-mm-dd',
startDate: '+7d',
startDate: '+0d',
todayHighlight: true,
autoclose: true,
calendarWeeks: true,
orientation: 'bottom auto'
orientation: 'bottom auto',
weekStart: 1,
showOnFocus: false
});
$('.datepicker').val(moment().format('YYYY-MM-DD'));
$('.datepicker').trigger('change');
$('.combobox').combobox({ appendId: '_text_input' });
$('#amount').val(1);
$('#best_before_date').val('');
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#purchase-form').validator();
$('#purchase-form').validator({
custom: {
'isodate': function($el)
{
if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
{
return 'Wrong date format, needs to be YYYY-MM-DD';
}
}
}
});
$('#purchase-form').validator('validate');
$('#purchase-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#purchase-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
});
$('#best_before_date-datepicker-button').on('click', function(e)
{
$('.datepicker').datepicker('show');
});
$('#best_before_date').on('change', function(e)
{
var value = $('#best_before_date').val();
if (value.length === 8 && $.isNumeric(value))
{
value = value.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
$('#best_before_date').val(value);
$('#purchase-form').validator('validate');
}
});
$('#best_before_date').on('keypress', function(e)
{
var element = $(e.target);
var value = element.val();
var dateObj = moment(element.val(), 'YYYY-MM-DD', true);
$('.datepicker').datepicker('hide');
if (value.length === 0)
{
element.val(moment().format('YYYY-MM-DD'));
}
else if (dateObj.isValid())
{
if (e.keyCode === 38) //Up
{
element.val(dateObj.add(-1, 'days').format('YYYY-MM-DD'));
}
else if (e.keyCode === 40) //Down
{
element.val(dateObj.add(1, 'days').format('YYYY-MM-DD'));
}
else if (e.keyCode === 37) //Left
{
element.val(dateObj.add(-1, 'weeks').format('YYYY-MM-DD'));
}
else if (e.keyCode === 39) //Right
{
element.val(dateObj.add(1, 'weeks').format('YYYY-MM-DD'));
}
}
$('#purchase-form').validator('validate');
});

View File

@@ -1,19 +1,23 @@
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Record purchase</h1>
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Purchase</h1>
<form id="purchase-form">
<div class="form-group">
<label for="product_id">Product</label>
<label for="product_id">Product&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<select class="form-control combobox" id="product_id" name="product_id" required>
<option value=""></option>
<?php foreach ($products as $product) : ?>
<option value="<?php echo $product->id; ?>"><?php echo $product->name; ?></option>
<option value="<?php echo $product->id; ?>"><?php echo $product->name; ?><?php if (!empty($product->barcode)) echo ' [' . $product->barcode . ']'; ?></option>
<?php endforeach; ?>
</select>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="best_before_date">Best before</label>
<div class="input-group date">
<input type="text" class="form-control" id="barcode" name="barcode" />
<div class="input-group-addon">
<i class="fa fa-barcode"></i>
<input type="text" data-isodate="isodate" class="form-control datepicker" id="best_before_date" name="best_before_date" required autocomplete="off">
<div id="best_before_date-datepicker-button" class="input-group-addon">
<i class="fa fa-calendar"></i>
</div>
</div>
<div class="help-block with-errors"></div>
@@ -23,21 +27,11 @@
<input type="number" class="form-control" id="amount" name="amount" value="1" min="1" required>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="best_before_date">Best before</label>
<div class="input-group date">
<input type="text" class="form-control datepicker" id="best_before_date" name="best_before_date" required>
<div class="input-group-addon">
<i class="fa fa-calendar"></i>
</div>
</div>
<div class="help-block with-errors"></div>
</div>
<button id="save-purchase-button" type="submit" class="btn btn-default">OK</button>
</form>
</div>
<div class="col-sm-3 col-md-3 main well">
<div class="col-sm-6 col-md-5 col-lg-3 main well">
<h3>Product overview <strong><span id="selected-product-name"></span></strong></h3>
<h4><strong>Purchase quantity:</strong> <span id="selected-product-purchase-qu-name"></span></h4>