[MERGE] point_of_sale: various fixes:

- taxes computation
- currency rounding
- paymentline keyboard focus
- css corrections
- invoice generation

bzr revid: fva@openerp.com-20130129153750-ghb4hrrc289z6kga
This commit is contained in:
Frédéric van der Essen 2013-01-29 16:37:50 +01:00
commit e1cb1c660d
8 changed files with 247 additions and 174 deletions

View File

@ -853,8 +853,7 @@ class pos_order(osv.osv):
inv_line['price_unit'] = line.price_unit
inv_line['discount'] = line.discount
inv_line['name'] = inv_name
inv_line['invoice_line_tax_id'] = ('invoice_line_tax_id' in inv_line)\
and [(6, 0, inv_line['invoice_line_tax_id'])] or []
inv_line['invoice_line_tax_id'] = [(6, 0, [x.id for x in line.product_id.taxes_id] )]
inv_line_ref.create(cr, uid, inv_line, context=context)
inv_ref.button_reset_taxes(cr, uid, [inv_id], context=context)
wf_service.trg_validate(uid, 'pos.order', order.id, 'invoice', cr)
@ -1156,7 +1155,6 @@ class pos_order_line(osv.osv):
prod = self.pool.get('product.product').browse(cr, uid, product, context=context)
taxes = prod.taxes_id
price = price_unit * (1 - (discount or 0.0) / 100.0)
taxes = account_tax_obj.compute_all(cr, uid, prod.taxes_id, price, qty, product=prod, partner=False)

View File

@ -233,7 +233,9 @@
font-style: italic;
cursor:pointer;
}
.point-of-sale .oe_pos_synch-notification.oe_inactive{
cursor: default;
}
.point-of-sale .oe_pos_synch-notification .oe_status_red{
display:inline-block;
cursor:pointer;
@ -542,7 +544,9 @@
background: -webkit-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
background: -moz-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
background: -ms-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
/* for some reason the -90deg orientation doesn't match the -webkit-linear-gradient. It should be 180deg here.
* webkit also insists on rendering *both* gradients instead of only the native one. So it doesn't looks right. ugh.
background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); */
/*background:#FFF;*/
padding: 3px;
padding-top: 15px;
@ -607,7 +611,9 @@
background: -webkit-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
background: -moz-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
background: -ms-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
/* troublesome in latest webkit
background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
*/
/*background:#FFF;*/
padding: 3px;
padding-top:15px;
@ -991,12 +997,20 @@
margin-bottom:10px;
}
.point-of-sale .order .summary .line{
float: right;
margin-right:15px;
margin-left: 15px;
padding-top:5px;
border-top: solid 2px;
border-color:#777;
}
.point-of-sale .order .summary .line .subentry{
font-size: 10px;
font-weight: normal;
text-align: center;
}
.point-of-sale .order .summary .line.empty{
text-align: right;
border-color:#BBB;
color:#999;
}

View File

@ -40,6 +40,10 @@ function openerp_pos_db(instance, module){
//cache the data in memory to avoid roundtrips to the localstorage
this.cache = {};
this.product_by_id = {};
this.product_by_ean13 = {};
this.product_by_category_id = {};
this.category_by_id = {};
this.root_category_id = 0;
this.category_products = {};
@ -49,6 +53,7 @@ function openerp_pos_db(instance, module){
this.category_search_string = {};
this.packagings_by_id = {};
this.packagings_by_product_id = {};
this.packagings_by_ean13 = {};
},
/* returns the category object from its id. If you pass a list of id as parameters, you get
* a list of category objects.
@ -137,7 +142,6 @@ function openerp_pos_db(instance, module){
/* saves a record store to the database */
save: function(store,data){
var str_data = JSON.stringify(data);
console.log('Storing '+ Math.round(str_data.length/1024.0)+' KB of data to store: '+store);
localStorage[this.name + '_' + store] = JSON.stringify(data);
this.cache[store] = data;
},
@ -153,8 +157,7 @@ function openerp_pos_db(instance, module){
return str + '\n';
},
add_products: function(products){
var stored_products = this.load('products',{});
var stored_categories = this.load('categories',{});
var stored_categories = this.product_by_category_id;
if(!products instanceof Array){
products = [products];
@ -187,10 +190,11 @@ function openerp_pos_db(instance, module){
}
this.category_search_string[ancestor] += search_string;
}
stored_products[product.id] = product;
this.product_by_id[product.id] = product;
if(product.ean13){
this.product_by_ean13[product.ean13] = product;
}
}
this.save('products',stored_products);
this.save('categories',stored_categories);
},
add_packagings: function(packagings){
for(var i = 0, len = packagings.length; i < len; i++){
@ -200,6 +204,9 @@ function openerp_pos_db(instance, module){
this.packagings_by_product_id[pack.product_id[0]] = [];
}
this.packagings_by_product_id[pack.product_id[0]].push(pack);
if(pack.ean13){
this.packagings_by_ean13[pack.ean13] = pack;
}
}
},
/* removes all the data from the database. TODO : being able to selectively remove data */
@ -219,31 +226,24 @@ function openerp_pos_db(instance, module){
return count;
},
get_product_by_id: function(id){
return this.load('products',{})[id];
return this.product_by_id[id];
},
get_product_by_ean13: function(ean13){
var products = this.load('products',{});
for(var i in products){
if( products[i] && products[i].ean13 === ean13){
return products[i];
}
if(this.product_by_ean13[ean13]){
return this.product_by_ean13[ean13];
}
for(var p in this.packagings_by_id){
var pack = this.packagings_by_id[p];
if( pack.ean === ean13){
return products[pack.product_id[0]];
}
var pack = this.packagings_by_ean13[ean13];
if(pack){
return this.product_by_id[pack.product_id[0]];
}
return undefined;
},
get_product_by_category: function(category_id){
var stored_categories = this.load('categories',{});
var stored_products = this.load('products',{});
var product_ids = stored_categories[category_id];
var product_ids = this.product_by_category_id[category_id];
var list = [];
if (product_ids) {
for (var i = 0, len = Math.min(product_ids.length, this.limit); i < len; i++) {
list.push(stored_products[product_ids[i]]);
list.push(this.product_by_id[product_ids[i]]);
}
}
return list;
@ -275,12 +275,9 @@ function openerp_pos_db(instance, module){
},
remove_order: function(order_id){
var orders = this.load('orders',[]);
console.log('Remove order:',order_id);
console.log('Order count:',orders.length);
orders = _.filter(orders, function(order){
return order.id !== order_id;
});
console.log('Order count:',orders.length);
this.save('orders',orders);
},
get_orders: function(){

View File

@ -1,6 +1,24 @@
function openerp_pos_models(instance, module){ //module is instance.point_of_sale
var QWeb = instance.web.qweb;
// rounds a value with a fixed number of decimals.
// round(3.141492,2) -> 3.14
function round(value,decimals){
var mult = Math.pow(10,decimals || 0);
return Math.round(value*mult)/mult;
}
window.round = round;
// rounds a value with decimal form precision
// round(3.141592,0.025) ->3.125
function round_pr(value,precision){
if(!precision || precision < 0){
throw new Error('round_pr(): needs a precision greater than zero, got '+precision+' instead');
}
return Math.round(value / precision) * precision;
}
window.round_pr = round_pr;
// The PosModel contains the Point Of Sale's representation of the backend.
// Since the PoS must work in standalone ( Without connection to the server )
@ -24,8 +42,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
this.proxy = new module.ProxyDevice(); // used to communicate to the hardware devices via a local proxy
this.db = new module.PosLS(); // a database used to store the products and categories
this.db.clear('products','categories');
this.debug = jQuery.deparam(jQuery.param.querystring()).debug !== undefined; //debug mode
this.debug = jQuery.deparam(jQuery.param.querystring()).debug !== undefined; //debug mode
// default attributes values. If null, it will be loaded below.
this.set({
@ -101,8 +118,9 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}).then(function(company_partners){
self.get('company').contact_address = company_partners[0].contact_address;
return self.fetch('res.currency',['symbol','position'],[['id','=',self.get('company').currency_id[0]]]);
return self.fetch('res.currency',['symbol','position','rounding','accuracy'],[['id','=',self.get('company').currency_id[0]]]);
}).then(function(currencies){
console.log('Currency:',currencies[0]);
self.set('currency',currencies[0]);
return self.fetch('product.uom', null, null);
@ -117,7 +135,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
return self.fetch('product.packaging', null, null);
}).then(function(packagings){
self.set('product.packaging',packagings);
return self.fetch('res.users', ['name','ean13'], [['ean13', '!=', false]]);
}).then(function(users){
self.set('user_list',users);
@ -211,7 +229,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
// logs the usefull posmodel data to the console for debug purposes
log_loaded_data: function(){
console.log('PosModel data has been loaded:');
console.log('PosModel: categories:',this.get('categories'));
console.log('PosModel: units:',this.get('units'));
console.log('PosModel: bank_statements:',this.get('bank_statements'));
console.log('PosModel: journals:',this.get('journals'));
@ -339,19 +356,26 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
this.product = options.product;
this.price = options.product.get('price');
this.quantity = 1;
this.quantityStr = '1';
this.discount = 0;
this.discountStr = '0';
this.type = 'unit';
this.selected = false;
},
// sets a discount [0,100]%
set_discount: function(discount){
this.discount = Math.max(0,Math.min(100,discount));
var disc = Math.min(Math.max(parseFloat(discount) || 0, 0),100);
this.discount = disc;
this.discountStr = '' + disc;
this.trigger('change');
},
// returns the discount [0,100]%
get_discount: function(){
return this.discount;
},
get_discount_str: function(){
return this.discountStr;
},
get_product_type: function(){
return this.type;
},
@ -359,13 +383,18 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
// product's unity of measure properties. Quantities greater than zero will not get
// rounded to zero
set_quantity: function(quantity){
if(_.isNaN(quantity)){
if(quantity === 'remove'){
this.order.removeOrderline(this);
}else if(quantity !== undefined){
this.quantity = Math.max(0,quantity);
return;
}else{
var quant = Math.max(parseFloat(quantity) || 0, 0);
var unit = this.get_unit();
if(unit && this.quantity > 0 ){
this.quantity = Math.max(unit.rounding, Math.round(quantity / unit.rounding) * unit.rounding);
if(unit){
this.quantity = Math.max(unit.rounding, Math.round(quant / unit.rounding) * unit.rounding);
this.quantityStr = this.quantity.toFixed(Math.max(0,Math.ceil(Math.log(1.0 / unit.rounding) / Math.log(10))));
}else{
this.quantity = quant;
this.quantityStr = '' + this.quantity;
}
}
this.trigger('change');
@ -374,6 +403,17 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
get_quantity: function(){
return this.quantity;
},
get_quantity_str: function(){
return this.quantityStr;
},
get_quantity_str_with_unit: function(){
var unit = this.get_unit();
if(unit && unit.name !== 'Unit(s)'){
return this.quantityStr + ' ' + unit.name;
}else{
return this.quantityStr;
}
},
// return the unit of measure of the product
get_unit: function(){
var unit_id = (this.product.get('uos_id') || this.product.get('uom_id'));
@ -390,15 +430,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
get_product: function(){
return this.product;
},
// return the base price of this product (for this orderline)
get_price: function(){
return this.price;
},
// changes the base price of the product for this orderline
set_price: function(price){
this.price = price;
this.trigger('change');
},
// selects or deselects this orderline
set_selected: function(selected){
this.selected = selected;
@ -429,7 +460,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
export_as_JSON: function() {
return {
qty: this.get_quantity(),
price_unit: this.get_price(),
price_unit: this.get_unit_price(),
discount: this.get_discount(),
product_id: this.get_product().get('id'),
};
@ -439,9 +470,10 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
return {
quantity: this.get_quantity(),
unit_name: this.get_unit().name,
price: this.get_price(),
price: this.get_unit_price(),
discount: this.get_discount(),
product_name: this.get_product().get('name'),
price_display : this.get_display_price(),
price_with_tax : this.get_price_with_tax(),
price_without_tax: this.get_price_without_tax(),
tax: this.get_tax(),
@ -449,6 +481,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
product_description_sale: this.get_product().get('description_sale'),
};
},
// changes the base price of the product for this orderline
set_unit_price: function(price){
this.price = round(parseFloat(price) || 0, 2);
this.trigger('change');
},
get_unit_price: function(){
var rounding = this.pos.get('currency').rounding;
return round_pr(this.price,rounding);
},
get_display_price: function(){
var rounding = this.pos.get('currency').rounding;
return round_pr(round_pr(this.get_unit_price() * this.get_quantity(),rounding) * (1- this.get_discount()/100.0),rounding);
},
get_price_without_tax: function(){
return this.get_all_prices().priceWithoutTax;
},
@ -458,9 +503,10 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
get_tax: function(){
return this.get_all_prices().tax;
},
get_all_prices: function() {
get_all_prices: function(){
var self = this;
var base = this.get_quantity() * this.price * (1 - (this.get_discount() / 100));
var currency_rounding = this.pos.get('currency').rounding;
var base = round_pr(this.get_quantity() * this.get_unit_price() * (1.0 - (this.get_discount() / 100.0)), currency_rounding);
var totalTax = base;
var totalNoTax = base;
@ -474,12 +520,13 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
if (tax.price_include) {
var tmp;
if (tax.type === "percent") {
tmp = base - (base / (1 + tax.amount));
tmp = base - round_pr(base / (1 + tax.amount),currency_rounding);
} else if (tax.type === "fixed") {
tmp = tax.amount * self.get_quantity();
tmp = round_pr(tax.amount * self.get_quantity(),currency_rounding);
} else {
throw "This type of tax is not supported by the point of sale: " + tax.type;
}
tmp = round_pr(tmp,currency_rounding);
taxtotal += tmp;
totalNoTax -= tmp;
} else {
@ -491,6 +538,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
} else {
throw "This type of tax is not supported by the point of sale: " + tax.type;
}
tmp = round_pr(tmp,currency_rounding);
taxtotal += tmp;
totalTax += tmp;
}
@ -515,7 +563,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
},
//sets the amount of money on this payment line
set_amount: function(value){
this.amount = value;
this.amount = parseFloat(value) || 0;
this.trigger('change');
},
// returns the amount of money on this paymentline
@ -584,7 +632,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
line.set_quantity(options.quantity);
}
if(options.price !== undefined){
line.set_price(options.price);
line.set_unit_price(options.price);
}
var last_orderline = this.getLastOrderline();
@ -613,14 +661,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
getName: function() {
return this.get('name');
},
getTotal: function() {
getSubtotal : function(){
return (this.get('orderLines')).reduce((function(sum, orderLine){
return sum + orderLine.get_display_price();
}), 0);
},
getTotalTaxIncluded: function() {
return (this.get('orderLines')).reduce((function(sum, orderLine) {
return sum + orderLine.get_price_with_tax();
}), 0);
},
getDiscountTotal: function() {
return (this.get('orderLines')).reduce((function(sum, orderLine) {
return sum + (orderLine.get_price() * (orderLine.get_discount()/100) * orderLine.get_quantity());
return sum + (orderLine.get_unit_price() * (orderLine.get_discount()/100) * orderLine.get_quantity());
}), 0);
},
getTotalTaxExcluded: function() {
@ -639,10 +692,10 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}), 0);
},
getChange: function() {
return this.getPaidTotal() - this.getTotal();
return this.getPaidTotal() - this.getTotalTaxIncluded();
},
getDueLeft: function() {
return this.getTotal() - this.getPaidTotal();
return this.getTotalTaxIncluded() - this.getPaidTotal();
},
// sets the type of receipt 'receipt'(default) or 'invoice'
set_receipt_type: function(type){
@ -698,10 +751,12 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
return {
orderlines: orderlines,
paymentlines: paymentlines,
total_with_tax: this.getTotal(),
subtotal: this.getSubtotal(),
total_with_tax: this.getTotalTaxIncluded(),
total_without_tax: this.getTotalTaxExcluded(),
total_tax: this.getTax(),
total_paid: this.getPaidTotal(),
total_discount: this.getDiscountTotal(),
change: this.getChange(),
name : this.getName(),
client: client ? client.name : null ,
@ -743,7 +798,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
return {
name: this.getName(),
amount_paid: this.getPaidTotal(),
amount_total: this.getTotal(),
amount_total: this.getTotalTaxIncluded(),
amount_tax: this.getTax(),
amount_return: this.getChange(),
lines: orderLines,
@ -800,20 +855,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
buffer: (this.get('buffer')) + newChar
});
}
this.updateTarget();
this.trigger('set_value',this.get('buffer'));
},
deleteLastChar: function() {
var tempNewBuffer = this.get('buffer').slice(0, -1);
if(!tempNewBuffer){
this.set({ buffer: "0" });
this.killTarget();
}else{
if (isNaN(tempNewBuffer)) {
tempNewBuffer = "0";
if(this.get('buffer') === ""){
if(this.get('mode') === 'quantity'){
this.trigger('set_value','remove');
}else{
this.trigger('set_value',this.get('buffer'));
}
this.set({ buffer: tempNewBuffer });
this.updateTarget();
}else{
var newBuffer = this.get('buffer').slice(0,-1) || "";
this.set({ buffer: newBuffer });
this.trigger('set_value',this.get('buffer'));
}
},
switchSign: function() {
@ -822,7 +876,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
this.set({
buffer: oldBuffer[0] === '-' ? oldBuffer.substr(1) : "-" + oldBuffer
});
this.updateTarget();
this.trigger('set_value',this.get('buffer'));
},
changeMode: function(newMode) {
this.set({
@ -836,15 +890,8 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
mode: "quantity"
});
},
updateTarget: function() {
var bufferContent, params;
bufferContent = this.get('buffer');
if (bufferContent && !isNaN(bufferContent)) {
this.trigger('set_value', parseFloat(bufferContent));
}
},
killTarget: function(){
this.trigger('set_value',Number.NaN);
resetValue: function(){
this.set({buffer:'0'});
},
});
}

View File

@ -368,7 +368,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
module.ChooseReceiptPopupWidget = module.PopUpWidget.extend({
template:'ChooseReceiptPopupWidget',
show: function(){
console.log('show');
this._super();
this.renderElement();
var self = this;
@ -603,7 +602,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
// initiates the connection to the payment terminal and starts the update requests
this.start = function(){
var def = new $.Deferred();
console.log("START");
self.pos.proxy.payment_request(self.pos.get('selectedOrder').getDueLeft())
.done(function(ack){
if(ack === 'ok'){
@ -613,7 +611,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
}else{
console.error('unknown payment request return value:',ack);
}
console.log("START_END");
def.resolve();
});
return def;
@ -621,10 +618,8 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
// gets updated status from the payment terminal and performs the appropriate consequences
this.update = function(){
console.log("UPDATE");
var def = new $.Deferred();
if(self.canceled){
console.log("UPDATE_END");
return def.resolve();
}
self.pos.proxy.payment_status()
@ -656,7 +651,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
}else{
console.error('unknown status value:',status.status);
}
console.log("UPDATE_END");
def.resolve();
});
return def;
@ -664,14 +658,12 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
// cancels a payment.
this.cancel = function(){
console.log("CANCEL");
if(!self.paid && !self.canceled){
self.canceled = true;
self.pos.proxy.payment_cancel();
self.pos_widget.screen_selector.set_current_screen(self.previous_screen);
self.queue.clear();
}
console.log("CANCEL_END");
return (new $.Deferred()).resolve();
}
@ -865,6 +857,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.bindPaymentLineEvents();
this.bind_orderline_events();
this.paymentlinewidgets = [];
this.focusedLine = null;
},
show: function(){
this._super();
@ -894,6 +887,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
});
this.updatePaymentSummary();
this.line_refocus();
},
close: function(){
this._super();
@ -931,17 +925,30 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.bind_orderline_events();
this.renderElement();
},
line_refocus: function(lineWidget){
if(lineWidget){
if(this.focusedLine !== lineWidget){
this.focusedLine = lineWidget;
}
}
if(this.focusedLine){
this.focusedLine.focus();
}
},
addPaymentLine: function(newPaymentLine) {
var self = this;
var l = new module.PaymentlineWidget(null, {
payment_line: newPaymentLine
var l = new module.PaymentlineWidget(this, {
payment_line: newPaymentLine,
});
l.on('delete_payment_line', self, function(r) {
self.deleteLine(r);
});
l.appendTo(this.$('#paymentlines'));
this.paymentlinewidgets.push(l);
this.$('.paymentline-amount input:last').focus();
if(this.numpadState){
this.numpadState.resetValue();
}
this.line_refocus(l);
},
renderElement: function() {
this._super();
@ -958,25 +965,26 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
},
deleteLine: function(lineWidget) {
this.currentPaymentLines.remove([lineWidget.payment_line]);
lineWidget.destroy();
},
updatePaymentSummary: function() {
var currentOrder = this.pos.get('selectedOrder');
var paidTotal = currentOrder.getPaidTotal();
var dueTotal = currentOrder.getTotal();
var dueTotal = currentOrder.getTotalTaxIncluded();
var remaining = dueTotal > paidTotal ? dueTotal - paidTotal : 0;
var change = paidTotal > dueTotal ? paidTotal - dueTotal : 0;
this.$('#payment-due-total').html(dueTotal.toFixed(2));
this.$('#payment-paid-total').html(paidTotal.toFixed(2));
this.$('#payment-remaining').html(remaining.toFixed(2));
this.$('#payment-change').html(change.toFixed(2));
if((currentOrder.selected_orderline == undefined))
remaining = 1
this.$('#payment-due-total').html(this.format_currency(dueTotal));
this.$('#payment-paid-total').html(this.format_currency(paidTotal));
this.$('#payment-remaining').html(this.format_currency(remaining));
this.$('#payment-change').html(this.format_currency(change));
if(currentOrder.selected_orderline === undefined){
remaining = 1; // What is this ?
}
if(this.pos_widget.action_bar){
this.pos_widget.action_bar.set_button_disabled('validation', remaining > 0);
}
this.$('.paymentline-amount input:last').focus();
},
set_numpad_state: function(numpadState) {
if (this.numpadState) {
@ -998,5 +1006,4 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.currentPaymentLines.last().set_amount(val);
},
});
}

View File

@ -22,14 +22,20 @@ function openerp_pos_basewidget(instance, module){ //module is instance.point_of
if(this.pos && this.pos.get('currency')){
this.currency = this.pos.get('currency');
}else{
this.currency = {symbol: '$', position: 'after'};
this.currency = {symbol: '$', position: 'after', rounding: 0.01};
}
var decimals = Math.max(0,Math.ceil(Math.log(1.0 / this.currency.rounding) / Math.log(10)));
this.format_currency = function(amount){
if(typeof amount === 'number'){
amount = Math.round(amount*100)/100;
amount = amount.toFixed(decimals);
}
if(this.currency.position === 'after'){
return Math.round(amount*100)/100 + ' ' + this.currency.symbol;
return amount + ' ' + this.currency.symbol;
}else{
return this.currency.symbol + ' ' + Math.round(amount*100)/100;
return this.currency.symbol + ' ' + amount;
}
}

View File

@ -186,7 +186,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
}else if( mode === 'discount'){
order.getSelectedLine().set_discount(val);
}else if( mode === 'price'){
order.getSelectedLine().set_price(val);
order.getSelectedLine().set_unit_price(val);
}
} else {
this.pos.get('selectedOrder').destroy();
@ -269,8 +269,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
update_summary: function(){
var order = this.pos.get('selectedOrder');
var total = order ? order.getTotal() : 0;
this.$('.summary .value.total').html(this.format_currency(total));
var total = order ? order.getTotalTaxIncluded() : 0;
var taxes = order ? total - order.getTotalTaxExcluded() : 0;
this.$('.summary .total > .value').html(this.format_currency(total));
this.$('.summary .total .subentry .value').html(this.format_currency(taxes));
},
set_display_mode: function(mode){
if(this.display_mode !== mode){
@ -311,24 +313,34 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
changeAmount: function(event) {
var newAmount = event.currentTarget.value;
if (newAmount && !isNaN(newAmount)) {
this.amount = parseFloat(newAmount);
this.payment_line.set_amount(this.amount);
var amount = parseFloat(newAmount);
if(!isNaN(amount)){
this.amount = amount;
this.payment_line.set_amount(amount);
}
},
changedAmount: function() {
if (this.amount !== this.payment_line.get_amount())
if (this.amount !== this.payment_line.get_amount()){
this.renderElement();
}
},
renderElement: function() {
var self = this;
this.name = this.payment_line.get_cashregister().get('journal_id')[1];
this._super();
this.$('input').keyup(_.bind(this.changeAmount, this));
this.$('input').keyup(function(event){
self.changeAmount(event);
});
this.$('.delete-payment-line').click(function() {
self.trigger('delete_payment_line', self);
});
},
focus: function(){
var val = this.$('input')[0].value;
this.$('input')[0].focus();
this.$('input')[0].value = val;
this.$('input')[0].select();
},
});
module.OrderButtonWidget = module.PosBaseWidget.extend({
@ -606,20 +618,15 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
if(this.scrollbar){
this.scrollbar.destroy();
}
this.pos.get('products')
.chain()
.map(function(product) {
var product = new module.ProductWidget(self, {
model: product,
weight: self.weight,
click_product_action: self.click_product_action,
})
self.productwidgets.push(product);
return product;
})
.invoke('appendTo', this.$('.product-list'));
var products = this.pos.get('products').models || [];
for(var i = 0, len = products.length; i < len; i++){
var product = new module.ProductWidget(self, {
model: products[i],
click_product_action: this.click_product_action,
});
this.productwidgets.push(product);
product.appendTo(this.$('.product-list'));
}
this.scrollbar = new module.ScrollbarWidget(this,{
target_widget: this,
target_selector: '.product-list-scroller',

View File

@ -48,11 +48,17 @@
</t>
<t t-name="SynchNotificationWidget">
<div class="oe_pos_synch-notification">
<t t-if="widget.get_nbr_pending() > 0" t-esc="widget.get_nbr_pending()"/>
<div t-if="widget.get_nbr_pending() > 0" class="oe_status_red"></div>
<div t-if="widget.get_nbr_pending() === 0" class="oe_status_green"></div>
</div>
<t t-if="widget.get_nbr_pending() > 0">
<div class="oe_pos_synch-notification">
<t t-esc="widget.get_nbr_pending()"/>
<div class="oe_status_red"></div>
</div>
</t>
<t t-if="widget.get_nbr_pending() === 0">
<div class="oe_pos_synch-notification oe_inactive">
<div class="oe_status_green"></div>
</div>
</t>
</t>
<t t-name="HeaderButtonWidget">
@ -214,11 +220,7 @@
<span class="left-block">
Total:
</span>
<span class="right-block">
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
<span id="payment-due-total"></span>
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
</span>
<span class='right-block' id="payment-due-total"></span>
</div>
<table id="paymentlines">
</table>
@ -227,31 +229,19 @@
<span class='left-block'>
Paid:
</span>
<span class='right-block'>
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
<span id="payment-paid-total"></span>
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
</span>
<span class='right-block' id="payment-paid-total"></span>
</div>
<div class="infoline">
<span class='left-block'>
Remaining:
</span>
<span class='right-block'>
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
<span id="payment-remaining"></span>
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
</span>
<span class='right-block' id="payment-remaining"></span>
</div>
<div class="infoline" >
<span class='left-block'>
Change:
</span>
<span class='right-block'>
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
<span id="payment-change"></span>
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
</span>
<span class='right-block' id="payment-change"></span>
</div>
</div>
</div>
@ -431,9 +421,13 @@
</ul>
<div class="summary">
<span t-attf-class="line #{widget.pos.get('selectedOrder').get('orderLines').length === 0 ? 'empty' : ''}">
<span class="label total">Total:</span> <span class="value total">0.00 €</span>
</span>
<div t-attf-class="line #{widget.pos.get('selectedOrder').get('orderLines').length === 0 ? 'empty' : ''}">
<div class='entry total'>
<span class="label">Total: </span> <span class="value">0.00 €</span>
<div class='subentry'>Taxes: <span class="value">0.00€</span></div>
</div>
</div>
<div class='clear'></div>
</div>
</div>
</div>
@ -500,26 +494,26 @@
<t t-esc="widget.model.get_product().get('name')"/>
</span>
<span class="price">
<t t-esc="widget.format_currency(widget.model.get_price_with_tax())"/>
<t t-esc="widget.format_currency(widget.model.get_display_price())"/>
</span>
<ul class="info-list">
<t t-if="widget.model.get_quantity() !== 1.0">
<t t-if="widget.model.get_quantity_str() !== '1'">
<li class="info">
<em>
<t t-esc="widget.model.get_quantity()" />
<t t-esc="widget.model.get_quantity_str()" />
</em>
<t t-esc="widget.model.get_unit().name" />
at
<t t-esc="widget.format_currency(widget.model.get_price())" />
<t t-esc="widget.format_currency(widget.model.get_unit_price())" />
/
<t t-esc="widget.model.get_unit().name" />
</li>
</t>
<t t-if="widget.model.get_discount() > 0">
<t t-if="widget.model.get_discount_str() !== '0'">
<li class="info">
With a
<em>
<t t-esc="widget.model.get_discount()" />%
<t t-esc="widget.model.get_discount_str()" />%
</em>
discount
</li>
@ -571,33 +565,36 @@
Shop: <t t-esc="widget.shop_obj.name"/><br />
<br />
<table>
<tr t-foreach="widget.currentOrderLines.toArray()" t-as="order">
<tr t-foreach="widget.currentOrderLines.toArray()" t-as="orderline">
<td>
<t t-esc="order.get_product().get('name')"/>
<t t-if="order.get_discount() > 0">
<t t-esc="orderline.get_product().get('name')"/>
<t t-if="orderline.get_discount() > 0">
<div class="pos-disc-font">
With a <t t-esc="order.get_discount()"/>% discount
With a <t t-esc="orderline.get_discount()"/>% discount
</div>
</t>
</td>
<td class="pos-right-align">
<t t-esc="order.get_quantity().toFixed(0)"/>
<t t-esc="orderline.get_quantity_str_with_unit()"/>
</td>
<td class="pos-right-align">
<t t-esc="widget.format_currency(order.get_price() * (1 - order.get_discount()/100) * order.get_quantity().toFixed(2))"/>
<t t-esc="widget.format_currency(orderline.get_display_price())"/>
</td>
</tr>
</table>
<br />
<table>
<tr><td>Subtotal:</td><td class="pos-right-align">
<t t-esc="widget.format_currency(widget.currentOrder.getSubtotal())"/>
</td></tr>
<tr><td>Tax:</td><td class="pos-right-align">
<t t-esc="widget.format_currency(widget.currentOrder.getTax().toFixed(2))"/>
<t t-esc="widget.format_currency(widget.currentOrder.getTax())"/>
</td></tr>
<tr><td>Discount:</td><td class="pos-right-align">
<t t-esc="widget.format_currency(widget.currentOrder.getDiscountTotal().toFixed(2))"/>
<t t-esc="widget.format_currency(widget.currentOrder.getDiscountTotal())"/>
</td></tr>
<tr class="emph"><td>Total:</td><td class="pos-right-align">
<t t-esc="widget.format_currency(widget.currentOrder.getTotal().toFixed(2))"/>
<t t-esc="widget.format_currency(widget.currentOrder.getTotalTaxIncluded())"/>
</td></tr>
</table>
<br />
@ -607,14 +604,14 @@
<t t-esc="pline.get_cashregister().get('journal_id')[1]"/>
</td>
<td class="pos-right-align">
<t t-esc="widget.format_currency((pline.get_amount()).toFixed(2))"/>
<t t-esc="widget.format_currency(pline.get_amount())"/>
</td>
</tr>
</table>
<br />
<table>
<tr><td>Change:</td><td class="pos-right-align">
<t t-esc="widget.format_currency((widget.currentOrder.getPaidTotal() - widget.currentOrder.getTotal()).toFixed(2))"/>
<t t-esc="widget.format_currency(widget.currentOrder.getPaidTotal() - widget.currentOrder.getTotalTaxIncluded())"/>
</td></tr>
</table>
</div>