diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 7836fcb9..21a67c9c 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -449,6 +449,79 @@ class Statement extends ModelObject { } +/** + * ArticleCategory model. Cannot be accessed through API. + * @extends Models.ModelObject + * @memberof Models + */ +class ArticleCategory extends ModelObject { + + /** + * Properties associated to a category + * @default ['id', 'name'] + * @see {@link Models.ModelObject.props|ModelObject.props} + */ + static get props() { + return ['id', 'name']; + } + + /** + * Default values for ArticleCategory model instances. + * @default { 'id': 0, 'name': '' } + * @see {@link Models.ModelObject.default_data|ModelObject.default_data} + */ + static get default_data() { + return {'id': 0, 'name': ''}; + } + + /** + * @default {@link Formatters.ArticleCategoryFormatter} + */ + formatter() { + return ArticleCategoryFormatter; + } +} + +/** + * Article model. Cannot be accessed through API. + * @extends Models.ModelObject + * @memberof Models + */ +class Article extends ModelObject { + /** + * Properties associated to an article + * @default ['id', 'name'] + * @see {@link Models.ModelObject.props|ModelObject.props} + */ + static get props() { + return ['id', 'name', 'price', 'stock', 'category']; + } + + /** + * Default values for Article model instances. + * @default { 'id': 0, 'name': '', 'price': 0, 'stock': 0, + * 'category': new ArticleCategory() } + * @see {@link Models.ModelObject.default_data|ModelObject.default_data} + */ + static get default_data() { + return { + 'id': 0, 'name': '', 'price': 0, 'stock': 0, + 'category': new ArticleCategory(), + }; + } + + /** + * @default {@link Formatters.ArticleCategoryFormatter} + */ + formatter() { + return ArticleFormatter; + } + + // Take care of 'price' type + // API currently returns a string object (serialization of Decimal type within Django) + get price() { return this._price; } + set price(v) { this._price = floatCheck(v); } +} /* ---------- ---------- */ @@ -683,3 +756,33 @@ class StatementFormatter extends Formatter { } } + + +/** + * @memberof Formatters + * @extends Formatters.Formatter + */ + +class ArticleCategoryFormatter extends Formatter { + + /** + * Properties renderable to html. + * @default {@link Models.Statement.props} + */ + static get props() { + return ArticleCategory.props; + } + + static get _data_stock() { + return { + 'default': '', 'low': 'low', + 'ok': 'ok', 'neg': 'neg', + }; + } + + static attr_data_stock(a) { + if (a.stock >= 5) { return this._data_stock.ok; } + else if (a.stock >= -5) { return this._data_stock.low; } + else /* a.stock < -5 */ { return this._data_stock.neg; } + } +} diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 7fc56605..6454afa9 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -189,6 +189,403 @@ function booleanCheck(v) { return v == true; } +function functionCheck(v) { + if (typeof v === 'function') + return v; + return function(){}; +} + +function restrict(obj, attr_list) { + var restricted = {} ; + for (let attr of attr_list) { + restricted[attr] = obj[attr] ; + } + return restricted ; +} + +class ArticleCategory { + + constructor(id, name) { + this.id = id; + this.name = name; + } + + get id() { return this._id; } + + set id(v) { this._id = intCheck(v); } + + html(template) { + var $template = $(template) + $template.attr('id', 'data-category-'+this.id); + $template.find('td').text(this.name); + return $template ; + } + + static compare(a, b) { + return a.name.localeCompare(b.name) ; + } +} + +class Article { + + constructor () { + $.extend(this, this.constructor.default_data); + } + + static get default_data() { + return { + 'id': 0, 'name': '', 'price': 0, 'stock': 0, + 'category': new ArticleCategory(), + }; + } + + get id() { return this._id; } + get price() { return this._price; } + get stock() { return this._stock; } + + set id(v) { this._id = intCheck(v); } + set price(v) { this._price = floatCheck(v); } + set stock(v) { this._stock = intCheck(v); } + + get str_price_ukf() { + return amountToUKF(this.price, false); + } + + static get _data_stock_ok() { return ''; } + static get _data_stock_low() { return 'low'; } + static get _data_stock_neg() { return 'neg'; } + + get data_stock() { + var stock = this.stock ; + if (stock >= 5) { return this.constructor._data_stock_ok; } + else if (stock >= -5) { return this.constructor._data_stock_low; } + else /* stock < -5 */ { return this.constructor._data_stock_neg; } + } + + from(data) { + $.extend(this, this.constructor.default_data, data); + } + + html(template) { + var $template = $(template); + $template + .find('.name').text(this.name).end() + .find('.price').text(this.str_price_ukf).end() + .find('.stock').text(this.stock).end(); + $template.attr('id', 'data-article-'+this.id); + $template.attr('data-stock', this.data_stock); + return $template ; + } + + static compare(a, b) { + return a.name.localeCompare(b.name) ; + } + + reset() { + this.from({}); + } +} + +class ArticleList { + constructor() { + this.articles = []; + this.categories = []; + } + + get_or_create(id, name) { + var category = this.categories.find(c => c.id === id); + if (!category) { + category = new ArticleCategory(id, name); + this.categories.push(category); + } + return category; + } + + from(data, callback) { + callback = functionCheck(callback); + + for (let article_data of data['articles']) { + var category = this.get_or_create(article_data['category_id'], article_data['category__name']) ; + article_data = restrict(article_data, ['name', 'price', 'stock', 'id']) ; + article_data['category'] = category ; + + var article = new Article() ; + article.from(article_data) ; + this.articles.push(article) ; + } + + callback() ; + } + + fromAPI(on_success, on_error) { + on_error = functionCheck(on_error); + var that = this ; + $.ajax({ + dataType: "json", + url : "{% url 'kfet.kpsul.articles_data' %}", + method : "GET", + }) + .done((data) => this.from(data, on_success)) + .fail(on_error); + } + + display($container, $article_template, $category_template) { + this.categories.sort(ArticleCategory.compare) ; + for (let cat of this.categories) { + var cat_articles = this.articles.filter(a => a.category.id === cat.id) ; + cat_articles.sort(Article.compare); + + $container.append(cat.html($category_template)) ; + for (let art of cat_articles) { + $container.append(art.html($article_template)) ; + } + } + } + + clear() { + this.articles = []; + this.categories = [] ; + } + + find_by_id(name) { + return this.articles.find(function(a) { + return a.name === name ; + }); + } + + get_from_elt($elt) { + var id = $elt.attr('id').split('-')[2]; + + return this.articles.find(function(article) { + return (article.id == id) ; + }); + } +} + +class ArticleManager { + + constructor(env) { + this._env = env; // Global K-Psul Manager + + this._$container = $('#articles_data tbody'); + this._$input = $('#article_autocomplete'); + this._$nb = $('#article_number'); + this._category_template = '