[MERGE] Merged with addons/trunk.

bzr revid: tde@openerp.com-20120913161324-nuc2mo1kynis151u
This commit is contained in:
Thibault Delavallée
2012-09-13 18:13:24 +02:00
16 changed files with 518 additions and 167 deletions
+12 -2
View File
@@ -2338,6 +2338,16 @@ class account_model(osv.osv):
return move_ids
def onchange_journal_id(self, cr, uid, ids, journal_id, context=None):
company_id = False
if journal_id:
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
if journal.company_id.id:
company_id = journal.company_id.id
return {'value': {'company_id': company_id}}
account_model()
class account_model_line(osv.osv):
@@ -3013,9 +3023,9 @@ class wizard_multi_charts_accounts(osv.osv_memory):
'purchase_tax_rate': fields.float('Purchase Tax(%)'),
'complete_tax_set': fields.boolean('Complete Set of Taxes', help='This boolean helps you to choose if you want to propose to the user to encode the sales and purchase rates or use the usual m2o fields. This last choice assumes that the set of tax defined for the chosen template is complete'),
}
def onchange_company_id(self, cr, uid, ids, company_id, context=None):
currency_id = False
currency_id = False
if company_id:
currency_id = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.id
return {'value': {'currency_id': currency_id}}
+9 -5
View File
@@ -43,11 +43,15 @@ class bank(osv.osv):
"Return the name to use when creating a bank journal"
return (bank.bank_name or '') + ' ' + bank.acc_number
def _prepare_name_get(self, cr, uid, bank_type_obj, bank_obj, context=None):
"""Add ability to have %(currency_name)s in the format_layout of
res.partner.bank.type"""
bank_obj._data[bank_obj.id]['currency_name'] = bank_obj.currency_id and bank_obj.currency_id.name or ''
return super(bank, self)._prepare_name_get(cr, uid, bank_type_obj, bank_obj, context=context)
def _prepare_name_get(self, cr, uid, bank_dicts, context=None):
"""Add ability to have %(currency_name)s in the format_layout of res.partner.bank.type"""
currency_ids = list(set(data['currency_id'][0] for data in bank_dicts if data['currency_id']))
currencies = self.pool.get('res.currency').browse(cr, uid, currency_ids, context=context)
currency_name = dict((currency.id, currency.name) for currency in currencies)
for data in bank_dicts:
data['currency_name'] = data['currency_id'] and currency_name[data['currency_id'][0]] or ''
return super(bank, self)._prepare_name_get(cr, uid, bank_dicts, context=context)
def post_write(self, cr, uid, ids, context={}):
if isinstance(ids, (int, long)):
+6 -6
View File
@@ -112,7 +112,7 @@
<field name="fiscalyear_id" widget="selection"/>
<label for="date_start" string="Duration"/>
<div>
<field name="date_start" class="oe_inline" nolabel="1"/> -
<field name="date_start" class="oe_inline" nolabel="1"/> -
<field name="date_stop" nolabel="1" class="oe_inline"/>
</div>
</group>
@@ -181,7 +181,7 @@
<form string="Account" version="7.0">
<label for="code" class="oe_edit_only" string="Account Code and Name"/>
<h1>
<field name="code" class="oe_inline" placeholder="Account code" style="width: 6em"/> -
<field name="code" class="oe_inline" placeholder="Account code" style="width: 6em"/> -
<field name="name" class="oe_inline" placeholder="Account name"/>
</h1>
<group>
@@ -1082,7 +1082,7 @@
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<form string="Journal Item" version="7.0">
<sheet>
<sheet>
<group>
<group>
<field name="name"/>
@@ -1349,7 +1349,7 @@
<field name="date"/>
<field name="to_check"/>
<field name="amount" invisible="1"/>
</group>
</group>
</group>
<notebook>
<page string="Journal Items">
@@ -1651,8 +1651,8 @@
<form string="Journal Entry Model" version="7.0">
<group col="4">
<field name="name"/>
<field name="journal_id"/>
<field name="company_id" widget='selection' groups="base.group_multi_company"/>
<field name="journal_id" on_change="onchange_journal_id(journal_id)"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group>
<field name="lines_id" widget="one2many_list"/>
+10
View File
@@ -223,6 +223,16 @@ class account_config_settings(osv.osv_memory):
return {'value': {'date_stop': end_date.strftime('%Y-%m-%d')}}
return {}
def open_company_form(self, cr, uid, ids, context=None):
config = self.browse(cr, uid, ids[0], context)
return {
'type': 'ir.actions.act_window',
'name': 'Configure your Company',
'res_model': 'res.company',
'res_id': config.company_id.id,
'view_mode': 'form',
}
def set_default_taxes(self, cr, uid, ids, context=None):
""" set default sale and purchase taxes for products """
ir_values = self.pool.get('ir.values')
+2 -4
View File
@@ -224,10 +224,8 @@
<div>
<div>
<label for="company_footer"/>
<button name="%(action_bank_tree)d"
string="Configure your bank accounts"
icon="gtk-go-forward"
type="action"
<button name="open_company_form" type="object"
string="Configure your company bank accounts" icon="gtk-go-forward"
class="oe_inline oe_link"/>
<field name="company_footer"/>
</div>
+9 -4
View File
@@ -72,19 +72,19 @@ class PointOfSaleController(openerpweb.Controller):
return getattr(self, method)(request, **kwargs)
@openerpweb.jsonrequest
def scan_item_success(self, request):
def scan_item_success(self, request, ean):
"""
A product has been scanned with success
"""
print 'scan_item_success'
print 'scan_item_success: ' + str(ean)
return
@openerpweb.jsonrequest
def scan_item_error_unrecognized(self, request):
def scan_item_error_unrecognized(self, request, ean):
"""
A product has been scanned without success
"""
print 'scan_item_error_unrecognized'
print 'scan_item_error_unrecognized: ' + str(ean)
return
@openerpweb.jsonrequest
@@ -166,4 +166,9 @@ class PointOfSaleController(openerpweb.Controller):
print 'print_receipt' + str(receipt)
return
@openerpweb.jsonrequest
def print_pdf_invoice(self, request, pdfinvoice):
print 'print_pdf_invoice' + str(pdfinvoice)
return
+4 -3
View File
@@ -6,17 +6,17 @@
</record>
<record id="base.user_demo" model="res.users">
<field name="groups_id" eval="[(4,ref('group_pos_user'))]"/>
<field name="ean13">0410200000005</field>
<field name="ean13">0420100000005</field>
</record>
<record id="account.cash_journal" model="account.journal">
<field eval="True" name="journal_user"/>
</record>
<record id="base.user_root" model="res.users">
<field name="ean13">0410300000004</field>
<field name="ean13">0410100000006</field>
<field name="groups_id" eval="[(4,ref('group_pos_manager'))]"/>
</record>
<record id="base.user_demo" model="res.users">
<field name="ean13">0410400000003</field>
<field name="ean13">0420100000005</field>
<field name="groups_id" eval="[(4,ref('group_pos_manager'))]"/>
</record>
@@ -189,6 +189,7 @@
<record id="citron" model="product.product">
<field name="list_price">1.98</field>
<field name="name">Lemon</field>
<field name="ean13">2301000000006</field>
<field name="to_weight">True</field>
<field name="pos_categ_id" ref="autres_agrumes"/>
<field name="uom_id" ref="product.product_uom_kgm" />
@@ -71,7 +71,7 @@
clear: left;
}
.point-of-sale .keyboard .lastitem {
margin-right: 0;
margin-right: 0 !important;
}
/* ---- full sized keyboard ---- */
@@ -79,13 +79,13 @@
.point-of-sale .full_keyboard {
list-style: none;
font-size: 14px;
width: 680px;
width: 685px;
height: 100%;
margin-left: auto;
margin-right: auto;
margin-left: auto !important;
margin-right: auto !important;
}
.point-of-sale .full_keyboard li{
margin: 0 5px 5px 0;
margin: 0 5px 5px 0 !important;
width: 40px;
height: 40px;
line-height: 40px;
@@ -115,22 +115,22 @@
.point-of-sale .simple_keyboard {
list-style: none;
font-size: 16px;
width: 545px;
width: 555px;
height: 220px;
margin-left: auto;
margin-right: auto;
margin-left: auto !important;
margin-right: auto !important;
}
.point-of-sale .simple_keyboard li{
margin: 0 5px 5px 0;
margin: 0 5px 5px 0 !important;
width: 49px;
height: 49px;
line-height: 49px;
}
.point-of-sale .simple_keyboard .firstitem.row_asdf{
margin-left:25px;
margin-left:25px !important;
}
.point-of-sale .simple_keyboard .firstitem.row_zxcv{
margin-left:55px;
margin-left:55px !important;
}
.point-of-sale .simple_keyboard .delete{
width: 103px;
@@ -139,7 +139,7 @@
width: 103px;
}
.point-of-sale .simple_keyboard .space{
width:268px;
width:273px;
}
.point-of-sale .simple_keyboard .numlock{
width:103px;
+80 -5
View File
@@ -373,7 +373,7 @@
/* ********* The product list ********* */
.point-of-sale .product-list {
padding:10px;
padding:10px !important;
}
.point-of-sale .product-list-scroller{
@@ -470,7 +470,7 @@
}
.point-of-sale .category-list{
padding:10px;
padding:10px !important;
}
/* d) the category button */
@@ -479,7 +479,7 @@
vertical-align: top;
display: inline-block;
font-size: 11px;
margin: 5px;
margin: 5px !important;
width: 120px;
height:120px;
background:#fff;
@@ -566,7 +566,7 @@
display: inline-block;
line-height: 100px;
font-size: 11px;
margin: 5px;
margin: 5px !important;
width: 120px;
height:120px;
background:#fff;
@@ -809,6 +809,8 @@
}
.point-of-sale .scale-screen .product-picture img{
max-width: 178px;
max-height:178px;
vertical-align: middle;
cursor:pointer;
}
@@ -860,7 +862,7 @@
.point-of-sale .goodbye-message{
position: absolute;
left:50%;
top:30%;
top:40%;
width:500px;
height:400px;
margin-left: -250px;
@@ -1100,6 +1102,79 @@
.point-of-sale .pos-actionbar .button.rightalign{
float:right;
}
/* ********* The Debug Widget ********* */
.point-of-sale .debug-widget{
z-index:100000;
position: absolute;
right: 10px;
top: 10px;
width: 200px;
font-size: 10px;
background: rgba(0,0,0,0.82);
color: white;
text-shadow: none;
padding-bottom: 10px;
box-shadow: 0px 3px 20px rgba(0,0,0,0.3);
cursor:move;
}
.point-of-sale .debug-widget .toggle{
position: absolute;
font-size: 16px;
cursor:pointer;
top:0px;
right:0px;
padding:10px;
padding-right:15px;
}
.point-of-sale .debug-widget .content{
overflow: hidden;
}
.point-of-sale .debug-widget h1{
background:black;
padding-top: 10px;
padding-left: 10px;
margin-top:0;
margin-bottom:0;
}
.point-of-sale .debug-widget .category{
background: black;
padding-left: 10px;
margin: 0px;
font-weight: bold;
padding-top:3px;
padding-bottom:3px;
}
.point-of-sale .debug-widget .button{
padding: 5px;
padding-left: 15px;
display: block;
cursor:pointer;
}
.point-of-sale .debug-widget .button:hover{
background: rgba(96,21,177,0.45);
}
.point-of-sale .debug-widget input{
margin-left:10px;
margin-top:7px;
}
.point-of-sale .debug-widget .status{
padding: 5px;
padding-left: 15px;
display: block;
cursor:default;
}
.point-of-sale .debug-widget .status.on{
background-color: #6cd11d;
}
.point-of-sale .debug-widget .event{
padding: 5px;
padding-left: 15px;
display: block;
cursor:default;
background-color: #1E1E1E;
}
/* ********* The PopupWidgets ********* */
+25
View File
@@ -21,6 +21,8 @@ function openerp_pos_db(instance, module){
this.category_childs = {};
this.category_parent = {};
this.category_search_string = {};
this.packagings_by_id = {};
this.packagings_by_product_id = {};
},
/* returns the category object from its id. If you pass a list of id as parameters, you get
* a list of category objects.
@@ -116,6 +118,10 @@ function openerp_pos_db(instance, module){
if(product.ean13){
str += '|' + product.ean13;
}
var packagings = this.packagings_by_product_id[product.id] || [];
for(var i = 0; i < packagings.length; i++){
str += '|' + packagings[i].ean;
}
return str + '\n';
},
add_products: function(products){
@@ -158,6 +164,16 @@ function openerp_pos_db(instance, module){
this.save('products',stored_products);
this.save('categories',stored_categories);
},
add_packagings: function(packagings){
for(var i = 0, len = packagings.length; i < len; i++){
var pack = packagings[i];
this.packagings_by_id[pack.id] = pack;
if(!this.packagings_by_product_id[pack.product_id[0]]){
this.packagings_by_product_id[pack.product_id[0]] = [];
}
this.packagings_by_product_id[pack.product_id[0]].push(pack);
}
},
/* removes all the data from the database. TODO : being able to selectively remove data */
clear: function(stores){
for(var i = 0, len = arguments.length; i < len; i++){
@@ -184,6 +200,12 @@ function openerp_pos_db(instance, module){
return products[i];
}
}
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]];
}
}
return undefined;
},
get_product_by_category: function(category_id){
@@ -223,9 +245,12 @@ 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(){
+73 -58
View File
@@ -1,26 +1,6 @@
function openerp_pos_devices(instance,module){ //module is instance.point_of_sale
var debug_devices = new (instance.web.Class.extend({
active: false,
payment_status: 'waiting_for_payment',
weight: 0,
activate: function(){
this.active = true;
},
deactivate: function(){
this.active = false;
},
set_weight: function(weight){ this.activate(); this.weight = weight; },
accept_payment: function(){ this.activate(); this.payment_status = 'payment_accepted'; },
reject_payment: function(){ this.activate(); this.payment_status = 'payment_rejected'; },
delay_payment: function(){ this.activate(); this.payment_status = 'waiting_for_payment'; },
}))();
if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){
window.debug_devices = debug_devices;
}
// this object interfaces with the local proxy to communicate to the various hardware devices
// connected to the Point of Sale. As the communication only goes from the POS to the proxy,
// methods are used both to signal an event, and to fetch information.
@@ -38,32 +18,42 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
this.connection = new instance.web.JsonRPC();
this.connection.setup(url);
this.bypass_proxy = false;
this.notifications = {};
},
message : function(name,params,success_callback, error_callback){
success_callback = success_callback || function(){};
error_callback = error_callback || function(){};
if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){
console.log('PROXY:',name,params);
var callbacks = this.notifications[name] || [];
for(var i = 0; i < callbacks.length; i++){
callbacks[i](params);
}
if(!(debug_devices && debug_devices.active)){
this.connection.rpc('/pos/'+name, params || {}, success_callback, error_callback);
this.connection.rpc('/pos/'+name, params || {}, success_callback, error_callback);
},
// this allows the client to be notified when a proxy call is made. The notification
// callback will be executed with the same arguments as the proxy call
add_notification: function(name, callback){
if(!this.notifications[name]){
this.notifications[name] = [];
}
this.notifications[name].push(callback);
},
//a product has been scanned and recognized with success
// ean is a parsed ean object
scan_item_success: function(ean){
this.message('scan_item_success',ean);
this.message('scan_item_success',{ean: ean});
},
// a product has been scanned but not recognized
// ean is a parsed ean object
scan_item_error_unrecognized: function(ean){
this.message('scan_item_error_unrecognized',ean);
this.message('scan_item_error_unrecognized',{ean: ean});
},
//the client is asking for help
@@ -78,12 +68,12 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
//the client is starting to weight
weighting_start: function(){
this.weight = 0;
if(debug_devices){
debug_devices.weigth = 0;
if(!this.weighting){
this.weight = 0;
this.weighting = true;
this.bypass_proxy = false;
this.message('weighting_start');
}
this.weighting = true;
this.message('weighting_start');
},
//returns the weight on the scale.
@@ -91,22 +81,29 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
// and a weighting_end()
weighting_read_kg: function(){
var self = this;
if(debug_devices && debug_devices.active){
return debug_devices.weight;
if(this.bypass_proxy){
return this.weight;
}else{
this.message('weighting_read_kg',{},function(weight){
if(self.weighting){
if(self.weighting && !self.bypass_proxy){
self.weight = weight;
}
});
return self.weight;
return this.weight;
}
},
// sets a custom weight, ignoring the proxy returned value until the next weighting_end
debug_set_weight: function(kg){
this.bypass_proxy = true;
this.weight = kg;
},
// the client has finished weighting products
weighting_end: function(){
this.weight = 0;
this.weighting = false;
this.bypass_proxy = false;
this.message('weighting_end');
},
@@ -116,9 +113,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
payment_request: function(price, method, info){
this.paying = true;
this.payment_status = 'waiting_for_payment';
if(debug_devices){
debug_devices.payment_status = 'waiting_for_payment';
}
this.message('payment_request',{'price':price,'method':method,'info':info});
},
@@ -127,18 +121,30 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
// returns 'waiting_for_payment' | 'payment_accepted' | 'payment_rejected'
is_payment_accepted: function(){
var self = this;
if(debug_devices.active){
return debug_devices.payment_status;
if(this.bypass_proxy){
this.bypass_proxy = false;
return this.payment_status;
}else{
this.message('is_payment_accepted', {}, function(payment_status){
if(self.paying){
self.payment_status = payment_status;
}
});
return self.payment_status;
return this.payment_status;
}
},
// override what the proxy says and accept the payment
debug_accept_payment: function(){
this.bypass_proxy = true;
this.payment_status = 'payment_accepted';
},
// override what the proxy says and reject the payment
debug_reject_payment: function(){
this.bypass_proxy = true;
this.payment_status = 'payment_rejected';
},
// the client cancels his payment
payment_canceled: function(){
this.paying = false;
@@ -212,6 +218,11 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
print_receipt: function(receipt){
this.message('print_receipt',{receipt: receipt});
},
// asks the proxy to print an invoice in pdf form ( used to print invoices generated by the server )
print_pdf_invoice: function(pdfinvoice){
this.message('print_pdf_invoice',{pdfinvoice: pdfinvoice});
},
});
// this module interfaces with the barcode reader. It assumes the barcode reader
@@ -237,6 +248,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
this.cashier_prefix_set = attributes.cashier_prefix_set || {'041':''};
this.client_prefix_set = attributes.client_prefix_set || {'042':''};
},
save_callbacks: function(){
var callbacks = {};
for(name in this.action_callback){
@@ -244,6 +256,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
}
this.action_callback_stack.push(callbacks);
},
restore_callbacks: function(){
if(this.action_callback_stack.length){
var callbacks = this.action_callback_stack.pop();
@@ -337,7 +350,6 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
value: 0,
unit: 'none',
};
console.log('ean',ean);
function match_prefix(prefix_set, type){
for(prefix in prefix_set){
@@ -380,6 +392,23 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
return parse_result;
},
on_ean: function(ean){
var parse_result = this.parse_ean(ean);
if (parse_result.type === 'error') { //most likely a checksum error, raise warning
console.warn('WARNING: barcode checksum error:',parse_result);
}else if(parse_result.type in {'unit':'', 'weight':'', 'price':''}){ //ean is associated to a product
if(this.action_callback['product']){
this.action_callback['product'](parse_result);
}
//this.trigger("codebar",parse_result );
}else{
if(this.action_callback[parse_result.type]){
this.action_callback[parse_result.type](parse_result);
}
}
},
// starts catching keyboard events and tries to interpret codebar
// calling the callbacks when needed.
connect: function(){
@@ -410,21 +439,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
lastTimeStamp = new Date().getTime();
if (codeNumbers.length == 13) {
//We have found what seems to be a valid codebar
var parse_result = self.parse_ean(codeNumbers.join(''));
if (parse_result.type === 'error') { //most likely a checksum error, raise warning
console.warn('WARNING: barcode checksum error:',parse_result);
}else if(parse_result.type in {'unit':'', 'weight':'', 'price':''}){ //ean is associated to a product
if(self.action_callback['product']){
self.action_callback['product'](parse_result);
}
//this.trigger("codebar",parse_result );
}else{
if(self.action_callback[parse_result.type]){
self.action_callback[parse_result.type](parse_result);
}
}
self.on_ean(codeNumbers.join(''));
codeNumbers = [];
}
} else {
+45 -20
View File
@@ -1,9 +1,6 @@
function openerp_pos_models(instance, module){ //module is instance.point_of_sale
var QWeb = instance.web.qweb;
var fetch = function(model, fields, domain, ctx){
return new instance.web.Model(model).query(fields).filter(domain).context(ctx).all()
};
// The PosModel contains the Point Of Sale's representation of the backend.
// Since the PoS must work in standalone ( Without connection to the server )
@@ -27,6 +24,8 @@ 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
// default attributes values. If null, it will be loaded below.
this.set({
@@ -51,7 +50,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
'units': null,
'units_by_id': null,
'selectedOrder': undefined,
'selectedOrder': null,
});
this.get('orders').bind('remove', function(){ self.on_removed_order(); });
@@ -70,15 +69,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
});
},
// helper function to load data from the server
fetch: function(model, fields, domain, ctx){
return new instance.web.Model(model).query(fields).filter(domain).context(ctx).all()
},
// loads all the needed data on the sever. returns a deferred indicating when all the data has loaded.
load_server_data: function(){
var self = this;
var loaded = fetch('res.users',['name','company_id'],[['id','=',this.session.uid]])
var loaded = self.fetch('res.users',['name','company_id'],[['id','=',this.session.uid]])
.pipe(function(users){
self.set('user',users[0]);
return fetch('res.company',
return self.fetch('res.company',
[
'currency_id',
'email',
@@ -93,15 +96,15 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}).pipe(function(companies){
self.set('company',companies[0]);
return fetch('res.partner',['contact_address'],[['id','=',companies[0].partner_id[0]]]);
return self.fetch('res.partner',['contact_address'],[['id','=',companies[0].partner_id[0]]]);
}).pipe(function(company_partners){
self.get('company').contact_address = company_partners[0].contact_address;
return fetch('res.currency',['symbol','position'],[['id','=',self.get('company').currency_id[0]]]);
return self.fetch('res.currency',['symbol','position'],[['id','=',self.get('company').currency_id[0]]]);
}).pipe(function(currencies){
self.set('currency',currencies[0]);
return fetch('product.uom', null, null);
return self.fetch('product.uom', null, null);
}).pipe(function(units){
self.set('units',units);
var units_by_id = {};
@@ -110,19 +113,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}
self.set('units_by_id',units_by_id);
return fetch('product.packaging', null, null);
return self.fetch('product.packaging', null, null);
}).pipe(function(packagings){
self.set('product.packaging',packagings);
return fetch('res.users', ['name','ean13'], [['ean13', '!=', false]]);
return self.fetch('res.users', ['name','ean13'], [['ean13', '!=', false]]);
}).pipe(function(users){
self.set('user_list',users);
return fetch('account.tax', ['amount', 'price_include', 'type']);
return self.fetch('account.tax', ['amount', 'price_include', 'type']);
}).pipe(function(taxes){
self.set('taxes', taxes);
return fetch(
return self.fetch(
'pos.session',
['id', 'journal_ids','name','user_id','config_id','start_at','stop_at'],
[['state', '=', 'opened'], ['user_id', '=', self.session.uid]]
@@ -130,7 +133,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}).pipe(function(sessions){
self.set('pos_session', sessions[0]);
return fetch(
return self.fetch(
'pos.config',
['name','journal_ids','shop_id','journal_id',
'iface_self_checkout', 'iface_led', 'iface_cashdrawer',
@@ -147,15 +150,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
self.iface_self_checkout = !!pos_config.iface_self_checkout;
self.iface_cashdrawer = !!pos_config.iface_cashdrawer;
return fetch('sale.shop',[],[['id','=',pos_config.shop_id[0]]]);
return self.fetch('sale.shop',[],[['id','=',pos_config.shop_id[0]]]);
}).pipe(function(shops){
self.set('shop',shops[0]);
return fetch('pos.category', ['id','name','parent_id','child_id','image'])
return self.fetch('product.packaging',['ean','product_id']);
}).pipe(function(packagings){
self.db.add_packagings(packagings);
return self.fetch('pos.category', ['id','name','parent_id','child_id','image'])
}).pipe(function(categories){
self.db.add_categories(categories);
return fetch(
return self.fetch(
'product.product',
['name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13',
'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description'],
@@ -165,7 +172,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}).pipe(function(products){
self.db.add_products(products);
return fetch(
return self.fetch(
'account.bank.statement',
['account_id','currency','journal_id','state','name','user_id','pos_session_id'],
[['state','=','open'],['pos_session_id', '=', self.get('pos_session').id]]
@@ -173,7 +180,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}).pipe(function(bank_statements){
self.set('bank_statements', bank_statements);
return fetch('account.journal', undefined, [['user_id','=', self.get('pos_session').user_id[0]]]);
return self.fetch('account.journal', undefined, [['user_id','=', self.get('pos_session').user_id[0]]]);
}).pipe(function(journals){
self.set('journals',journals);
@@ -226,6 +233,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
// saves the order locally and try to send it to the backend. 'record' is a bizzarely defined JSON version of the Order
push_order: function(record) {
console.log('PUSHING NEW ORDER:',record);
this.db.add_order(record);
this.flush();
},
@@ -241,10 +249,15 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
// and remove the successfully sent ones from the db once
// it has been confirmed that they have been sent correctly.
flush: function() {
//TODO make the mutex work
console.log('FLUSH');
//this makes sure only one _int_flush is called at the same time
/*
return this.flush_mutex.exec(_.bind(function() {
return this._flush(0);
}, this));
*/
this._flush(0);
},
// attempts to send an order of index 'index' in the list of order to send. The index
// is used to skip orders that failed. do not call this method outside the mutex provided
@@ -253,6 +266,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
var self = this;
var orders = this.db.get_orders();
self.set('nbr_pending_operations',orders.length);
console.log('TRYING TO FLUSH ORDER:',index,'Of',orders.length);
var order = orders[index];
if(!order){
@@ -268,6 +282,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
})
.done(function(){
//remove from db if success
console.log('Order successfully sent');
self.db.remove_order(order.id);
self._flush(index);
});
@@ -301,6 +316,9 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
});
module.Product = Backbone.Model.extend({
get_image_url: function(){
return '/web/binary/image?session_id='+instance.session.session_id+'&model=product.product&field=image&id='+this.get('id');
},
});
module.ProductCollection = Backbone.Collection.extend({
@@ -330,7 +348,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
get_discount: function(){
return this.discount;
},
// FIXME
get_product_type: function(){
return this.type;
},
@@ -546,6 +563,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
this.pos = attributes.pos;
this.selected_orderline = undefined;
this.screen_data = {}; // see ScreenSelector
this.receipt_type = 'receipt'; // 'receipt' || 'invoice'
return this;
},
generateUniqueId: function() {
@@ -617,6 +635,13 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
getDueLeft: function() {
return this.getTotal() - this.getPaidTotal();
},
// sets the type of receipt 'receipt'(default) or 'invoice'
set_receipt_type: function(type){
this.receipt_type = type;
},
get_receipt_type: function(){
return this.receipt_type;
},
// the client related to the current order.
set_client: function(client){
this.set('client',client);
+68 -20
View File
@@ -65,6 +65,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
},
close_popup: function(){
if(this.current_popup){
this.current_popup.close();
this.current_popup.hide();
this.current_popup = null;
}
@@ -188,7 +189,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
return true;
}
}
this.pos.proxy.scan_item_unrecognized(ean);
this.pos.proxy.scan_item_error_unrecognized(ean);
return false;
},
@@ -206,7 +207,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
return true;
}
}
this.pos.proxy.scan_item_unrecognized(ean);
this.pos.proxy.scan_item_error_unrecognized(ean);
return false;
//TODO start the transaction
},
@@ -336,6 +337,11 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.$el.show();
}
},
/* called before hide, when a popup is closed */
close: function(){
},
/* hides the popup. keep in mind that this is called in the initialization pass of the
* pos instantiation, so you don't want to do anything fancy in here */
hide: function(){
if(this.$el){
this.$el.hide();
@@ -352,9 +358,40 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.$el.find('.button').off('click').click(function(){
self.pos_widget.screen_selector.close_popup();
self.pos.proxy.help_canceled();
});
},
close:function(){
this.pos.proxy.help_canceled();
},
});
module.ChooseReceiptPopupWidget = module.PopUpWidget.extend({
template:'ChooseReceiptPopupWidget',
show: function(){
console.log('show');
this._super();
this.renderElement();
var self = this;
var currentOrder = self.pos.get('selectedOrder');
this.$('.button.receipt').off('click').click(function(){
currentOrder.set_receipt_type('receipt');
self.pos_widget.screen_selector.set_current_screen('products');
});
this.$('.button.invoice').off('click').click(function(){
currentOrder.set_receipt_type('invoice');
self.pos_widget.screen_selector.set_current_screen('products');
});
},
get_client_name: function(){
var client = this.pos.get('selectedOrder').get_client();
if( client ){
return client.name;
}else{
return '';
}
},
});
module.ErrorPopupWidget = module.PopUpWidget.extend({
@@ -492,10 +529,6 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
var product = this.get_product();
return (product ? product.get('list_price') : 0) || 0;
},
get_product_image: function(){
var product = this.get_product();
return product ? product.get('image') : undefined;
},
get_product_weight: function(){
return this.weight || 0;
},
@@ -527,23 +560,21 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
//we get the first cashregister marked as self-checkout
var selfCheckoutRegisters = [];
for(var i = 0; i < this.pos.get('cashRegisters').models.length; i++){
var cashregister = this.pos.get('cashRegisters').models[i];
for(var i = 0; i < self.pos.get('cashRegisters').models.length; i++){
var cashregister = self.pos.get('cashRegisters').models[i];
if(cashregister.self_checkout_payment_method){
selfCheckoutRegisters.push(cashregister);
}
}
var cashregister = selfCheckoutRegisters[0] || this.pos.get('cashRegisters').models[0];
var cashregister = selfCheckoutRegisters[0] || self.pos.get('cashRegisters').models[0];
currentOrder.addPaymentLine(cashregister);
self.pos.push_order(currentOrder.exportAsJSON()).then(function() {
currentOrder.destroy();
self.pos.proxy.transaction_end();
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
});
self.pos.push_order(currentOrder.exportAsJSON())
currentOrder.destroy();
self.pos.proxy.transaction_end();
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
}else if(payment === 'payment_rejected'){
clearInterval(this.intervalID);
clearInterval(self.intervalID);
//TODO show a tryagain thingie ?
}
},500);
@@ -571,19 +602,35 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
show_numpad: false,
show_leftpane: false,
barcode_product_action: function(ean){
this.pos.proxy.transaction_start();
this._super(ean);
},
barcode_client_action: function(ean){
this.pos.proxy.transaction_start();
this._super(ean);
this.pos_widget.screen_selector.set_current_screen(this.next_screen);
$('.goodbye-message').hide();
this.pos_widget.screen_selector.show_popup('choose-receipt');
},
show: function(){
this._super();
var self = this;
this.add_action_button({
label: 'help',
icon: '/point_of_sale/static/src/img/icons/png48/help.png',
click: function(){
$('.goodbye-message').css({opacity:1}).hide();
self.help_button_action();
},
});
$('.goodbye-message').css({opacity:1}).show();
setTimeout(function(){
$('.goodbye-message').animate({opacity:0},500,'swing',function(){$('.goodbye-message').hide();});
},3000);
},5000);
},
});
@@ -743,6 +790,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
});
this.updatePaymentSummary();
this.$('.paymentline-amout input').last().focus();
},
close: function(){
this._super();
@@ -830,7 +878,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.numpadState.set({mode: 'payment'});
},
set_value: function(val) {
this.currentPaymentLines.last().set({amount: val});
this.currentPaymentLines.last().set_amount(val);
},
});
+102 -21
View File
@@ -284,12 +284,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.click_product_action = options.click_product_action;
},
// returns the url of the product thumbnail
get_image_url: function() {
return '/web/binary/image?session_id='+instance.session.session_id+'&model=product.product&field=image&id='+this.model.get('id');
},
renderElement: function() {
this._super();
this.$('img').replaceWith(this.pos_widget.image_cache.get_image(this.get_image_url()));
this.$('img').replaceWith(this.pos_widget.image_cache.get_image(this.model.get_image_url()));
var self = this;
$("a", this.$el).click(function(e){
if(self.click_product_action){
@@ -667,9 +664,95 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
show: function(){ this.$el.show(); },
hide: function(){ this.$el.hide(); },
});
// The debug widget lets the user control and monitor the hardware and software status
// without the use of the proxy
module.DebugWidget = module.PosBaseWidget.extend({
template: "DebugWidget",
eans:{
admin_badge: '0410100000006',
client_badge: '0420100000005',
invalid_ean: '1232456',
soda_33cl: '5449000000996',
oranges_kg: '2100002031410',
lemon_price: '2301000001560',
unknown_product: '9900000000004',
},
events:[
'scan_item_success',
'scan_item_error_unrecognized',
'payment_request',
'open_cashbox',
'print_receipt',
'print_pdf_invoice',
'weighting_read_kg',
'is_payment_accepted',
],
minimized: false,
start: function(){
var self = this;
this.$el.draggable();
this.$('.toggle').click(function(){
var content = self.$('.content');
var bg = self.$el;
if(!self.minimized){
content.animate({'height':'0'},200);
}else{
content.css({'height':'auto'});
}
self.minimized = !self.minimized;
});
this.$('.button.accept_payment').click(function(){
self.pos.proxy.debug_accept_payment();
});
this.$('.button.reject_payment').click(function(){
self.pos.proxy.debug_reject_payment();
});
this.$('.button.set_weight').click(function(){
var kg = Number(self.$('input.weight').val());
if(!Number.isNaN(kg)){
self.pos.proxy.debug_set_weight(kg);
}
});
this.$('.button.custom_ean').click(function(){
var ean = self.pos.barcode_reader.sanitize_ean(self.$('input.ean').val() || '0');
self.$('input.ean').val(ean);
self.pos.barcode_reader.on_ean(ean);
});
_.each(this.eans, function(ean, name){
self.$('.button.'+name).click(function(){
self.$('input.ean').val(ean);
self.pos.barcode_reader.on_ean(ean);
});
});
_.each(this.events, function(name){
self.pos.proxy.add_notification(name,function(){
self.$('.event.'+name).stop().clearQueue().css({'background-color':'#6CD11D'});
self.$('.event.'+name).animate({'background-color':'#1E1E1E'},2000);
});
});
self.pos.proxy.add_notification('help_needed',function(){
self.$('.status.help_needed').addClass('on');
});
self.pos.proxy.add_notification('help_canceled',function(){
self.$('.status.help_needed').removeClass('on');
});
self.pos.proxy.add_notification('transaction_start',function(){
self.$('.status.transaction').addClass('on');
});
self.pos.proxy.add_notification('transaction_end',function(){
self.$('.status.transaction').removeClass('on');
});
self.pos.proxy.add_notification('weighting_start',function(){
self.$('.status.weighting').addClass('on');
});
self.pos.proxy.add_notification('weighting_end',function(){
self.$('.status.weighting').removeClass('on');
});
},
});
// ---------- Main Point of Sale Widget ----------
@@ -698,6 +781,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
});
// The PosWidget is the main widget that contains all other widgets in the PointOfSale.
// It is mainly composed of :
// - a header, containing the list of orders
@@ -722,14 +806,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.leftpane_width = '440px';
this.cashier_controls_visible = true;
this.image_cache = new module.ImageCache(); // for faster products image display
/*
//Epileptic mode
setInterval(function(){
$('body').css({'-webkit-filter':'hue-rotate('+Math.random()*360+'deg)' });
},100);
*/
},
start: function() {
@@ -758,6 +834,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
self.screen_selector.set_default_screen();
window.screen_selector = self.screen_selector;
self.pos.barcode_reader.connect();
instance.webclient.set_content_full_screen(true);
@@ -771,11 +849,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
self.$('.loader').animate({opacity:0},1500,'swing',function(){self.$('.loader').hide();});
self.$('.loader img').hide();
if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){
window.pos = self.pos;
window.pos_widget = self.pos_widget;
}
},function(){ // error when loading models data from the backend
self.$('.loader img').hide();
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_session_opening']], ['res_id'])
@@ -831,6 +904,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.error_session_popup = new module.ErrorNoSessionPopupWidget(this, {});
this.error_session_popup.appendTo($('.point-of-sale'));
this.choose_receipt_popup = new module.ChooseReceiptPopupWidget(this, {});
this.choose_receipt_popup.appendTo($('.point-of-sale'));
// -------- Misc ---------
this.notification = new module.SynchNotificationWidget(this,{});
@@ -890,12 +966,17 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
'error': this.error_popup,
'error-product': this.error_product_popup,
'error-session': this.error_session_popup,
'choose-receipt': this.choose_receipt_popup,
},
default_client_screen: 'welcome',
default_cashier_screen: 'products',
default_mode: this.pos.iface_self_checkout ? 'client' : 'cashier',
});
if(this.pos.debug){
this.debug_widget = new module.DebugWidget(this);
this.debug_widget.appendTo(this.$('#content'));
}
},
changed_pending_operations: function () {
@@ -965,9 +1046,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
try_close: function() {
var self = this;
self.pos.flush().then(function() {
self.close();
});
//TODO : do the close after the flush...
self.pos.flush()
self.close();
},
close: function() {
var self = this;
+57 -7
View File
@@ -185,8 +185,8 @@
<span class="product-price">
<t t-esc="widget.format_currency(widget.get_product_price()) + '/Kg'" />
</span>
<t t-if="widget.get_product_image()">
<img t-att-src="'data:image/png;base64,'+ widget.get_product_image()" />
<t t-if="widget.get_product()">
<img t-att-src="widget.get_product().get_image_url()" />
</t>
</div>
</div>
@@ -313,18 +313,16 @@
</div>
</t>
<t t-name="ReceiptPopupWidget">
<t t-name="ChooseReceiptPopupWidget">
<div class="modal-dialog">
<div class="popup popup-help">
<p class="message">Welcome Mr. John Smith <br /> Choose your type of receipt:</p>
<p class="message">Welcome <t t-esc="widget.get_client_name()" /><br /> Choose your type of receipt:</p>
<div class = "button big-left receipt">
Ticket
</div>
<div class = "button big-right invoice">
Invoice
</div>
<div class="footer">
</div>
</div>
</div>
</t>
@@ -348,7 +346,8 @@
<t t-name="ErrorPopupWidget">
<div class="modal-dialog">
<div class="popup popup-help">
<p class="message"><t t-esc=" widget.message || 'Error.' " /></p>
<p class="message"><t t-esc=" widget.message || 'Error' " /></p>
<p class="comment"><t t-esc=" widget.comment || '' "/></p>
</div>
</div>
</t>
@@ -415,6 +414,57 @@
</div>
</t>
<t t-name="DebugWidget">
<div class="debug-widget">
<h1>Debug Window</h1>
<div class="toggle">▾</div>
<div class="content">
<p class="category">Payment Terminal</p>
<ul>
<li class="button accept_payment">Accept Payment</li>
<li class="button reject_payment">Reject Payment</li>
</ul>
<p class="category">Electronic Scale</p>
<ul>
<li><input type="text" class="weight"></input></li>
<li class="button set_weight">Set Weight</li>
</ul>
<p class="category">Barcode Scanner</p>
<ul>
<li><input type="text" class="ean"></input></li>
<li class="button custom_ean">Custom Ean13</li>
<li class="button admin_badge">Admin Badge</li>
<li class="button client_badge">Client Badge</li>
<li class="button soda_33cl">Soda 33cl</li>
<li class="button oranges_kg">3.141Kg Oranges</li>
<li class="button lemon_price">1.54€ Lemon</li>
<li class="button unknown_product">Unknown Product</li>
<li class="button invalid_ean">Invalid Ean</li>
</ul>
<p class="category">Hardware Status</p>
<ul>
<li class="status help_needed">Help needed</li>
<li class="status weighting">Weighting</li>
<li class="status transaction">In Transaction</li>
</ul>
<p class="category">Hardware Events</p>
<ul>
<li class="event scan_item_success">Scan Item Success</li>
<li class="event scan_item_error_unrecognized">Scan Item Unrecognized</li>
<li class="event payment_request">Payment Request</li>
<li class="event open_cashbox">Open Cashbox</li>
<li class="event print_receipt">Print Receipt</li>
<li class="event print_pdf_invoice">Print Invoice</li>
<li class="event weighting_read_kg">Read Weighting Scale</li>
<li class="event is_payment_accepted">Check Payment</li>
</ul>
</div>
</div>
</t>
<t t-name="OrderlineWidget">
<li class="orderline">
<span class="product-name">
@@ -117,6 +117,8 @@ openerp.web_linkedin = function(instance) {
"count": 25,
}).result(function(result) {
children_def.resolve(result);
}).error(function() {
children_def.reject();
});
defs.push(children_def.pipe(function(result) {
result = _.reject(result.people.values || [], function(el) {
@@ -130,6 +132,8 @@ openerp.web_linkedin = function(instance) {
var p_to_change = _.toArray(arguments);
to_change.child_ids = p_to_change;
});
}, function() {
return $.when();
}));
/* TODO
to_change.linkedinUrl = _.str.sprintf("http://www.linkedin.com/company/%d", entity.id);