[WIP] point_of_sale: in progress of solving ]bugs in taxes and order editing

bzr revid: fva@openerp.com-20130122131801-46dyysig5e2owifa
This commit is contained in:
Frédéric van der Essen
2013-01-22 14:18:01 +01:00
parent db4f0a54de
commit 5883f32718
5 changed files with 160 additions and 59 deletions
+105 -31
View File
@@ -1,6 +1,11 @@
function openerp_pos_models(instance, module){ //module is instance.point_of_sale
var QWeb = instance.web.qweb;
function round(value,decimals){
var mult = Math.pow(10,decimals || 0);
return Math.round(value*mult)/mult;
}
// 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 +29,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({
@@ -338,20 +342,38 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
this.order = options.order;
this.product = options.product;
this.price = options.product.get('price');
this.priceStr = '' + this.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 = parseFloat(discount);
if(_.isNaN(disc)){
return;
}else if(disc < 0){
this.discount = 0;
this.discountStr = '0';
}else if(disc > 100){
this.discount = 100;
this.discountStr = '100';
}else{
this.discount = disc;
this.discountStr = discount;
}
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 +381,23 @@ 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)){
this.order.removeOrderline(this);
}else if(quantity !== undefined){
this.quantity = Math.max(0,quantity);
var quant = parseFloat(quantity);
if(_.isNaN(quant)){
if(quantity === 'remove'){
this.order.removeOrderline(this);
}
return;
}else{
if(quant < 0){
quant = 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.ceil(Math.log(1.0 / unit.rounding) / Math.log(10)));
}else{
this.quantity = quant;
this.quantityStr = '' + this.quantity;
}
}
this.trigger('change');
@@ -374,6 +406,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 +433,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 +463,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 +473,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 +484,21 @@ 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){
var pr = parseFloat(price);
if(_.isNaN(pr)){
return;
}
this.price = round(pr,2);
this.trigger('change');
},
get_unit_price: function(){
return this.price;
},
get_display_price: function(){
return round(round(this.price * this.get_quantity(),2) * (1- this.get_discount()/100.0),2);
},
get_price_without_tax: function(){
return this.get_all_prices().priceWithoutTax;
},
@@ -460,7 +510,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
},
get_all_prices: function() {
var self = this;
var base = this.get_quantity() * this.price * (1 - (this.get_discount() / 100));
var base = round(this.get_quantity() * this.price * (1 - (this.get_discount() / 100)),2); //FIXME en fonction de la currency
var totalTax = base;
var totalNoTax = base;
@@ -474,12 +524,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(base / (1 + tax.amount),2); //FIXME en fonction de la currency
} else if (tax.type === "fixed") {
tmp = tax.amount * self.get_quantity();
tmp = round(tax.amount * self.get_quantity(),2);
} else {
throw "This type of tax is not supported by the point of sale: " + tax.type;
}
tmp = round(tmp,2);
taxtotal += tmp;
totalNoTax -= tmp;
} else {
@@ -491,6 +542,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(tmp,2);
taxtotal += tmp;
totalTax += tmp;
}
@@ -515,8 +567,16 @@ 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.trigger('change');
if(typeof value === 'string'){
var val = parseFloat(value);
if(!isNaN(val)){
this.amount = val;
this.trigger('change');
}
}else{
this.amount = value;
this.trigger('change');
}
},
// returns the amount of money on this paymentline
get_amount: function(){
@@ -584,7 +644,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 +673,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() {
@@ -807,7 +872,11 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
if(!tempNewBuffer){
this.set({ buffer: "0" });
this.killTarget();
if(this.get('mode') === 'quantity'){
this.killTarget();
}else{
this.updateTarget();
}
}else{
if (isNaN(tempNewBuffer)) {
tempNewBuffer = "0";
@@ -836,15 +905,20 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
mode: "quantity"
});
},
resetValue: function(){
this.set({buffer:'0'});
},
updateTarget: function() {
var bufferContent, params;
bufferContent = this.get('buffer');
if (bufferContent && !isNaN(bufferContent)) {
this.trigger('set_value', parseFloat(bufferContent));
console.log('set_value ',bufferContent);
this.trigger('set_value',bufferContent);
}
},
killTarget: function(){
this.trigger('set_value',Number.NaN);
console.log('set_value ','remove');
this.trigger('set_value','remove');
},
});
}
@@ -942,6 +942,9 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
l.appendTo(this.$('#paymentlines'));
this.paymentlinewidgets.push(l);
this.$('.paymentline-amount input:last').focus();
if(this.numpadState){
this.numpadState.resetValue();
}
},
renderElement: function() {
this._super();
@@ -962,7 +965,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
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;
@@ -998,5 +1001,4 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.currentPaymentLines.last().set_amount(val);
},
});
}
@@ -26,10 +26,14 @@ function openerp_pos_basewidget(instance, module){ //module is instance.point_of
}
this.format_currency = function(amount){
if(typeof amount === 'number'){
amount = Math.round(amount*100)/100;
amount = amount.toFixed(2);
}
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;
}
}
+19 -6
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,7 +269,11 @@ 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;
var subtotal = order ? order.getSubtotal() : 0;
var total = order ? order.getTotalTaxIncluded() : 0;
var taxes = order ? total - order.getTotalTaxExcluded() : 0;
this.$('.summary .value.subtotal').html(this.format_currency(subtotal));
this.$('.summary .value.taxes').html(this.format_currency(taxes));
this.$('.summary .value.total').html(this.format_currency(total));
},
set_display_mode: function(mode){
@@ -311,14 +315,23 @@ 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);
console.log(event);
console.log('changeAmount:',newAmount);
if( typeof newAmmount === 'string'){
var amount = parseFloat(newAmount);
if(!isNaN(amount)){
this.amount = amount;
this.payment_line.set_amount(amount);
}
}else if(!isNaN(newAmount)){
this.amount = newAmount;
this.payment_line.set_amount(newAmount);
}
},
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;
+26 -18
View File
@@ -438,7 +438,15 @@
</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 class='entry subtotal'>
<span class="label subtotal">Subtotal:</span> <span class="value subtotal">0.00 €</span>
</span>
<span class='entry taxes'>
<span class="label taxes">Taxes:</span> <span class="value taxes">0.00€</span>
</span>
<span class='entry total'>
<span class="label total">Total:</span> <span class="value total">0.00 €</span>
</span>
</span>
</div>
</div>
@@ -506,26 +514,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>
@@ -577,33 +585,33 @@
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>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 />
@@ -613,14 +621,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>