diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css
index d592ec3f..32331d07 100644
--- a/kfet/static/kfet/css/kpsul.css
+++ b/kfet/static/kfet/css/kpsul.css
@@ -315,7 +315,7 @@ input[type=number]::-webkit-outer-spin-button {
}
#articles_data .article[data_stock="low"] {
- background:rgba(236,100,0,0.3);
+ background:rgba(236,100,0,0.3);
}
#articles_data span {
@@ -377,7 +377,10 @@ input[type=number]::-webkit-outer-spin-button {
#basket_rel, #previous_op {
border-top:1px solid #C8102E;
- padding-left: 3px;
+}
+
+#basket_rel {
+ padding-top: 35px;
}
#basket {
@@ -385,61 +388,80 @@ input[type=number]::-webkit-outer-spin-button {
}
@media (min-width:768px) {
- #basket {
- margin-right:7px;
- }
- #basket_rel {
+ #basket_rel, #previous_op {
border-top:0;
- margin-left:7px;
- margin-right:7px;
- }
- #previous_op {
- border-top:0;
- margin-left:7px;
+ margin-left:15px;
}
}
-#basket table {
+#basket > .items {
width:100%;
}
-#basket table tr {
+#basket .basket-item {
+ width: 100%;
height:25px;
font-size:14px;
}
-#basket tr .amount {
+#basket .basket-item > span {
+ display: inline-block;
+}
+
+#basket .basket-item .amount {
width:70px;
padding-right:15px;
text-align:right;
}
-#basket tr .number {
- width:50px;
+#basket .basket-item .number {
+ width:75px;
padding-right:15px;
text-align:right;
}
-#basket tr .lowstock {
- display:none;
- padding-right:15px;
+#basket .basket-item > .lowstock {
+ width: 30px;
+ padding-right: 15px;
}
-#basket tr.ui-selected, #basket tr.ui-selecting {
+#basket .basket-item .glyphicon.lowstock {
+ display: none;
+}
+
+#basket .basket-item[low_stock=true] .glyphicon.lowstock {
+ display: inline-block;
+}
+
+#basket .basket-item.ui-selected,
+#basket .basket-item.ui-selecting {
background-color:rgba(200,16,46,0.6);
color:#FFF;
}
+.basket_summary table {
+ margin: 0 auto;
+}
+
+.basket_summary table tr td:first-child {
+ padding-right: 15px;
+ font-weight: bold;
+}
+
/* History */
#previous_op .trigramme {
width:100%;
+ height: 30px;
background-color:rgba(200,16,46,0.85);
color:#FFF;
font-weight:bold;
- padding:3px;
- margin-left: -3px;
- margin-bottom: 3px;
+ padding:5px;
+ margin-bottom: 5px;
+ text-align:center;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
}
.kpsul_middle_right_col {
diff --git a/kfet/static/kfet/js/history.js b/kfet/static/kfet/js/history.js
index 0f07f73b..e110f0cc 100644
--- a/kfet/static/kfet/js/history.js
+++ b/kfet/static/kfet/js/history.js
@@ -62,7 +62,7 @@ class KHistory {
}
constructor(options) {
- var all_options = $.extend({}, this.constructor.default_options, options);
+ var all_options = $.extend(true, {}, this.constructor.default_options, options);
this.api_options = all_options.api_options;
this._$container = $('#history');
@@ -93,20 +93,8 @@ class KHistory {
}
fetch(api_options) {
- this.data.clear();
-
$.extend(this.api_options, api_options);
-
- this.data.fromAPI(this.api_options)
- .done( () => this.display_data() );
-
- }
-
- display_data() {
- this.display.clear();
- this.display.render(this.data);
- var nb_opes = this._$container.find('.ope[canceled="false"]').length;
- this._$nb_opes.text(nb_opes);
+ this.data.fromAPI(this.api_options);
}
_init_events() {
@@ -120,6 +108,16 @@ class KHistory {
that.cancel_operations(to_cancel);
}
});
+
+ $(this.data).on("changed", function() {
+ let nb_opes = 0;
+ that.data.traverse(Operation, function(o) {
+ if (!o.canceled_at)
+ nb_opes++;
+ });
+ that._$nb_opes.text(nb_opes);
+ });
+
}
cancel_operations(to_cancel) {
@@ -137,21 +135,6 @@ class KHistory {
});
}
- add_node(data) {
- var node = this.data.get_or_create(data.modelname, data.content, 0);
- this.display.add(node);
- }
-
- update_node(modelname, id, update_data) {
- var updated = this.data.update(modelname, id, update_data);
- if (!updated)
- return false;
-
- this.display.update(updated);
-
- return true;
- }
-
is_valid(opegroup) {
var options = this.api_options;
@@ -190,10 +173,10 @@ class KHistory {
'canceled_by': ope.canceled_by,
};
if (ope.modelname === 'ope') {
- this.update_node('purchase', ope.id, update_data)
- || this.update_node('specialope', ope.id, update_data);
+ this.data.update('purchase', ope.id, update_data)
+ || this.data.update('specialope', ope.id, update_data);
} else if (ope.modelname === 'transfer') {
- this.update_node('transfer', ope.id, update_data);
+ this.data.update('transfer', ope.id, update_data);
}
}
}
@@ -201,11 +184,11 @@ class KHistory {
for (let opegroup of opegroups) {
if (opegroup['cancellation']) {
let update_data = { 'amount': opegroup.amount };
- this.update_node('opegroup', opegroup.id, update_data);
+ this.data.update('opegroup', opegroup.id, update_data);
}
if (opegroup['add'] && this.is_valid(opegroup)) {
- this.add_node(opegroup);
+ this.data.create(opegroup.modelname, opegroup.content);
}
}
diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js
index 89ea0143..125eaff7 100644
--- a/kfet/static/kfet/js/kfet.api.js
+++ b/kfet/static/kfet/js/kfet.api.js
@@ -747,7 +747,7 @@ class Operation extends ModelObject {
* @see {@link Models.ModelObject.props|ModelObject.props}
*/
static get props() {
- return ['id', 'amount', 'canceled_at', 'canceled_by', 'group'];
+ return ['id', 'amount', 'canceled_at', 'canceled_by'];
}
/**
@@ -758,7 +758,6 @@ class Operation extends ModelObject {
static get default_data() {
return {
'id': '', 'amount': 0, 'canceled_at': undefined, 'canceled_by': '',
- 'group': new HistoryGroup()
};
}
@@ -933,9 +932,16 @@ class ModelForest {
* @param {Object[]} [datalist=[]]
*/
constructor(data) {
+ this._init_events();
this.from(data || {});
}
+ _init_events() {
+ $(this).on("created deleted loaded updated update_all",
+ (e) => $(this).trigger("changed", [e])
+ );
+ }
+
/**
* Return true if instance is empty
*/
@@ -964,26 +970,40 @@ class ModelForest {
* @param {Object} data
* @param {number} direction
*/
- get_or_create(modelname, data, direction) {
+ get_or_create(modelname, data, options) {
+ if (options === undefined)
+ options = {};
+
+ var existing = this.find(modelname, options.find_callback || data.id);
+
+ if (existing)
+ return existing;
+
+ return this.create(modelname, data, options);
+ }
+
+ create(modelname, data, options) {
+ options = $.extend({
+ direction: 0,
+ fire_events: true,
+ }, options);
+
var struct = this.constructor.structure;
var struct_data = struct[modelname];
var model = struct_data.model;
- var existing = this.find(modelname, data.id);
- if (existing) {
- return existing;
- }
-
var node;
if (data instanceof ModelObject)
node = data;
else
node = new model(data);
- if (direction <= 0) {
+ if (options.direction <= 0) {
var parent_name = struct_data.parent;
if (!parent_name) {
this.roots.push(node);
+ if (options.fire_events)
+ $(this).trigger("created", [node]);
return node;
}
@@ -1011,24 +1031,33 @@ class ModelForest {
parent_modelname = data.parent.modelname;
}
- var parent = this.get_or_create(parent_modelname, parent_data, -1);
+ var parent = this.get_or_create(parent_modelname, parent_data, {
+ direction: -1,
+ fire_events: false
+ });
var parent_childname = struct[parent_modelname].children;
node[parent_name] = parent;
parent[parent_childname].push(node);
}
- if (direction >= 0) {
+ if (options.direction >= 0) {
var child_name = struct_data.children;
if (data.children && data.children.length) {
for (let child_data of data.children) {
- var child = this.get_or_create(child_data.modelname, child_data.content, 1);
- var child_parent = struct[child_data.modelname];
+ var child = this.get_or_create(child_data.modelname, child_data.content, {
+ direction: 1,
+ fire_events: false
+ });
+ var child_parent = struct[child_data.modelname].parent;
child[child_parent] = node;
node[child_name].push(child);
}
}
}
+ if (options.fire_events)
+ $(this).trigger("created", [node]);
+
return node;
}
@@ -1042,9 +1071,12 @@ class ModelForest {
this.related = data.related;
for (let modelname in data.objects) {
for (let obj_data of data.objects[modelname])
- this.get_or_create(modelname, obj_data, 0);
+ this.get_or_create(modelname, obj_data, {
+ fire_events: false
+ });
}
}
+ $(this).trigger("loaded");
}
/**
@@ -1061,10 +1093,13 @@ class ModelForest {
* @param {string} modelname
* @param {function} callback
*/
- traverse(modelname, callback) {
+ traverse(model, callback) {
var that = this;
+ if (typeof model === "string")
+ model = this.constructor.structure[model].model;
+
function recurse(node) {
- if (node.constructor.verbose_name === modelname) {
+ if (node instanceof model) {
if (callback(node)) {
return true;
}
@@ -1090,36 +1125,53 @@ class ModelForest {
* @param {string} modelname
* @param {number} id
*/
- find(modelname, id) {
+ find(model, id) {
+ let test;
+ if (typeof id === "function")
+ test = id;
+ else
+ test = (node) => (node.id === id);
+
var result = null;
function callback(node) {
- if (node.id == id) {
+ if (test(node)) {
result = node;
return true;
}
}
- this.traverse(modelname, callback);
+ this.traverse(model, callback);
return result;
}
- update(modelname, id, update_data) {
- var updated = null;
+ update(model, id, update_data) {
+ let node = this.find(model, id);
- function callback(node) {
- if (node.id == id) {
- node.update(update_data);
- updated = node;
- return true;
- }
+ if (node) {
+ node.update(update_data);
+ $(this).trigger("updated", [node]);
}
- this.traverse(modelname, callback);
-
- return updated;
+ return node;
}
+
+ delete(model, id) {
+ let node = this.find(model, id);
+
+ if (!node)
+ return false;
+
+ if (!this.get_parent(node)) {
+ this.roots.splice(this.roots.indexOf(node), 1);
+ $(this).trigger("deleted", [node]);
+ return node;
+ }
+
+ // TODO: if it is not a root
+ }
+
}
@@ -1275,9 +1327,27 @@ class ForestDisplay {
constructor($container, templates, data) {
this._templates = templates;
this._$container = $container;
- this.data = data || new ModelForest();
+ this.data = data;
+
+ this._init_events();
}
+ _init_events() {
+ var that = this;
+ $(this.data).on("created", (e, created) => this.add(created));
+ $(this.data).on("deleted", (e, deleted) => this.delete(deleted));
+ $(this.data).on("loaded", () => this.display());
+ $(this.data).on("updated", (e, updated) => this.update(updated));
+ $(this.data).on("update_all", function() {
+ for (let root of that.data.roots)
+ that.update(root);
+ });
+ }
+
+ display() {
+ this.clear();
+ this.render(this.data);
+ }
/**
* Renders a node (and all its offspring) and returns the
@@ -1326,7 +1396,6 @@ class ForestDisplay {
* @param {Object} [options] Options for element render method
*/
add(node, options) {
- var struct = this.data.constructor.structure;
var existing = this.data.get_parent(node);
var first_missing = node;
@@ -1336,12 +1405,12 @@ class ForestDisplay {
}
var $to_insert = this.render_element(first_missing, options);
- if (existing) {
- this._$container.find('#'+existing.constructor.verbose_name+'-'+existing.id+'>.children')
- .prepend($to_insert);
- } else {
+ if (existing)
+ this._$container
+ .find('#'+existing.constructor.verbose_name+'-'+existing.id+'>.children')
+ .prepend($to_insert);
+ else
this._$container.prepend($to_insert);
- }
}
@@ -1379,6 +1448,11 @@ class ForestDisplay {
$to_replace.replaceWith($new_elt);
}
+ delete(data) {
+ let modelname = data.constructor.verbose_name;
+ this._$container.find('#'+modelname+'-'+data.id).remove();
+ }
+
/**
* Clears all elements from container
*/
@@ -1797,7 +1871,7 @@ class OperationFormatter extends Formatter {
* a.amount displayed according to a.is_cof and a.trigramme values.
*/
static prop_amount(a) {
- return amountDisplay(a.amount, a.group.is_cof, a.group.trigramme);
+ return amountDisplay(a.amount, a.opegroup.is_cof, a.opegroup.trigramme);
}
/**
@@ -1836,7 +1910,7 @@ class PurchaseFormatter extends OperationFormatter {
*/
static prop_addcost(a) {
if (a.addcost_for) {
- return '('+amountDisplay(a.addcost_amount, a.is_cof)
+ return '('+amountDisplay(a.addcost_amount, a.opegroup.is_cof)
+'UKF pour '+a.addcost_for+')';
} else {
return '';
diff --git a/kfet/static/kfet/js/kfet.js b/kfet/static/kfet/js/kfet.js
index a7e893b6..0c979bf6 100644
--- a/kfet/static/kfet/js/kfet.js
+++ b/kfet/static/kfet/js/kfet.js
@@ -116,6 +116,8 @@ class Config {
* @param {string} key
*/
static get(key) {
+ if (key == "addcost")
+ return this.get("addcost_for") && this.get("addcost_amount");
return this._get_or_create_config()[key];
}
diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js
index 9e14f709..94ade8df 100644
--- a/kfet/static/kfet/js/kpsul.js
+++ b/kfet/static/kfet/js/kpsul.js
@@ -12,9 +12,11 @@ class KPsulManager {
this.account_manager = new AccountManager(this);
this.checkout_manager = new CheckoutManager(this);
this.article_manager = new ArticleManager(this);
+ this.basket = new BasketManager(this);
this.history = new KHistory({
api_options: {'opesonly': true},
});
+ this.previous_basket = new PreviousBasket(this);
this._init_events();
}
@@ -22,13 +24,17 @@ class KPsulManager {
reset(soft) {
soft = soft || false;
+ this.basket.reset();
this.account_manager.reset();
this.article_manager.reset();
if (!soft) {
this.checkout_manager.reset();
- this.article_manager.reset_data();
- this.history.fetch();
+ this.previous_basket.reset();
+ Config.reset( () => {
+ this.article_manager.reset_data();
+ this.history.fetch();
+ });
}
return this;
@@ -135,8 +141,7 @@ class AccountManager {
this.display();
kpsul.focus();
- kpsul._env.updateBasketAmount();
- kpsul._env.updateBasketRel();
+ $(this).trigger("changed", [this.account]);
}
reset() {
@@ -445,8 +450,8 @@ class CheckoutSelection {
class ArticleManager {
- constructor(env) {
- this._env = env; // Global K-Psul Manager
+ constructor(kpsul) {
+ this.kpsul = kpsul; // Global K-Psul Manager
this._$container = $('#articles_data');
this._$input = $('#article_autocomplete');
@@ -481,10 +486,6 @@ class ArticleManager {
return this._$nb.val();
}
- display_list() {
- this.display.render(this.data);
- }
-
validate(article) {
this.selected.from(article);
this._$input.val(article.name);
@@ -504,18 +505,12 @@ class ArticleManager {
reset_data() {
this.display.clear();
this.data.clear();
- this.data.fromAPI()
- .done( () => this.display_list() );
+ this.data.fromAPI();
}
update_data(data) {
- for (let article_dict of data.articles) {
-
- var updated = this.data.update('article', article_dict.id, article_dict);
- if (updated) {
- this.display.update(updated);
- }
- }
+ for (let article_dict of data.articles)
+ this.data.update('article', article_dict.id, article_dict);
}
reset() {
@@ -524,6 +519,7 @@ class ArticleManager {
this._$nb.val('');
this._$input.val('');
this.autocomplete.showAll();
+ return this;
}
_init_events() {
@@ -536,7 +532,7 @@ class ArticleManager {
//Global input event (to merge ?)
this._$input.on('keydown', function(e) {
if (e.keyCode == 13 && that._$input.val() == '') {
- kpsul._env.performOperations();
+ that.kpsul._env.performOperations();
}
});
@@ -549,9 +545,8 @@ class ArticleManager {
this._$nb.on('keydown', function(e) {
if (e.keyCode == 13 && that.constructor.check_nb(that.nb) && !that.is_empty()) {
- kpsul._env.addPurchase(that.selected, that.nb);
- that.reset();
- that.focus();
+ that.kpsul.basket.add_purchase(that.selected.id, parseInt(that.nb));
+ that.reset().focus();
}
if (normalKeys.test(e.keyCode) || arrowKeys.test(e.keyCode) || e.ctrlKey) {
@@ -699,3 +694,423 @@ class ArticleAutocomplete {
this.matching = [];
}
}
+
+
+class BasketManager {
+
+ constructor(kpsul) {
+ this.kpsul = kpsul;
+
+ this._$container = $('#basket');
+
+ let item_template = '
';
+ let templates = {
+ purchase: item_template,
+ specialope: item_template,
+ };
+ this.data = new BasketData();
+ this.display = new ForestDisplay(this._$container, templates, this.data);
+
+ this.summary = new BasketSummary(this);
+ this.formset = new BasketFormset(this);
+ this.selection = new BasketSelection(this);
+
+ this._init_events();
+ }
+
+ _init_events() {
+ $(this.data).on("changed", (e) => $(this).trigger("changed", [e]));
+ $(this.kpsul.account_manager).on("changed", (e) => $(this.data).trigger("update_all", [e]));
+ }
+
+ is_empty() {
+ return this.data.is_empty();
+ }
+
+ reset() {
+ this.data.clear();
+ this.formset.reset();
+ this.selection.reset();
+ }
+
+ total_amount() {
+ let total = 0;
+ for (let ope of this.data.roots)
+ total += ope.amount;
+ return total;
+ }
+
+ add_purchase(article_id, nb) {
+ let found = this.find_purchase(article_id);
+ if (found) {
+ let new_nb = found.article_nb + nb;
+ if (new_nb > 0) {
+ found.update({
+ article_nb: found.article_nb + nb
+ });
+ $(this.data).trigger("updated", [found]);
+ this.formset.update(found.id, found.for_formset());
+ } else {
+ this.delete(found.id);
+ }
+ } else {
+ let created = this.data.create("purchase", {
+ id: this.formset.new_index(),
+ article: this.kpsul.article_manager.data.find("article", article_id),
+ article_nb: nb
+ });
+ this.formset.create(created.for_formset());
+ }
+ }
+
+ find_purchase(article_id) {
+ return this.data.find("purchase", (purchase) => purchase.article.id === article_id);
+ }
+
+ add_deposit(amount) {
+ this._add_special("deposit", amount);
+ }
+
+ add_withdraw(amount) {
+ this._add_special("withdraw", amount);
+ }
+
+ add_edit(amount) {
+ this._add_special("edit", amount);
+ }
+
+ _add_special(type, amount) {
+ let created = this.data.create("specialope", {
+ id: this.formset.new_index(),
+ type: type,
+ amount: amount
+ });
+ this.formset.create(created.for_formset());
+ }
+
+ delete(id) {
+ this.data.delete(Operation, id);
+ this.formset.delete(id);
+ }
+
+}
+
+
+class BasketData extends ModelForest {
+
+ static get structure() {
+ return {
+ purchase: {
+ model: PurchaseBasket
+ },
+ specialope: {
+ model: SpecialOperationBasket
+ }
+ };
+ }
+
+}
+
+
+class PurchaseBasket extends Purchase {
+
+ static get default_data() {
+ let defaults = $.extend({}, Purchase.default_data);
+ delete defaults.amount;
+ return defaults;
+ }
+
+ formatter() {
+ return PurchaseBasketFormatter;
+ }
+
+ for_formset() {
+ return {
+ id: this.id,
+ type: "purchase",
+ amount: 0, // avoid django error
+ article: this.article,
+ article_nb: this.article_nb
+ };
+ }
+
+ get amount() {
+ let amount_ukf = - this.article.price * this.article_nb;
+ if (Config.get('addcost')
+ && kpsul.account_manager.account.trigramme != Config.get('addcost_for')
+ && this.article.category.has_addcost)
+ amount_ukf -= Config.get('addcost_amount') * this.article_nb;
+ let reduc_divisor = 1;
+ if (kpsul.account_manager.account.is_cof)
+ reduc_divisor += Config.get('subvention_cof') / 100;
+ return amount_ukf / reduc_divisor;
+ }
+
+}
+
+
+class SpecialOperationBasket extends SpecialOperation {
+
+ formatter() {
+ return SpecialOperationBasketFormatter;
+ }
+
+ for_formset() {
+ return {
+ id: this.id,
+ type: this.type,
+ amount: this.amount
+ };
+ }
+
+}
+
+
+class ItemBasketFormatter extends Formatter {
+
+ static get props() {
+ return ['amount', 'number', 'name'];
+ }
+
+ static prop_amount(o) {
+ let account = kpsul.account_manager.account;
+ return amountDisplay(o.amount, account.is_cof, account.trigramme);
+ }
+
+}
+
+
+class PurchaseBasketFormatter extends ItemBasketFormatter {
+
+ static get attrs() {
+ return ['article_id', 'low_stock'];
+ }
+
+ static prop_number(o) {
+ return "(" + o.article_nb + "/" + o.article.stock + ")";
+ }
+
+ static prop_name(o) {
+ return o.article.name;
+ }
+
+ static attr_article_id(o) {
+ return o.article.id;
+ }
+
+ static attr_low_stock(o) {
+ let stock = o.article.stock;
+ return -5 <= stock && stock <= 5;
+ }
+
+}
+
+
+class SpecialOperationBasketFormatter extends ItemBasketFormatter {
+
+ static prop_number(o) {
+ return o.amount.toFixed(2) + '€';
+ }
+
+ static prop_name(o) {
+ return SpecialOperation.verbose_types[o.type] || '';
+ }
+
+}
+
+
+class BasketSummary {
+
+ constructor(basket) {
+ this.basket = basket;
+
+ this._$container = $("#basket_rel");
+
+ this._init_events();
+ }
+
+ _init_events() {
+ $(this.basket).on("changed", () => this.update_infos());
+ }
+
+ update_infos() {
+ let html = '';
+ if (!this.basket.is_empty() && !kpsul.account_manager.is_empty()) {
+ let account = kpsul.account_manager.account;
+ let amount = this.basket.total_amount();
+ html += 'Total | ' + amountDisplay(amount, account.is_cof, account.trigramme) + ' |
';
+ if (account.trigramme == "LIQ") {
+ let abs_amount = Math.abs(amount);
+ for (let given of [5, 10, 20])
+ if (abs_amount < given)
+ html += this.rendu(abs_amount, given);
+ } else {
+ let new_balance = account.balance + amount;
+ html += 'Nouveau solde | ' + amountDisplay(new_balance, account.is_cof) + ' |
';
+ if (new_balance < 0)
+ html += 'Manque | ' + (- new_balance).toFixed(2) + '€ |
';
+ }
+ }
+ html += '
';
+ this._$container.html(html);
+ }
+
+ rendu(amount, given) {
+ return 'Sur ' + given.toString() +'€ | ' + (given - amount).toFixed(2) + '€ |
';
+ }
+
+}
+
+
+class BasketFormset {
+
+ constructor(basket) {
+ this.basket = basket;
+
+ this._$container = $('#operation_formset');
+ this._$mngmt_total_forms_input = $('#id_form-TOTAL_FORMS');
+ this._mngmt_total_forms = 1;
+ this._prefix_regex = /__prefix__/;
+
+ this._$empty_html =
+ $('#operation_empty_html')
+ .removeAttr('id')
+ .find('label').remove().end()
+ .find('#id_form-__prefix__-DELETE').css('display', 'none').end();
+ $('#id_form-0-DELETE').prop('checked', true);
+ }
+
+ reset() {
+ this._mngmt_total_forms = 1;
+ this._$mngmt_total_forms_input.val(1);
+ this._$container.find("[data-opeindex]").remove();
+ }
+
+ new_index() {
+ let index = this._mngmt_total_forms++;
+ this._$mngmt_total_forms_input.val(index + 1);
+ return index;
+ }
+
+ create(data) {
+ let that = this;
+ let $ope = this._$empty_html.clone();
+ let index = data.id;
+
+ $ope.attr('data-opeindex', index);
+
+ $ope.find(':input').each( function() {
+ let name = $(this).attr('name').replace(that._prefix_regex, index);
+ let id = 'id_' + name;
+ $(this).attr({
+ name: name,
+ id: id
+ });
+ });
+
+ this._$container.append($ope);
+
+ this._update(index, data);
+
+ return index;
+ }
+
+ update(index, data) {
+ this._update(index, data);
+ }
+
+ delete(index) {
+ this.update(index, {
+ delete: true,
+ });
+ }
+
+ _update(index, data) {
+ let $ope = this._$container.find(`[data-opeindex=${index}]`);
+ let selector_prefix = `#id_form-${index}-`;
+
+ $ope.find(selector_prefix + 'type').val(data.type);
+
+ if (data.amount !== undefined)
+ $ope.find(selector_prefix + 'amount').val(data.amount.toFixed(2));
+ if (data.article !== undefined)
+ $ope.find(selector_prefix + 'article').val(data.article.id);
+ if (data.article_nb !== undefined)
+ $ope.find(selector_prefix + 'article_nb').val(data.article_nb);
+ if (data.delete !== undefined)
+ $ope.find(selector_prefix + 'DELETE').prop('checked', true);
+ }
+
+}
+
+
+class PreviousBasket {
+
+ constructor(kpsul) {
+ this.kpsul = kpsul;
+
+ this._$container = $("#previous_op");
+ }
+
+ update() {
+ let account = this.kpsul.account_manager.account;
+ let html = ``;
+ html += `${account.trigramme} - ${account.name}
`;
+ html += this.kpsul.basket.summary._$container.html();
+ this._$container.html(html);
+ }
+
+ reset() {
+ this._$container.html("");
+ }
+
+}
+
+
+class BasketSelection {
+
+ constructor(basket) {
+ this.basket = basket;
+ this._init();
+ }
+
+ _init() {
+ this.basket._$container.selectable({
+ filter: ".basket-item"
+ });
+ this._init_events();
+ }
+
+ _init_events() {
+ let basket = this.basket;
+ $(document).on('keydown', function (e) {
+ switch(e.which) {
+ case 46:
+ // DEL (Suppr)
+ basket._$container.find('.ui-selected').each( function() {
+ let dom_id = $(this).parent().attr("id");
+ let id = parseInt(dom_id.split("-")[1]);
+ basket.delete(id);
+ });
+ break;
+ case 38:
+ // Arrow up
+ basket._$container.find('.ui-selected').each( function() {
+ basket.add_purchase(parseInt($(this).attr('article_id')), 1);
+ });
+ break;
+ case 40:
+ // Arrow down
+ basket._$container.find('.ui-selected').each( function() {
+ basket.add_purchase(parseInt($(this).attr('article_id')), -1);
+ });
+ break;
+ }
+ });
+ }
+
+ reset() {
+ this.basket._$container.find('.ui-selected').removeClass('.ui-selected');
+ }
+
+}
diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html
index e94f5c6c..682a44b1 100644
--- a/kfet/templates/kfet/kpsul.html
+++ b/kfet/templates/kfet/kpsul.html
@@ -135,16 +135,14 @@
-
@@ -210,7 +208,7 @@ $(document).ready(function() {
url: Urls['kfet.kpsul.perform_operations'](),
data: data,
on_success: function() {
- updatePreviousOp();
+ kpsul.previous_basket.update();
coolReset();
},
on_400: function(response) {
@@ -228,234 +226,6 @@ $(document).ready(function() {
performOperations();
});
- // -----
- // Basket
- // -----
-
- var item_basket_default_html = '
| | | |
';
- var basket_container = $('#basket table');
- var arrowKeys = /^(37|38|39|40)$/;
-
- function amountEuroPurchase(article, nb) {
- var amount_euro = - article.price * nb ;
- if (Config.get('addcost_for')
- && Config.get('addcost_amount')
- && kpsul.account_manager.account.trigramme != Config.get('addcost_for')
- && article.category.has_addcost)
- amount_euro -= Config.get('addcost_amount') * nb;
- var reduc_divisor = 1;
- if (kpsul.account_manager.account.is_cof)
- reduc_divisor = 1 + Config.get('subvention_cof') / 100;
- return (amount_euro / reduc_divisor).toFixed(2);
- }
-
- function addPurchase(article, nb) {
-
- var existing = false;
- formset_container.find('[data-opeindex]').each(function () {
- var opeindex = $(this).attr('data-opeindex');
- var article_id = $(this).find('#id_form-'+opeindex+'-article').val();
- if (article_id == article.id) {
- existing = true ;
- addExistingPurchase(opeindex, nb);
- }
- });
- if (!existing) {
- var amount_euro = amountEuroPurchase(article, nb);
- var index = addPurchaseToFormset(article.id, nb, amount_euro);
- var article_basket_html = $(item_basket_default_html);
- article_basket_html
- .attr('data-opeindex', index)
- .find('.number').text('('+nb+'/'+article.stock+')').end()
- .find('.name').text(article.name).end()
- .find('.amount').text(amountToUKF(amount_euro, kpsul.account_manager.account.is_cof));
- basket_container.prepend(article_basket_html);
- if (article.is_low_stock(nb))
- article_basket_html.find('.lowstock')
- .show();
- updateBasketRel();
- }
- }
-
- function addDeposit(amount) {
- var deposit_basket_html = $(item_basket_default_html);
- var amount = parseFloat(amount).toFixed(2);
- var index = addDepositToFormset(amount);
- deposit_basket_html
- .attr('data-opeindex', index)
- .find('.number').text(amount+"€").end()
- .find('.name').text('Charge').end()
- .find('.amount').text(amountToUKF(amount, kpsul.account_manager.account.is_cof));
- basket_container.prepend(deposit_basket_html);
- updateBasketRel();
- }
-
- function addEdit(amount) {
- var deposit_basket_html = $(item_basket_default_html);
- var amount = parseFloat(amount).toFixed(2);
- var index = addEditToFormset(amount);
- deposit_basket_html
- .attr('data-opeindex', index)
- .find('.number').text(amount+"€").end()
- .find('.name').text('Édition').end()
- .find('.amount').text(amountToUKF(amount, kpsul.account_manager.account.is_cof));
- basket_container.prepend(deposit_basket_html);
- updateBasketRel();
- }
-
- function addWithdraw(amount) {
- var withdraw_basket_html = $(item_basket_default_html);
- var amount = (- parseFloat(amount)).toFixed(2);
- var index = addWithdrawToFormset(amount);
- withdraw_basket_html
- .attr('data-opeindex', index)
- .find('.number').text(amount+"€").end()
- .find('.name').text('Retrait').end()
- .find('.amount').text(amountToUKF(amount, kpsul.account_manager.account.is_cof));
- basket_container.prepend(withdraw_basket_html);
- updateBasketRel();
- }
-
- basket_container.selectable({
- filter: 'tr',
- });
-
- $(document).on('keydown', function (e) {
- switch(e.which) {
- case 46:
- // DEL (Suppr)
- basket_container.find('.ui-selected').each(function () {
- deleteFromBasket($(this).data('opeindex'));
- });
- break;
- case 38:
- // Arrow up
- basket_container.find('.ui-selected').each(function () {
- addExistingPurchase($(this).data('opeindex'), 1);
- });
- break;
- case 40:
- // Arrow down
- basket_container.find('.ui-selected').each(function () {
- addExistingPurchase($(this).data('opeindex'), -1);
- });
- break;
- }
- });
-
- function isBasketEmpty() {
- return !basket_container.find('[data-opeindex]').length;
- }
-
- function getAmountBasket() {
- var total = 0;
- formset_container.find('[data-opeindex]').each(function () {
- var opeindex = $(this).attr('data-opeindex');
- if (!$(this).find('#id_form-'+opeindex+'-DELETE').prop('checked'))
- total += parseFloat($(this).find('#id_form-'+opeindex+'-amount').val());
- });
- return total;
- }
-
- function updateBasketAmount() {
- formset_container.find('[data-opeindex]').each(function () {
- var opeindex = $(this).attr('data-opeindex');
- var deleted = $(this).find('#id_form-'+opeindex+'-DELETE').prop('checked');
- var type = $(this).find('#id_form-'+opeindex+'-type').val();
- var article_id = $(this).find('#id_form-'+opeindex+'-article').val();
- var article_nb = $(this).find('#id_form-'+opeindex+'-article_nb').val();
- var amount = $(this).find('#id_form-'+opeindex+'-amount');
- if (!deleted && type == "purchase")
- amount.val(amountEuroPurchase(article_id, article_nb));
- basket_container.find('[data-opeindex='+opeindex+'] .amount').text(amountToUKF(amount.val(), kpsul.account_manager.account.is_cof, false));
- });
- }
-
- var basketrel_container = $('#basket_rel');
-
- function updateBasketRel() {
- var basketrel_html = '';
- var account = kpsul.account_manager.account;
- var trigramme = account.trigramme;
- var is_cof = account.is_cof;
- if (trigramme == 'LIQ' && !isBasketEmpty()) {
- var amount = - getAmountBasket();
- basketrel_html += '
Total: '+amount.toFixed(2)+' €
';
- if (amount < 5)
- basketrel_html += '
Sur 5€: '+ (5-amount).toFixed(2) +' €
';
- if (amount < 10)
- basketrel_html += '
Sur 10€: '+ (10-amount).toFixed(2) +' €
';
- if (amount < 20)
- basketrel_html += '
Sur 20€: '+ (20-amount).toFixed(2) +' €
';
- } else if (trigramme != '' && !isBasketEmpty()) {
- var amount = getAmountBasket();
- var amountUKF = amountToUKF(amount, is_cof);
- var newBalance = account.balance + amount;
- var newBalanceUKF = amountToUKF(newBalance, is_cof, true);
- basketrel_html += '
Total: '+amountUKF+'
';
- basketrel_html += '
Nouveau solde: '+newBalanceUKF+'
';
- if (newBalance < 0)
- basketrel_html += '
Manque: '+ (-newBalance).toFixed(2) +' €
';
- }
- basketrel_container.html(basketrel_html);
- }
-
- function deleteFromBasket(opeindex) {
- basket_container.find('[data-opeindex='+opeindex+']').remove();
- deleteFromFormset(opeindex);
- updateBasketRel();
- }
-
- function addExistingPurchase(opeindex, nb) {
- var type = formset_container.find("#id_form-"+opeindex+"-type").val();
- var id = formset_container.find("#id_form-"+opeindex+"-article").val();
- var article = kpsul.article_manager.get_article(parseInt(id));
- var nb_before = formset_container.find("#id_form-"+opeindex+"-article_nb").val();
- var nb_after = parseInt(nb_before) + parseInt(nb);
- var amountEuro_after = amountEuroPurchase(article, nb_after);
- var amountUKF_after = amountToUKF(amountEuro_after, kpsul.account_manager.account.is_cof, false);
-
- if (type == 'purchase') {
- if (nb_after == 0) {
- deleteFromBasket(opeindex);
- } else if (nb_after > 0 && nb_after <= 25) {
- if (nb_before > 0) {
- var article_html = basket_container.find('[data-opeindex='+opeindex+']');
- article_html.find('.amount').text(amountUKF_after).end()
- .find('.number').text('('+nb_after+'/'+article.stock+')').end() ;
-
- } else {
- article_html = $(item_basket_default_html);
- article_html
- .attr('data-opeindex', opeindex)
- .find('.number').text('('+nb_after+'/'+article.stock+')').end()
- .find('.name').text(article.name).end()
- .find('.amount').text(amountUKF_after);
- basket_container.prepend(article_basket_html);
-
- }
-
- if (article.is_low_stock(nb_after))
- article_html.find('.lowstock')
- .show();
- else
- article_html.find('.lowstock')
- .hide();
- updateExistingFormset(opeindex, nb_after, amountEuro_after);
- updateBasketRel();
- }
- }
- }
-
- function resetBasket() {
- basket_container.find('tr').remove();
- mngmt_total_forms = 1;
- mngmt_total_forms_input.val(1);
- formset_container.find('div').remove();
- updateBasketRel();
- kpsul.article_manager.reset();
- }
-
// -----
// Ask deposit or withdraw
// -----
@@ -469,12 +239,12 @@ $(document).ready(function() {
function callback(amount) {
if (!$.isNumeric(amount) || amount <= 0)
return false;
- addDeposit(amount);
+ kpsul.basket.add_deposit(amount);
}
depositDialog.open({
callback: callback,
- next_focus: kpsul.article_manager,
+ next_focus: kpsul,
});
}
@@ -487,12 +257,12 @@ $(document).ready(function() {
function callback(amount) {
if (!$.isNumeric(amount))
return false;
- addEdit(amount);
+ kpsul.basket.add_edit(amount);
}
editDialog.open({
callback: callback,
- next_focus: kpsul.article_manager,
+ next_focus: kpsul,
});
}
@@ -505,12 +275,12 @@ $(document).ready(function() {
function callback(amount) {
if (!$.isNumeric(amount) || amount <= 0)
return false;
- addWithdraw(amount);
+ kpsul.basket.add_withdraw(- amount);
}
withdrawDialog.open({
callback: callback,
- next_focus: kpsul.article_manager,
+ next_focus: kpsul,
});
}
@@ -522,87 +292,6 @@ $(document).ready(function() {
depositButton.on('click', function() { askDeposit(); });
withdrawButton.on('click', function() { askWithdraw(); });
- // -----
- // Operation formset management
- // -----
-
- var operation_empty_html = $('#operation_empty_html')
- .removeAttr('id')
- .find('label').remove().end()
- .find('#id_form-__prefix__-DELETE').css('display','none').end();
- $('#id_form-0-DELETE').prop('checked',true);
-
- var formset_container = $('#operation_formset');
- var mngmt_total_forms_input = $('#id_form-TOTAL_FORMS');
- var mngmt_total_forms = 1;
- var prefix_regex = /__prefix__/;
-
- function addOperationToFormset(type, amount, article='', article_nb='') {
- var operation_html = operation_empty_html.clone();
- var index = mngmt_total_forms;
-
- operation_html.attr('data-opeindex', index);
-
- operation_html
- .find('#id_form-__prefix__-type').val(type).end()
- .find('#id_form-__prefix__-amount').val((parseFloat(amount)).toFixed(2)).end()
- .find('#id_form-__prefix__-article').val(article).end()
- .find('#id_form-__prefix__-article_nb').val(article_nb).end();
-
- mngmt_total_forms_input.val(index+1);
- mngmt_total_forms++;
-
- operation_html.find(':input').each(function() {
- var name = $(this).attr('name').replace(prefix_regex, index);
- var id = 'id_' + name;
- $(this).attr({'name': name, 'id': id});
- });
- formset_container.append(operation_html);
-
- return index;
- }
-
- function addDepositToFormset(amount) {
- return addOperationToFormset('deposit', amount, '', '');
- }
-
- function addEditToFormset(amount) {
- return addOperationToFormset('edit', amount, '', '');
- }
-
- function addWithdrawToFormset(amount) {
- return addOperationToFormset('withdraw', amount, '', '');
- }
-
- function addPurchaseToFormset(article_id, article_nb, amount=0) {
- return addOperationToFormset('purchase', amount, article_id, article_nb);
- }
-
- function deleteFromFormset(opeindex) {
- updateExistingFormset(opeindex, 0, '0.00');
- }
-
- function updateExistingFormset(opeindex, nb, amount) {
- formset_container
- .find('#id_form-'+opeindex+'-amount').val((parseFloat(amount)).toFixed(2)).end()
- .find('#id_form-'+opeindex+'-article_nb').val(nb).end()
- .find('#id_form-'+opeindex+'-DELETE').prop('checked', !nb);
- }
-
- var previousop_container = $('#previous_op');
-
- function updatePreviousOp() {
- var previousop_html = '';
- var trigramme = kpsul.account_manager.account.trigramme;
- previousop_html += '
Trigramme : '+trigramme+'
';
- previousop_html += basketrel_container.html();
- previousop_container.html(previousop_html);
- }
-
- function resetPreviousOp() {
- previousop_container.html('');
- }
-
// -----
// Addcost
// -----
@@ -654,24 +343,18 @@ $(document).ready(function() {
// Reset functions
- function coolReset(give_tri_focus=true) {
- kpsul.account_manager.reset();
- resetBasket();
+ function coolReset() {
resetComment();
resetSelectable();
- if (give_tri_focus)
- kpsul.account_manager.focus();
+ kpsul.reset(true).focus();
}
- function hardReset(give_tri_focus=true) {
- coolReset(give_tri_focus);
- kpsul.checkout_manager.reset();
- resetPreviousOp();
+ function hardReset() {
+ coolReset();
Config.reset(function() {
- kpsul.article_manager.reset_data();
displayAddcost();
- kpsul.history.fetch();
});
+ kpsul.reset().focus();
}
function resetSelectable() {
@@ -708,12 +391,12 @@ $(document).ready(function() {
case 113:
if (e.shiftKey) {
// Shift+F2 - Account reset
- account_manager
+ kpsul.account_manager
.reset()
.focus();
} else {
// F2 - Basket reset
- resetBasket();
+ kpsul.basket.reset();
kpsul.article_manager.focus();
}
return false;
@@ -746,11 +429,7 @@ $(document).ready(function() {
// -----
var env = {
- addPurchase: addPurchase,
- updateBasketAmount: updateBasketAmount,
- updateBasketRel: updateBasketRel,
performOperations: performOperations,
- coolReset: coolReset,
};
window.kpsul = new KPsulManager(env);
diff --git a/kfet/views.py b/kfet/views.py
index 6751d95b..da223e73 100644
--- a/kfet/views.py
+++ b/kfet/views.py
@@ -1564,7 +1564,6 @@ def history_json(request):
'id': ope.id,
'amount': ope.amount,
'canceled_at': ope.canceled_at,
- 'is_cof': opegroup.is_cof,
'trigramme':
opegroup.on_acc and opegroup.on_acc.trigramme or None,
'opegroup__id': opegroup.id,