2010-08-09 11:14:53 +00:00
# -*- coding: utf-8 -*-
2008-08-24 14:45:43 +00:00
##############################################################################
2010-10-08 06:13:09 +00:00
#
2009-01-30 10:37:24 +00:00
# OpenERP, Open Source Management Solution
2010-08-09 11:14:53 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2008-11-03 19:18:56 +00:00
#
# This program is free software: you can redistribute it and/or modify
2010-08-09 11:14:53 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2008-11-03 19:18:56 +00:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2010-08-09 11:14:53 +00:00
# GNU Affero General Public License for more details.
2008-11-03 19:18:56 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
2010-10-08 06:13:09 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2008-08-24 14:45:43 +00:00
#
##############################################################################
2012-07-30 13:33:43 +00:00
2012-01-05 13:13:19 +00:00
import logging
2012-12-06 14:56:32 +00:00
import time
2015-04-13 17:43:53 +00:00
from datetime import datetime
2010-10-26 05:37:43 +00:00
2013-02-01 06:24:21 +00:00
from openerp import tools
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
2015-02-19 07:50:03 +00:00
from openerp . tools import float_is_zero
2012-12-06 14:56:32 +00:00
from openerp . tools . translate import _
import openerp . addons . decimal_precision as dp
import openerp . addons . product . product
2008-08-24 14:45:43 +00:00
2012-01-05 13:13:19 +00:00
_logger = logging . getLogger ( __name__ )
2012-04-04 12:31:14 +00:00
class pos_config ( osv . osv ) :
_name = ' pos.config '
2012-05-09 08:19:42 +00:00
POS_CONFIG_STATE = [
( ' active ' , ' Active ' ) ,
( ' inactive ' , ' Inactive ' ) ,
( ' deprecated ' , ' Deprecated ' )
]
2012-04-04 12:31:14 +00:00
2013-03-18 08:45:47 +00:00
def _get_currency ( self , cr , uid , ids , fieldnames , args , context = None ) :
2013-12-30 07:24:52 +00:00
result = dict . fromkeys ( ids , False )
for pos_config in self . browse ( cr , uid , ids , context = context ) :
if pos_config . journal_id :
currency_id = pos_config . journal_id . currency . id or pos_config . journal_id . company_id . currency_id . id
else :
2014-01-02 11:30:09 +00:00
currency_id = self . pool [ ' res.users ' ] . browse ( cr , uid , uid , context = context ) . company_id . currency_id . id
2013-12-30 07:24:52 +00:00
result [ pos_config . id ] = currency_id
return result
2013-03-18 08:45:47 +00:00
2012-04-04 12:31:14 +00:00
_columns = {
2014-05-21 09:52:05 +00:00
' name ' : fields . char ( ' Point of Sale Name ' , select = 1 ,
2012-05-13 11:39:37 +00:00
required = True , help = " An internal identification of the point of sale " ) ,
' journal_ids ' : fields . many2many ( ' account.journal ' , ' pos_config_journal_rel ' ,
' pos_config_id ' , ' journal_id ' , ' Available Payment Methods ' ,
2013-04-05 13:44:38 +00:00
domain = " [( ' journal_user ' , ' = ' , True ), ( ' type ' , ' in ' , [ ' bank ' , ' cash ' ])] " , ) ,
2014-03-21 16:06:34 +00:00
' picking_type_id ' : fields . many2one ( ' stock.picking.type ' , ' Picking Type ' ) ,
2014-03-24 12:33:46 +00:00
' stock_location_id ' : fields . many2one ( ' stock.location ' , ' Stock Location ' , domain = [ ( ' usage ' , ' = ' , ' internal ' ) ] , required = True ) ,
2012-05-13 11:39:37 +00:00
' journal_id ' : fields . many2one ( ' account.journal ' , ' Sale Journal ' ,
2012-08-10 13:45:17 +00:00
domain = [ ( ' type ' , ' = ' , ' sale ' ) ] ,
2012-05-13 11:39:37 +00:00
help = " Accounting journal used to post sales entries. " ) ,
2013-03-18 08:45:47 +00:00
' currency_id ' : fields . function ( _get_currency , type = " many2one " , string = " Currency " , relation = " res.currency " ) ,
2014-09-08 10:33:37 +00:00
' iface_self_checkout ' : fields . boolean ( ' Self Checkout Mode ' , # FIXME : this field is obsolete
2014-07-09 11:39:38 +00:00
help = " Check this if this point of sale should open by default in a self checkout mode. If unchecked, Odoo uses the normal cashier mode by default. " ) ,
2014-02-18 08:34:12 +00:00
' iface_cashdrawer ' : fields . boolean ( ' Cashdrawer ' , help = " Automatically open the cashdrawer " ) ,
2014-01-02 14:15:19 +00:00
' iface_payment_terminal ' : fields . boolean ( ' Payment Terminal ' , help = " Enables Payment Terminal integration " ) ,
' iface_electronic_scale ' : fields . boolean ( ' Electronic Scale ' , help = " Enables Electronic Scale integration " ) ,
' iface_vkeyboard ' : fields . boolean ( ' Virtual KeyBoard ' , help = " Enables an integrated Virtual Keyboard " ) ,
' iface_print_via_proxy ' : fields . boolean ( ' Print via Proxy ' , help = " Bypass browser printing and prints via the hardware proxy " ) ,
2014-01-17 17:58:30 +00:00
' iface_scan_via_proxy ' : fields . boolean ( ' Scan via Proxy ' , help = " Enable barcode scanning with a remotely connected barcode scanner " ) ,
2013-04-11 12:22:50 +00:00
' iface_invoicing ' : fields . boolean ( ' Invoicing ' , help = ' Enables invoice generation from the Point of Sale ' ) ,
2013-11-06 16:17:23 +00:00
' iface_big_scrollbars ' : fields . boolean ( ' Large Scrollbars ' , help = ' For imprecise industrial touchscreens ' ) ,
2014-01-02 14:15:19 +00:00
' receipt_header ' : fields . text ( ' Receipt Header ' , help = " A short text that will be inserted as a header in the printed receipt " ) ,
' receipt_footer ' : fields . text ( ' Receipt Footer ' , help = " A short text that will be inserted as a footer in the printed receipt " ) ,
2014-01-17 17:58:30 +00:00
' proxy_ip ' : fields . char ( ' IP Address ' , help = ' The hostname or ip address of the hardware proxy, Will be autodetected if left empty ' , size = 45 ) ,
2012-04-04 12:31:14 +00:00
2014-07-06 14:44:26 +00:00
' state ' : fields . selection ( POS_CONFIG_STATE , ' Status ' , required = True , readonly = True , copy = False ) ,
2012-05-13 11:39:37 +00:00
' sequence_id ' : fields . many2one ( ' ir.sequence ' , ' Order IDs Sequence ' , readonly = True ,
2014-07-09 11:39:38 +00:00
help = " This sequence is automatically created by Odoo but you can change it " \
2014-07-06 14:44:26 +00:00
" to customize the reference numbers of your orders. " , copy = False ) ,
2012-05-13 11:04:17 +00:00
' session_ids ' : fields . one2many ( ' pos.session ' , ' config_id ' , ' Sessions ' ) ,
2012-08-17 15:15:29 +00:00
' group_by ' : fields . boolean ( ' Group Journal Items ' , help = " Check this if you want to group the Journal Items by Product while closing a Session " ) ,
2014-03-21 16:06:34 +00:00
' pricelist_id ' : fields . many2one ( ' product.pricelist ' , ' Pricelist ' , required = True ) ,
2014-06-13 14:19:05 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True ) ,
' barcode_product ' : fields . char ( ' Product Barcodes ' , size = 64 , help = ' The pattern that identifies product barcodes ' ) ,
' barcode_cashier ' : fields . char ( ' Cashier Barcodes ' , size = 64 , help = ' The pattern that identifies cashier login barcodes ' ) ,
' barcode_customer ' : fields . char ( ' Customer Barcodes ' , size = 64 , help = ' The pattern that identifies customer \' s client card barcodes ' ) ,
' barcode_price ' : fields . char ( ' Price Barcodes ' , size = 64 , help = ' The pattern that identifies a product with a barcode encoded price ' ) ,
' barcode_weight ' : fields . char ( ' Weight Barcodes ' , size = 64 , help = ' The pattern that identifies a product with a barcode encoded weight ' ) ,
' barcode_discount ' : fields . char ( ' Discount Barcodes ' , size = 64 , help = ' The pattern that identifies a product with a barcode encoded discount ' ) ,
2012-04-04 12:31:14 +00:00
}
2012-08-28 11:21:16 +00:00
def _check_cash_control ( self , cr , uid , ids , context = None ) :
return all (
( sum ( int ( journal . cash_control ) for journal in record . journal_ids ) < = 1 )
for record in self . browse ( cr , uid , ids , context = context )
)
2014-08-26 12:21:59 +00:00
def _check_company_location ( self , cr , uid , ids , context = None ) :
for config in self . browse ( cr , uid , ids , context = context ) :
if config . stock_location_id . company_id and config . stock_location_id . company_id . id != config . company_id . id :
return False
return True
def _check_company_journal ( self , cr , uid , ids , context = None ) :
for config in self . browse ( cr , uid , ids , context = context ) :
if config . journal_id and config . journal_id . company_id . id != config . company_id . id :
return False
return True
2014-10-17 12:22:13 +00:00
def _check_company_payment ( self , cr , uid , ids , context = None ) :
for config in self . browse ( cr , uid , ids , context = context ) :
journal_ids = [ j . id for j in config . journal_ids ]
if self . pool [ ' account.journal ' ] . search ( cr , uid , [
( ' id ' , ' in ' , journal_ids ) ,
( ' company_id ' , ' != ' , config . company_id . id )
] , count = True , context = context ) :
return False
return True
2012-08-28 11:21:16 +00:00
_constraints = [
( _check_cash_control , " You cannot have two cash controls in one Point Of Sale ! " , [ ' journal_ids ' ] ) ,
2014-08-26 12:21:59 +00:00
( _check_company_location , " The company of the stock location is different than the one of point of sale " , [ ' company_id ' , ' stock_location_id ' ] ) ,
( _check_company_journal , " The company of the sale journal is different than the one of point of sale " , [ ' company_id ' , ' journal_id ' ] ) ,
2014-10-17 12:22:13 +00:00
( _check_company_payment , " The company of a payment method is different than the one of point of sale " , [ ' company_id ' , ' journal_ids ' ] ) ,
2012-08-28 11:21:16 +00:00
]
2012-05-13 11:04:17 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
result = [ ]
states = {
' opening_control ' : _ ( ' Opening Control ' ) ,
' opened ' : _ ( ' In Progress ' ) ,
' closing_control ' : _ ( ' Closing Control ' ) ,
' closed ' : _ ( ' Closed & Posted ' ) ,
}
for record in self . browse ( cr , uid , ids , context = context ) :
if ( not record . session_ids ) or ( record . session_ids [ 0 ] . state == ' closed ' ) :
result . append ( ( record . id , record . name + ' ( ' + _ ( ' not used ' ) + ' ) ' ) )
continue
session = record . session_ids [ 0 ]
2012-08-17 15:15:29 +00:00
result . append ( ( record . id , record . name + ' ( ' + session . user_id . name + ' ) ' ) ) #, '+states[session.state]+')'))
2012-05-13 11:04:17 +00:00
return result
2012-05-12 22:37:43 +00:00
def _default_sale_journal ( self , cr , uid , context = None ) :
2013-08-14 14:02:40 +00:00
company_id = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context ) . company_id . id
res = self . pool . get ( ' account.journal ' ) . search ( cr , uid , [ ( ' type ' , ' = ' , ' sale ' ) , ( ' company_id ' , ' = ' , company_id ) ] , limit = 1 , context = context )
2012-05-12 22:37:43 +00:00
return res and res [ 0 ] or False
2012-04-26 12:30:17 +00:00
2013-02-06 12:38:51 +00:00
def _default_pricelist ( self , cr , uid , context = None ) :
2013-06-14 14:16:43 +00:00
res = self . pool . get ( ' product.pricelist ' ) . search ( cr , uid , [ ( ' type ' , ' = ' , ' sale ' ) ] , limit = 1 , context = context )
2013-02-06 12:38:51 +00:00
return res and res [ 0 ] or False
2012-04-26 12:30:17 +00:00
2014-03-24 12:33:46 +00:00
def _get_default_location ( self , cr , uid , context = None ) :
wh_obj = self . pool . get ( ' stock.warehouse ' )
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context )
res = wh_obj . search ( cr , uid , [ ( ' company_id ' , ' = ' , user . company_id . id ) ] , limit = 1 , context = context )
if res and res [ 0 ] :
return wh_obj . browse ( cr , uid , res [ 0 ] , context = context ) . lot_stock_id . id
return False
2014-03-24 12:07:47 +00:00
def _get_default_company ( self , cr , uid , context = None ) :
company_id = self . pool . get ( ' res.users ' ) . _get_company ( cr , uid , context = context )
return company_id
2012-05-12 22:37:43 +00:00
_defaults = {
' state ' : POS_CONFIG_STATE [ 0 ] [ 0 ] ,
2012-06-01 15:44:29 +00:00
' journal_id ' : _default_sale_journal ,
' group_by ' : True ,
2013-07-11 08:45:47 +00:00
' pricelist_id ' : _default_pricelist ,
2013-04-11 12:22:50 +00:00
' iface_invoicing ' : True ,
2014-03-24 12:33:46 +00:00
' stock_location_id ' : _get_default_location ,
2014-03-24 12:07:47 +00:00
' company_id ' : _get_default_company ,
2014-06-13 14:19:05 +00:00
' barcode_product ' : ' * ' ,
' barcode_cashier ' : ' 041* ' ,
' barcode_customer ' : ' 042* ' ,
' barcode_weight ' : ' 21xxxxxNNDDD ' ,
' barcode_discount ' : ' 22xxxxxxxxNN ' ,
' barcode_price ' : ' 23xxxxxNNNDD ' ,
2012-05-12 22:37:43 +00:00
}
2012-04-04 12:31:14 +00:00
2014-03-24 12:54:41 +00:00
def onchange_picking_type_id ( self , cr , uid , ids , picking_type_id , context = None ) :
p_type_obj = self . pool . get ( " stock.picking.type " )
p_type = p_type_obj . browse ( cr , uid , picking_type_id , context = context )
if p_type . default_location_src_id and p_type . default_location_src_id . usage == ' internal ' and p_type . default_location_dest_id and p_type . default_location_dest_id . usage == ' customer ' :
return { ' value ' : { ' stock_location_id ' : p_type . default_location_src_id . id } }
return False
2012-04-04 12:31:14 +00:00
def set_active ( self , cr , uid , ids , context = None ) :
return self . write ( cr , uid , ids , { ' state ' : ' active ' } , context = context )
def set_inactive ( self , cr , uid , ids , context = None ) :
return self . write ( cr , uid , ids , { ' state ' : ' inactive ' } , context = context )
def set_deprecate ( self , cr , uid , ids , context = None ) :
return self . write ( cr , uid , ids , { ' state ' : ' deprecated ' } , context = context )
2012-04-26 12:30:17 +00:00
def create ( self , cr , uid , values , context = None ) :
2014-08-26 12:31:42 +00:00
ir_sequence = self . pool . get ( ' ir.sequence ' )
# force sequence_id field to new pos.order sequence
values [ ' sequence_id ' ] = ir_sequence . create ( cr , uid , {
' name ' : ' POS Order %s ' % values [ ' name ' ] ,
' padding ' : 4 ,
' prefix ' : " %s / " % values [ ' name ' ] ,
' code ' : " pos.order " ,
' company_id ' : values . get ( ' company_id ' , False ) ,
} , context = context )
# TODO master: add field sequence_line_id on model
# this make sure we always have one available per company
ir_sequence . create ( cr , uid , {
' name ' : ' POS order line %s ' % values [ ' name ' ] ,
' padding ' : 4 ,
' prefix ' : " %s / " % values [ ' name ' ] ,
' code ' : " pos.order.line " ,
' company_id ' : values . get ( ' company_id ' , False ) ,
} , context = context )
2012-04-26 12:30:17 +00:00
return super ( pos_config , self ) . create ( cr , uid , values , context = context )
def unlink ( self , cr , uid , ids , context = None ) :
for obj in self . browse ( cr , uid , ids , context = context ) :
if obj . sequence_id :
obj . sequence_id . unlink ( )
return super ( pos_config , self ) . unlink ( cr , uid , ids , context = context )
2012-04-04 12:31:14 +00:00
class pos_session ( osv . osv ) :
_name = ' pos.session '
2012-05-13 11:04:17 +00:00
_order = ' id desc '
2012-04-04 12:31:14 +00:00
2012-05-09 13:30:18 +00:00
POS_SESSION_STATE = [
( ' opening_control ' , ' Opening Control ' ) , # Signal open
2012-05-13 11:04:17 +00:00
( ' opened ' , ' In Progress ' ) , # Signal closing
2012-05-09 13:30:18 +00:00
( ' closing_control ' , ' Closing Control ' ) , # Signal close
2012-05-10 07:48:04 +00:00
( ' closed ' , ' Closed & Posted ' ) ,
2012-05-09 13:30:18 +00:00
]
2012-04-10 11:24:29 +00:00
2012-08-28 11:21:16 +00:00
def _compute_cash_all ( self , cr , uid , ids , fieldnames , args , context = None ) :
result = dict ( )
2012-08-11 13:34:06 +00:00
2012-05-09 14:22:11 +00:00
for record in self . browse ( cr , uid , ids , context = context ) :
2012-08-28 11:21:16 +00:00
result [ record . id ] = {
' cash_journal_id ' : False ,
' cash_register_id ' : False ,
' cash_control ' : False ,
2012-05-30 14:35:43 +00:00
}
2012-08-28 11:21:16 +00:00
for st in record . statement_ids :
if st . journal_id . cash_control == True :
result [ record . id ] [ ' cash_control ' ] = True
result [ record . id ] [ ' cash_journal_id ' ] = st . journal_id . id
result [ record . id ] [ ' cash_register_id ' ] = st . id
2012-05-30 14:35:43 +00:00
return result
2012-04-04 12:31:14 +00:00
_columns = {
2012-05-12 22:37:43 +00:00
' config_id ' : fields . many2one ( ' pos.config ' , ' Point of Sale ' ,
2012-05-13 11:39:37 +00:00
help = " The physical point of sale you will use. " ,
2012-05-09 08:19:42 +00:00
required = True ,
select = 1 ,
domain = " [( ' state ' , ' = ' , ' active ' )] " ,
) ,
2014-05-21 09:52:05 +00:00
' name ' : fields . char ( ' Session ID ' , required = True , readonly = True ) ,
2012-05-12 22:37:43 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Responsible ' ,
2012-05-09 08:19:42 +00:00
required = True ,
select = 1 ,
2012-08-09 21:23:11 +00:00
readonly = True ,
states = { ' opening_control ' : [ ( ' readonly ' , False ) ] }
2012-05-09 08:19:42 +00:00
) ,
2013-03-18 09:07:47 +00:00
' currency_id ' : fields . related ( ' config_id ' , ' currency_id ' , type = " many2one " , relation = ' res.currency ' , string = " Currnecy " ) ,
2012-08-09 21:23:11 +00:00
' start_at ' : fields . datetime ( ' Opening Date ' , readonly = True ) ,
' stop_at ' : fields . datetime ( ' Closing Date ' , readonly = True ) ,
2012-04-10 11:24:29 +00:00
2012-10-12 11:42:58 +00:00
' state ' : fields . selection ( POS_SESSION_STATE , ' Status ' ,
2012-05-13 11:39:37 +00:00
required = True , readonly = True ,
2014-07-06 14:44:26 +00:00
select = 1 , copy = False ) ,
2014-06-13 14:19:05 +00:00
2014-08-20 13:07:56 +00:00
' sequence_number ' : fields . integer ( ' Order Sequence Number ' , help = ' A sequence number that is incremented with each order ' ) ,
' login_number ' : fields . integer ( ' Login Sequence Number ' , help = ' A sequence number that is incremented each time a user resumes the pos session ' ) ,
2012-04-26 12:30:17 +00:00
2012-08-28 11:21:16 +00:00
' cash_control ' : fields . function ( _compute_cash_all ,
multi = ' cash ' ,
type = ' boolean ' , string = ' Has Cash Control ' ) ,
' cash_journal_id ' : fields . function ( _compute_cash_all ,
multi = ' cash ' ,
type = ' many2one ' , relation = ' account.journal ' ,
string = ' Cash Journal ' , store = True ) ,
' cash_register_id ' : fields . function ( _compute_cash_all ,
multi = ' cash ' ,
type = ' many2one ' , relation = ' account.bank.statement ' ,
string = ' Cash Register ' , store = True ) ,
2012-04-26 12:30:17 +00:00
2012-05-10 07:48:04 +00:00
' opening_details_ids ' : fields . related ( ' cash_register_id ' , ' opening_details_ids ' ,
2012-05-13 11:39:37 +00:00
type = ' one2many ' , relation = ' account.cashbox.line ' ,
string = ' Opening Cash Control ' ) ,
2012-04-26 12:30:17 +00:00
' details_ids ' : fields . related ( ' cash_register_id ' , ' details_ids ' ,
2012-05-13 11:39:37 +00:00
type = ' one2many ' , relation = ' account.cashbox.line ' ,
string = ' Cash Control ' ) ,
2012-05-11 21:29:12 +00:00
' cash_register_balance_end_real ' : fields . related ( ' cash_register_id ' , ' balance_end_real ' ,
2012-05-13 11:39:37 +00:00
type = ' float ' ,
digits_compute = dp . get_precision ( ' Account ' ) ,
string = " Ending Balance " ,
2013-04-05 09:24:19 +00:00
help = " Total of closing cash control lines. " ,
2012-05-13 11:39:37 +00:00
readonly = True ) ,
2012-05-11 21:29:12 +00:00
' cash_register_balance_start ' : fields . related ( ' cash_register_id ' , ' balance_start ' ,
2012-05-13 11:39:37 +00:00
type = ' float ' ,
digits_compute = dp . get_precision ( ' Account ' ) ,
string = " Starting Balance " ,
2013-04-05 09:24:19 +00:00
help = " Total of opening cash control lines. " ,
2012-05-13 11:39:37 +00:00
readonly = True ) ,
2012-05-11 21:29:12 +00:00
' cash_register_total_entry_encoding ' : fields . related ( ' cash_register_id ' , ' total_entry_encoding ' ,
2012-05-13 11:39:37 +00:00
string = ' Total Cash Transaction ' ,
2013-04-05 09:24:19 +00:00
readonly = True ,
help = " Total of all paid sale orders " ) ,
2012-05-11 21:29:12 +00:00
' cash_register_balance_end ' : fields . related ( ' cash_register_id ' , ' balance_end ' ,
2012-05-13 11:39:37 +00:00
type = ' float ' ,
digits_compute = dp . get_precision ( ' Account ' ) ,
2013-04-12 09:38:07 +00:00
string = " Theoretical Closing Balance " ,
2013-04-05 09:24:19 +00:00
help = " Sum of opening balance and transactions. " ,
2012-05-13 11:39:37 +00:00
readonly = True ) ,
2012-05-11 21:29:12 +00:00
' cash_register_difference ' : fields . related ( ' cash_register_id ' , ' difference ' ,
2012-05-13 11:39:37 +00:00
type = ' float ' ,
string = ' Difference ' ,
2013-04-12 09:38:07 +00:00
help = " Difference between the theoretical closing balance and the real closing balance. " ,
2012-05-13 11:39:37 +00:00
readonly = True ) ,
2012-05-10 07:48:04 +00:00
2012-05-09 08:19:42 +00:00
' journal_ids ' : fields . related ( ' config_id ' , ' journal_ids ' ,
type = ' many2many ' ,
readonly = True ,
relation = ' account.journal ' ,
2012-05-13 11:39:37 +00:00
string = ' Available Payment Methods ' ) ,
2012-05-07 13:09:46 +00:00
' order_ids ' : fields . one2many ( ' pos.order ' , ' session_id ' , ' Orders ' ) ,
2012-05-09 14:22:11 +00:00
2012-05-10 07:48:04 +00:00
' statement_ids ' : fields . one2many ( ' account.bank.statement ' , ' pos_session_id ' , ' Bank Statement ' , readonly = True ) ,
2012-04-10 11:24:29 +00:00
}
_defaults = {
' name ' : ' / ' ,
' user_id ' : lambda obj , cr , uid , context : uid ,
2012-05-09 13:30:18 +00:00
' state ' : ' opening_control ' ,
2014-06-13 14:19:05 +00:00
' sequence_number ' : 1 ,
2014-08-20 13:07:56 +00:00
' login_number ' : 0 ,
2012-04-04 12:31:14 +00:00
}
2012-04-26 12:30:17 +00:00
_sql_constraints = [
( ' uniq_name ' , ' unique(name) ' , " The name of this POS Session must be unique ! " ) ,
]
2012-05-10 11:25:33 +00:00
def _check_unicity ( self , cr , uid , ids , context = None ) :
for session in self . browse ( cr , uid , ids , context = None ) :
# open if there is no session in 'opening_control', 'opened', 'closing_control' for one user
domain = [
2012-08-09 21:23:11 +00:00
( ' state ' , ' not in ' , ( ' closed ' , ' closing_control ' ) ) ,
2013-10-14 12:19:59 +00:00
( ' user_id ' , ' = ' , session . user_id . id )
2012-05-10 11:25:33 +00:00
]
count = self . search_count ( cr , uid , domain , context = context )
2012-05-12 22:37:43 +00:00
if count > 1 :
2012-05-10 11:25:33 +00:00
return False
return True
def _check_pos_config ( self , cr , uid , ids , context = None ) :
for session in self . browse ( cr , uid , ids , context = None ) :
domain = [
( ' state ' , ' != ' , ' closed ' ) ,
2012-05-12 22:37:43 +00:00
( ' config_id ' , ' = ' , session . config_id . id )
2012-05-10 11:25:33 +00:00
]
count = self . search_count ( cr , uid , domain , context = context )
2012-05-12 22:37:43 +00:00
if count > 1 :
2012-05-10 11:25:33 +00:00
return False
return True
2012-05-12 22:37:43 +00:00
_constraints = [
2012-07-25 10:49:32 +00:00
( _check_unicity , " You cannot create two active sessions with the same responsible! " , [ ' user_id ' , ' state ' ] ) ,
( _check_pos_config , " You cannot create two active sessions related to the same point of sale! " , [ ' config_id ' ] ) ,
2012-05-10 11:25:33 +00:00
]
2012-04-10 11:24:29 +00:00
def create ( self , cr , uid , values , context = None ) :
2014-07-06 14:44:26 +00:00
context = dict ( context or { } )
2012-11-03 17:12:25 +00:00
config_id = values . get ( ' config_id ' , False ) or context . get ( ' default_config_id ' , False )
if not config_id :
raise osv . except_osv ( _ ( ' Error! ' ) ,
_ ( " You should assign a Point of Sale to your session. " ) )
# journal_id is not required on the pos_config because it does not
# exists at the installation. If nothing is configured at the
# installation we do the minimal configuration. Impossible to do in
# the .xml files as the CoA is not yet installed.
jobj = self . pool . get ( ' pos.config ' )
pos_config = jobj . browse ( cr , uid , config_id , context = context )
2014-03-24 12:07:47 +00:00
context . update ( { ' company_id ' : pos_config . company_id . id } )
2012-11-03 17:12:25 +00:00
if not pos_config . journal_id :
jid = jobj . default_get ( cr , uid , [ ' journal_id ' ] , context = context ) [ ' journal_id ' ]
if jid :
2015-01-13 14:54:42 +00:00
jobj . write ( cr , openerp . SUPERUSER_ID , [ pos_config . id ] , { ' journal_id ' : jid } , context = context )
2012-11-03 17:12:25 +00:00
else :
raise osv . except_osv ( _ ( ' error! ' ) ,
_ ( " Unable to open the session. You have to assign a sale journal to your point of sale. " ) )
# define some cash journal if no payment method exists
if not pos_config . journal_ids :
journal_proxy = self . pool . get ( ' account.journal ' )
cashids = journal_proxy . search ( cr , uid , [ ( ' journal_user ' , ' = ' , True ) , ( ' type ' , ' = ' , ' cash ' ) ] , context = context )
if not cashids :
cashids = journal_proxy . search ( cr , uid , [ ( ' type ' , ' = ' , ' cash ' ) ] , context = context )
2012-08-10 13:45:17 +00:00
if not cashids :
2012-11-03 17:12:25 +00:00
cashids = journal_proxy . search ( cr , uid , [ ( ' journal_user ' , ' = ' , True ) ] , context = context )
2012-09-17 12:09:26 +00:00
2015-01-13 14:54:42 +00:00
journal_proxy . write ( cr , openerp . SUPERUSER_ID , cashids , { ' journal_user ' : True } )
jobj . write ( cr , openerp . SUPERUSER_ID , [ pos_config . id ] , { ' journal_ids ' : [ ( 6 , 0 , cashids ) ] } )
2012-08-10 13:45:17 +00:00
2012-11-03 17:12:25 +00:00
pos_config = jobj . browse ( cr , uid , config_id , context = context )
bank_statement_ids = [ ]
for journal in pos_config . journal_ids :
bank_values = {
' journal_id ' : journal . id ,
' user_id ' : uid ,
2014-03-24 12:07:47 +00:00
' company_id ' : pos_config . company_id . id
2012-11-03 17:12:25 +00:00
}
statement_id = self . pool . get ( ' account.bank.statement ' ) . create ( cr , uid , bank_values , context = context )
bank_statement_ids . append ( statement_id )
2012-05-09 14:22:11 +00:00
2012-11-03 17:12:25 +00:00
values . update ( {
2014-08-26 12:31:42 +00:00
' name ' : self . pool [ ' ir.sequence ' ] . get ( cr , uid , ' pos.session ' ) ,
2012-11-03 17:12:25 +00:00
' statement_ids ' : [ ( 6 , 0 , bank_statement_ids ) ] ,
' config_id ' : config_id
} )
2012-04-10 11:24:29 +00:00
return super ( pos_session , self ) . create ( cr , uid , values , context = context )
2012-05-08 15:28:05 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
for obj in self . browse ( cr , uid , ids , context = context ) :
2012-05-09 14:22:11 +00:00
for statement in obj . statement_ids :
statement . unlink ( context = context )
2014-07-18 12:30:13 +00:00
return super ( pos_session , self ) . unlink ( cr , uid , ids , context = context )
2012-05-08 15:28:05 +00:00
2012-10-01 09:52:54 +00:00
def open_cb ( self , cr , uid , ids , context = None ) :
"""
call the Point Of Sale interface and set the pos . session to ' opened ' ( in progress )
"""
if context is None :
context = dict ( )
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
this_record = self . browse ( cr , uid , ids [ 0 ] , context = context )
2013-02-13 14:00:52 +00:00
this_record . signal_workflow ( ' open ' )
2012-10-01 09:52:54 +00:00
context . update ( active_id = this_record . id )
return {
2013-12-07 17:00:14 +00:00
' type ' : ' ir.actions.act_url ' ,
' url ' : ' /pos/web/ ' ,
' target ' : ' self ' ,
2012-10-01 09:52:54 +00:00
}
2014-08-20 13:07:56 +00:00
def login ( self , cr , uid , ids , context = None ) :
this_record = self . browse ( cr , uid , ids [ 0 ] , context = context )
this_record . write ( {
' login_number ' : this_record . login_number + 1 ,
} )
2012-04-10 11:24:29 +00:00
def wkf_action_open ( self , cr , uid , ids , context = None ) :
2012-08-10 13:45:17 +00:00
# second browse because we need to refetch the data from the DB for cash_register_id
2012-04-30 15:05:57 +00:00
for record in self . browse ( cr , uid , ids , context = context ) :
values = { }
if not record . start_at :
values [ ' start_at ' ] = time . strftime ( ' % Y- % m- %d % H: % M: % S ' )
values [ ' state ' ] = ' opened '
2014-07-06 14:44:26 +00:00
record . write ( values )
2012-05-09 14:22:11 +00:00
for st in record . statement_ids :
2014-07-06 14:44:26 +00:00
st . button_open ( )
2012-08-10 13:45:17 +00:00
2012-08-09 21:23:11 +00:00
return self . open_frontend_cb ( cr , uid , ids , context = context )
2012-04-10 11:24:29 +00:00
2012-05-30 14:35:43 +00:00
def wkf_action_opening_control ( self , cr , uid , ids , context = None ) :
return self . write ( cr , uid , ids , { ' state ' : ' opening_control ' } , context = context )
2012-05-09 13:30:18 +00:00
def wkf_action_closing_control ( self , cr , uid , ids , context = None ) :
2012-05-13 12:08:12 +00:00
for session in self . browse ( cr , uid , ids , context = context ) :
for statement in session . statement_ids :
2012-11-03 17:12:25 +00:00
if ( statement != session . cash_register_id ) and ( statement . balance_end != statement . balance_end_real ) :
2012-08-28 11:21:16 +00:00
self . pool . get ( ' account.bank.statement ' ) . write ( cr , uid , [ statement . id ] , { ' balance_end_real ' : statement . balance_end } )
2012-05-12 22:37:43 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' closing_control ' , ' stop_at ' : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) } , context = context )
def wkf_action_close ( self , cr , uid , ids , context = None ) :
2012-05-07 13:09:46 +00:00
# Close CashBox
2012-05-09 10:39:59 +00:00
for record in self . browse ( cr , uid , ids , context = context ) :
2012-05-09 14:22:11 +00:00
for st in record . statement_ids :
2012-05-12 22:37:43 +00:00
if abs ( st . difference ) > st . journal_id . amount_authorized_diff :
2012-05-13 12:08:12 +00:00
# The pos manager can close statements with maximums.
if not self . pool . get ( ' ir.model.access ' ) . check_groups ( cr , uid , " point_of_sale.group_pos_manager " ) :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) ,
2013-04-29 05:38:51 +00:00
_ ( " Your ending balance is too different from the theoretical cash closing ( %.2f ), the maximum allowed is: %.2f . You can contact your manager to force it. " ) % ( st . difference , st . journal_id . amount_authorized_diff ) )
2013-04-05 13:44:38 +00:00
if ( st . journal_id . type not in [ ' bank ' , ' cash ' ] ) :
raise osv . except_osv ( _ ( ' Error! ' ) ,
_ ( " The type of the journal for your payment method should be bank or cash " ) )
2012-05-12 22:37:43 +00:00
getattr ( st , ' button_confirm_ %s ' % st . journal_id . type ) ( context = context )
2012-05-07 13:09:46 +00:00
self . _confirm_orders ( cr , uid , ids , context = context )
2012-08-09 21:23:11 +00:00
self . write ( cr , uid , ids , { ' state ' : ' closed ' } , context = context )
obj = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' point_of_sale ' , ' menu_point_root ' ) [ 1 ]
return {
' type ' : ' ir.actions.client ' ,
' name ' : ' Point of Sale Menu ' ,
' tag ' : ' reload ' ,
' params ' : { ' menu_id ' : obj } ,
}
2012-04-10 11:24:29 +00:00
2012-05-07 13:09:46 +00:00
def _confirm_orders ( self , cr , uid , ids , context = None ) :
[IMP] Workflow api changes: [account_payment, account_voucher, hr_holidays, hr_payroll, hr_timesheet_sheet, l10n_in_hr_payroll, point_of_sale, procurement, purchase, sale, sale_stock].
bzr revid: tta@openerp.com-20130204082943-vfevxeb7za6r4sy7
bzr revid: tta@openerp.com-20130204112949-07l1v3ru215iglut
2013-02-04 11:29:49 +00:00
pos_order_obj = self . pool . get ( ' pos.order ' )
2012-05-07 13:09:46 +00:00
for session in self . browse ( cr , uid , ids , context = context ) :
2015-04-13 17:43:53 +00:00
company_id = session . config_id . journal_id . company_id . id
local_context = dict ( context or { } , force_company = company_id )
2012-06-04 10:56:10 +00:00
order_ids = [ order . id for order in session . order_ids if order . state == ' paid ' ]
2012-06-01 09:53:56 +00:00
2015-04-13 17:43:53 +00:00
move_id = pos_order_obj . _create_account_move ( cr , uid , session . start_at , session . name , session . config_id . journal_id . id , company_id , context = context )
2012-06-04 10:56:10 +00:00
2014-02-06 16:45:22 +00:00
pos_order_obj . _create_account_move_line ( cr , uid , order_ids , session , move_id , context = local_context )
2012-06-01 09:53:56 +00:00
2012-05-07 13:09:46 +00:00
for order in session . order_ids :
2014-07-18 13:43:00 +00:00
if order . state == ' done ' :
continue
2012-09-05 15:05:38 +00:00
if order . state not in ( ' paid ' , ' invoiced ' ) :
2012-05-07 13:09:46 +00:00
raise osv . except_osv (
2012-08-07 11:31:37 +00:00
_ ( ' Error! ' ) ,
2012-07-25 10:49:32 +00:00
_ ( " You cannot confirm all orders of this session, because they have not the ' paid ' status " ) )
2012-05-07 13:09:46 +00:00
else :
2014-07-07 09:50:30 +00:00
pos_order_obj . signal_workflow ( cr , uid , [ order . id ] , ' done ' )
2012-05-07 13:09:46 +00:00
return True
2012-05-25 13:07:59 +00:00
def open_frontend_cb ( self , cr , uid , ids , context = None ) :
if not context :
context = { }
if not ids :
return { }
2013-08-28 07:30:30 +00:00
for session in self . browse ( cr , uid , ids , context = context ) :
if session . user_id . id != uid :
raise osv . except_osv (
_ ( ' Error! ' ) ,
_ ( " You cannot use the session of another users. This session is owned by %s . Please first close this one to use this point of sale. " % session . user_id . name ) )
2012-09-27 12:20:22 +00:00
context . update ( { ' active_id ' : ids [ 0 ] } )
2012-05-25 13:07:59 +00:00
return {
2013-12-07 17:00:14 +00:00
' type ' : ' ir.actions.act_url ' ,
' target ' : ' self ' ,
' url ' : ' /pos/web/ ' ,
2012-05-25 13:07:59 +00:00
}
2008-08-24 14:45:43 +00:00
class pos_order ( osv . osv ) :
_name = " pos.order "
_description = " Point of Sale "
2011-09-25 14:09:30 +00:00
_order = " id desc "
2012-03-30 08:27:51 +00:00
2014-06-23 21:06:55 +00:00
def _order_fields ( self , cr , uid , ui_order , context = None ) :
2014-06-13 14:19:05 +00:00
return {
' name ' : ui_order [ ' name ' ] ,
' user_id ' : ui_order [ ' user_id ' ] or False ,
' session_id ' : ui_order [ ' pos_session_id ' ] ,
' lines ' : ui_order [ ' lines ' ] ,
' pos_reference ' : ui_order [ ' name ' ] ,
' partner_id ' : ui_order [ ' partner_id ' ] or False ,
}
2014-06-23 21:06:55 +00:00
def _payment_fields ( self , cr , uid , ui_paymentline , context = None ) :
2014-06-13 14:19:05 +00:00
return {
' amount ' : ui_paymentline [ ' amount ' ] or 0.0 ,
' payment_date ' : ui_paymentline [ ' name ' ] ,
' statement_id ' : ui_paymentline [ ' statement_id ' ] ,
' payment_name ' : ui_paymentline . get ( ' note ' , False ) ,
' journal ' : ui_paymentline [ ' journal_id ' ] ,
}
2015-01-19 13:48:42 +00:00
def _process_order ( self , cr , uid , order , context = None ) :
order_id = self . create ( cr , uid , self . _order_fields ( cr , uid , order , context = context ) , context )
for payments in order [ ' statement_ids ' ] :
self . add_payment ( cr , uid , order_id , self . _payment_fields ( cr , uid , payments [ 2 ] , context = context ) , context = context )
session = self . pool . get ( ' pos.session ' ) . browse ( cr , uid , order [ ' pos_session_id ' ] , context = context )
if session . sequence_number < = order [ ' sequence_number ' ] :
session . write ( { ' sequence_number ' : order [ ' sequence_number ' ] + 1 } )
session . refresh ( )
2015-02-19 07:50:03 +00:00
if not float_is_zero ( order [ ' amount_return ' ] , self . pool . get ( ' decimal.precision ' ) . precision_get ( cr , uid , ' Account ' ) ) :
2015-01-19 13:48:42 +00:00
cash_journal = session . cash_journal_id
if not cash_journal :
cash_journal_ids = filter ( lambda st : st . journal_id . type == ' cash ' , session . statement_ids )
if not len ( cash_journal_ids ) :
raise osv . except_osv ( _ ( ' error! ' ) ,
_ ( " No cash statement found for this session. Unable to record returned cash. " ) )
cash_journal = cash_journal_ids [ 0 ] . journal_id
self . add_payment ( cr , uid , order_id , {
' amount ' : - order [ ' amount_return ' ] ,
' payment_date ' : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
' payment_name ' : _ ( ' return ' ) ,
' journal ' : cash_journal . id ,
} , context = context )
return order_id
2012-01-05 13:13:19 +00:00
def create_from_ui ( self , cr , uid , orders , context = None ) :
2014-02-13 15:24:49 +00:00
# Keep only new orders
submitted_references = [ o [ ' data ' ] [ ' name ' ] for o in orders ]
2014-03-26 11:29:22 +00:00
existing_order_ids = self . search ( cr , uid , [ ( ' pos_reference ' , ' in ' , submitted_references ) ] , context = context )
existing_orders = self . read ( cr , uid , existing_order_ids , [ ' pos_reference ' ] , context = context )
2014-02-13 15:24:49 +00:00
existing_references = set ( [ o [ ' pos_reference ' ] for o in existing_orders ] )
orders_to_save = [ o for o in orders if o [ ' data ' ] [ ' name ' ] not in existing_references ]
2012-06-04 11:15:50 +00:00
order_ids = [ ]
2014-07-22 12:33:32 +00:00
2014-02-13 15:24:49 +00:00
for tmp_order in orders_to_save :
2013-04-11 12:07:19 +00:00
to_invoice = tmp_order [ ' to_invoice ' ]
2012-06-04 11:15:50 +00:00
order = tmp_order [ ' data ' ]
2015-01-19 13:48:42 +00:00
order_id = self . _process_order ( cr , uid , order , context = context )
2012-06-04 11:15:50 +00:00
order_ids . append ( order_id )
2014-02-24 15:08:30 +00:00
try :
2014-07-07 09:50:30 +00:00
self . signal_workflow ( cr , uid , [ order_id ] , ' paid ' )
2014-02-24 15:08:30 +00:00
except Exception as e :
2014-05-19 13:36:48 +00:00
_logger . error ( ' Could not fully process the POS Order: %s ' , tools . ustr ( e ) )
2013-04-11 12:07:19 +00:00
if to_invoice :
self . action_invoice ( cr , uid , [ order_id ] , context )
order_obj = self . browse ( cr , uid , order_id , context )
2014-07-07 09:50:30 +00:00
self . pool [ ' account.invoice ' ] . signal_workflow ( cr , uid , [ order_obj . invoice_id . id ] , ' invoice_open ' )
2013-07-11 08:45:47 +00:00
2012-06-04 11:15:50 +00:00
return order_ids
2010-04-08 09:20:32 +00:00
2013-03-25 13:44:10 +00:00
def write ( self , cr , uid , ids , vals , context = None ) :
res = super ( pos_order , self ) . write ( cr , uid , ids , vals , context = context )
2013-04-04 15:14:28 +00:00
#If you change the partner of the PoS order, change also the partner of the associated bank statement lines
2013-03-28 11:28:29 +00:00
partner_obj = self . pool . get ( ' res.partner ' )
2013-03-25 13:44:10 +00:00
bsl_obj = self . pool . get ( " account.bank.statement.line " )
if ' partner_id ' in vals :
for posorder in self . browse ( cr , uid , ids , context = context ) :
2013-04-04 15:14:28 +00:00
if posorder . invoice_id :
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( " You cannot change the partner of a POS order for which an invoice has already been issued. " ) )
2013-03-28 11:28:29 +00:00
if vals [ ' partner_id ' ] :
p_id = partner_obj . browse ( cr , uid , vals [ ' partner_id ' ] , context = context )
part_id = partner_obj . _find_accounting_partner ( p_id ) . id
else :
part_id = False
2013-04-04 15:14:28 +00:00
bsl_ids = [ x . id for x in posorder . statement_ids ]
2013-03-25 13:44:10 +00:00
bsl_obj . write ( cr , uid , bsl_ids , { ' partner_id ' : part_id } , context = context )
return res
2010-06-11 13:03:03 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2008-12-20 09:43:37 +00:00
for rec in self . browse ( cr , uid , ids , context = context ) :
2011-09-25 14:09:30 +00:00
if rec . state not in ( ' draft ' , ' cancel ' ) :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' Unable to Delete! ' ) , _ ( ' In order to delete a sale, it must be new or cancelled. ' ) )
2008-12-20 09:43:37 +00:00
return super ( pos_order , self ) . unlink ( cr , uid , ids , context = context )
2011-09-25 14:09:30 +00:00
def onchange_partner_id ( self , cr , uid , ids , part = False , context = None ) :
2008-12-20 09:43:37 +00:00
if not part :
2010-10-27 04:29:13 +00:00
return { ' value ' : { } }
2010-10-26 05:37:43 +00:00
pricelist = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , part , context = context ) . property_product_pricelist . id
return { ' value ' : { ' pricelist_id ' : pricelist } }
2008-08-24 14:45:43 +00:00
2010-04-26 10:30:38 +00:00
def _amount_all ( self , cr , uid , ids , name , args , context = None ) :
2010-07-12 13:40:45 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
2010-10-26 05:37:43 +00:00
res = { }
for order in self . browse ( cr , uid , ids , context = context ) :
2010-04-26 10:30:38 +00:00
res [ order . id ] = {
' amount_paid ' : 0.0 ,
' amount_return ' : 0.0 ,
' amount_tax ' : 0.0 ,
2010-07-12 13:40:45 +00:00
}
2011-09-25 14:09:30 +00:00
val1 = val2 = 0.0
2010-07-12 13:40:45 +00:00
cur = order . pricelist_id . currency_id
2010-04-26 10:30:38 +00:00
for payment in order . statement_ids :
2010-10-05 06:30:26 +00:00
res [ order . id ] [ ' amount_paid ' ] + = payment . amount
res [ order . id ] [ ' amount_return ' ] + = ( payment . amount < 0 and payment . amount or 0 )
2008-08-24 14:45:43 +00:00
for line in order . lines :
2010-12-15 13:29:59 +00:00
val1 + = line . price_subtotal_incl
2011-09-25 14:09:30 +00:00
val2 + = line . price_subtotal
res [ order . id ] [ ' amount_tax ' ] = cur_obj . round ( cr , uid , cur , val1 - val2 )
res [ order . id ] [ ' amount_total ' ] = cur_obj . round ( cr , uid , cur , val1 )
2008-08-24 14:45:43 +00:00
return res
2010-07-12 13:40:45 +00:00
2008-08-24 14:45:43 +00:00
_columns = {
2014-07-06 14:44:26 +00:00
' name ' : fields . char ( ' Order Ref ' , required = True , readonly = True , copy = False ) ,
2010-01-18 08:38:26 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True , readonly = True ) ,
2012-05-12 22:37:43 +00:00
' date_order ' : fields . datetime ( ' Order Date ' , readonly = True , select = True ) ,
2012-07-25 10:49:32 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Salesman ' , help = " Person who uses the the cash register. It can be a reliever, a student or an interim employee. " ) ,
2013-12-24 15:11:12 +00:00
' amount_tax ' : fields . function ( _amount_all , string = ' Taxes ' , digits_compute = dp . get_precision ( ' Account ' ) , multi = ' all ' ) ,
2014-11-11 17:00:24 +00:00
' amount_total ' : fields . function ( _amount_all , string = ' Total ' , digits_compute = dp . get_precision ( ' Account ' ) , multi = ' all ' ) ,
2013-12-24 15:11:12 +00:00
' amount_paid ' : fields . function ( _amount_all , string = ' Paid ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True , digits_compute = dp . get_precision ( ' Account ' ) , multi = ' all ' ) ,
' amount_return ' : fields . function ( _amount_all , ' Returned ' , digits_compute = dp . get_precision ( ' Account ' ) , multi = ' all ' ) ,
2014-07-06 14:44:26 +00:00
' lines ' : fields . one2many ( ' pos.order.line ' , ' order_id ' , ' Order Lines ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True , copy = True ) ,
2010-10-26 05:37:43 +00:00
' statement_ids ' : fields . one2many ( ' account.bank.statement.line ' , ' pos_statement_id ' , ' Payments ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
2010-01-18 08:38:26 +00:00
' pricelist_id ' : fields . many2one ( ' product.pricelist ' , ' Pricelist ' , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
2010-10-26 05:37:43 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Customer ' , change_default = True , select = 1 , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' paid ' : [ ( ' readonly ' , False ) ] } ) ,
2014-06-13 14:19:05 +00:00
' sequence_number ' : fields . integer ( ' Sequence Number ' , help = ' A session-unique sequence number for the order ' ) ,
2011-09-25 14:09:30 +00:00
2012-04-30 15:05:57 +00:00
' session_id ' : fields . many2one ( ' pos.session ' , ' Session ' ,
2012-05-04 12:51:58 +00:00
#required=True,
2012-04-30 15:05:57 +00:00
select = 1 ,
domain = " [( ' state ' , ' = ' , ' opened ' )] " ,
states = { ' draft ' : [ ( ' readonly ' , False ) ] } ,
readonly = True ) ,
2012-04-10 11:24:29 +00:00
2011-09-25 14:09:30 +00:00
' state ' : fields . selection ( [ ( ' draft ' , ' New ' ) ,
2011-12-08 12:01:11 +00:00
( ' cancel ' , ' Cancelled ' ) ,
( ' paid ' , ' Paid ' ) ,
2011-09-25 14:09:30 +00:00
( ' done ' , ' Posted ' ) ,
2011-12-08 12:01:11 +00:00
( ' invoiced ' , ' Invoiced ' ) ] ,
2014-07-06 14:44:26 +00:00
' Status ' , readonly = True , copy = False ) ,
2011-09-25 14:09:30 +00:00
2014-07-06 14:44:26 +00:00
' invoice_id ' : fields . many2one ( ' account.invoice ' , ' Invoice ' , copy = False ) ,
' account_move ' : fields . many2one ( ' account.move ' , ' Journal Entry ' , readonly = True , copy = False ) ,
' picking_id ' : fields . many2one ( ' stock.picking ' , ' Picking ' , readonly = True , copy = False ) ,
2014-03-24 12:07:47 +00:00
' picking_type_id ' : fields . related ( ' session_id ' , ' config_id ' , ' picking_type_id ' , string = " Picking Type " , type = ' many2one ' , relation = ' stock.picking.type ' ) ,
2014-03-24 15:22:11 +00:00
' location_id ' : fields . related ( ' session_id ' , ' config_id ' , ' stock_location_id ' , string = " Location " , type = ' many2one ' , store = True , relation = ' stock.location ' ) ,
2010-01-18 08:38:26 +00:00
' note ' : fields . text ( ' Internal Notes ' ) ,
2014-07-06 14:44:26 +00:00
' nb_print ' : fields . integer ( ' Number of Print ' , readonly = True , copy = False ) ,
' pos_reference ' : fields . char ( ' Receipt Ref ' , readonly = True , copy = False ) ,
2012-05-13 10:16:41 +00:00
' sale_journal ' : fields . related ( ' session_id ' , ' config_id ' , ' journal_id ' , relation = ' account.journal ' , type = ' many2one ' , string = ' Sale Journal ' , store = True , readonly = True ) ,
2010-01-18 08:38:26 +00:00
}
2012-05-12 22:37:43 +00:00
def _default_session ( self , cr , uid , context = None ) :
so = self . pool . get ( ' pos.session ' )
session_ids = so . search ( cr , uid , [ ( ' state ' , ' = ' , ' opened ' ) , ( ' user_id ' , ' = ' , uid ) ] , context = context )
return session_ids and session_ids [ 0 ] or False
2011-09-25 14:09:30 +00:00
def _default_pricelist ( self , cr , uid , context = None ) :
2012-11-06 06:13:02 +00:00
session_ids = self . _default_session ( cr , uid , context )
if session_ids :
session_record = self . pool . get ( ' pos.session ' ) . browse ( cr , uid , session_ids , context = context )
2013-02-06 12:38:51 +00:00
return session_record . config_id . pricelist_id and session_record . config_id . pricelist_id . id or False
2011-01-17 08:28:47 +00:00
return False
2008-08-24 14:45:43 +00:00
2013-09-03 09:03:34 +00:00
def _get_out_picking_type ( self , cr , uid , context = None ) :
2014-05-08 14:39:40 +00:00
return self . pool . get ( ' ir.model.data ' ) . xmlid_to_res_id (
cr , uid , ' point_of_sale.picking_type_posout ' , context = context )
2013-09-03 09:03:34 +00:00
2008-08-24 14:45:43 +00:00
_defaults = {
' user_id ' : lambda self , cr , uid , context : uid ,
2010-10-26 05:37:43 +00:00
' state ' : ' draft ' ,
2012-04-30 15:05:57 +00:00
' name ' : ' / ' ,
2010-11-04 12:27:41 +00:00
' date_order ' : lambda * a : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
2010-10-26 05:37:43 +00:00
' nb_print ' : 0 ,
2014-06-13 14:19:05 +00:00
' sequence_number ' : 1 ,
2012-05-12 22:37:43 +00:00
' session_id ' : _default_session ,
2010-01-18 08:38:26 +00:00
' company_id ' : lambda self , cr , uid , c : self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , c ) . company_id . id ,
2011-09-25 14:09:30 +00:00
' pricelist_id ' : _default_pricelist ,
2008-08-24 14:45:43 +00:00
}
2012-04-30 15:05:57 +00:00
def create ( self , cr , uid , values , context = None ) :
2014-08-26 12:31:42 +00:00
if values . get ( ' session_id ' ) :
# set name based on the sequence specified on the config
session = self . pool [ ' pos.session ' ] . browse ( cr , uid , values [ ' session_id ' ] , context = context )
values [ ' name ' ] = session . config_id . sequence_id . _next ( )
else :
# fallback on any pos.order sequence
values [ ' name ' ] = self . pool . get ( ' ir.sequence ' ) . get_id ( cr , uid , ' pos.order ' , ' code ' , context = context )
2012-04-30 15:05:57 +00:00
return super ( pos_order , self ) . create ( cr , uid , values , context = context )
2008-08-24 14:45:43 +00:00
def test_paid ( self , cr , uid , ids , context = None ) :
2011-09-25 14:09:30 +00:00
""" A Point of Sale is paid when the sum
2010-04-08 09:20:32 +00:00
@return : True
2010-07-12 13:40:45 +00:00
"""
2010-10-26 05:37:43 +00:00
for order in self . browse ( cr , uid , ids , context = context ) :
2008-08-24 14:45:43 +00:00
if order . lines and not order . amount_total :
return True
2010-01-18 08:38:26 +00:00
if ( not order . lines ) or ( not order . statement_ids ) or \
2011-09-25 14:09:30 +00:00
( abs ( order . amount_total - order . amount_paid ) > 0.00001 ) :
2008-08-24 14:45:43 +00:00
return False
return True
2010-06-11 13:03:03 +00:00
def create_picking ( self , cr , uid , ids , context = None ) :
2008-08-24 14:45:43 +00:00
""" Create a picking for each order and validate it. """
2013-12-02 09:38:00 +00:00
picking_obj = self . pool . get ( ' stock.picking ' )
2011-04-26 07:39:18 +00:00
partner_obj = self . pool . get ( ' res.partner ' )
2011-09-25 14:09:30 +00:00
move_obj = self . pool . get ( ' stock.move ' )
for order in self . browse ( cr , uid , ids , context = context ) :
2011-04-26 07:39:18 +00:00
addr = order . partner_id and partner_obj . address_get ( cr , uid , [ order . partner_id . id ] , [ ' delivery ' ] ) or { }
2013-09-03 09:03:34 +00:00
picking_type = order . picking_type_id
2014-03-24 12:07:47 +00:00
picking_id = False
if picking_type :
picking_id = picking_obj . create ( cr , uid , {
' origin ' : order . name ,
' partner_id ' : addr . get ( ' delivery ' , False ) ,
2015-02-11 09:19:40 +00:00
' date_done ' : order . date_order ,
2014-03-24 12:07:47 +00:00
' picking_type_id ' : picking_type . id ,
' company_id ' : order . company_id . id ,
' move_type ' : ' direct ' ,
' note ' : order . note or " " ,
' invoice_state ' : ' none ' ,
} , context = context )
self . write ( cr , uid , [ order . id ] , { ' picking_id ' : picking_id } , context = context )
location_id = order . location_id . id
2013-12-10 18:17:33 +00:00
if order . partner_id :
destination_id = order . partner_id . property_stock_customer . id
2014-03-24 12:07:47 +00:00
elif picking_type :
if not picking_type . default_location_dest_id :
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' Missing source or destination location for picking type %s . Please configure those fields and try again. ' % ( picking_type . name , ) ) )
2013-12-30 10:28:02 +00:00
destination_id = picking_type . default_location_dest_id . id
2014-03-24 12:07:47 +00:00
else :
destination_id = partner_obj . default_get ( cr , uid , [ ' property_stock_customer ' ] , context = context ) [ ' property_stock_customer ' ]
2011-09-25 14:09:30 +00:00
2014-03-24 12:07:47 +00:00
move_list = [ ]
2011-09-25 14:09:30 +00:00
for line in order . lines :
if line . product_id and line . product_id . type == ' service ' :
continue
2014-03-24 12:07:47 +00:00
move_list . append ( move_obj . create ( cr , uid , {
2011-09-25 14:09:30 +00:00
' name ' : line . name ,
' product_uom ' : line . product_id . uom_id . id ,
' product_uos ' : line . product_id . uom_id . id ,
' picking_id ' : picking_id ,
2014-03-24 12:07:47 +00:00
' picking_type_id ' : picking_type . id ,
2011-09-25 14:09:30 +00:00
' product_id ' : line . product_id . id ,
' product_uos_qty ' : abs ( line . qty ) ,
2013-08-06 13:09:39 +00:00
' product_uom_qty ' : abs ( line . qty ) ,
2008-08-24 14:45:43 +00:00
' state ' : ' draft ' ,
2013-12-10 18:17:33 +00:00
' location_id ' : location_id if line . qty > = 0 else destination_id ,
' location_dest_id ' : destination_id if line . qty > = 0 else location_id ,
2014-03-24 12:07:47 +00:00
} , context = context ) )
if picking_id :
picking_obj . action_confirm ( cr , uid , [ picking_id ] , context = context )
picking_obj . force_assign ( cr , uid , [ picking_id ] , context = context )
picking_obj . action_done ( cr , uid , [ picking_id ] , context = context )
elif move_list :
move_obj . action_confirm ( cr , uid , move_list , context = context )
move_obj . force_assign ( cr , uid , move_list , context = context )
move_obj . action_done ( cr , uid , move_list , context = context )
2008-08-24 14:45:43 +00:00
return True
2010-01-18 08:38:26 +00:00
def cancel_order ( self , cr , uid , ids , context = None ) :
2010-07-12 13:40:45 +00:00
""" Changes order state to cancel
2010-04-08 09:20:32 +00:00
@return : True
2010-07-12 13:40:45 +00:00
"""
2011-09-25 14:09:30 +00:00
stock_picking_obj = self . pool . get ( ' stock.picking ' )
for order in self . browse ( cr , uid , ids , context = context ) :
2013-09-27 13:22:11 +00:00
stock_picking_obj . action_cancel ( cr , uid , [ order . picking_id . id ] )
2011-09-25 14:09:30 +00:00
if stock_picking_obj . browse ( cr , uid , order . picking_id . id , context = context ) . state < > ' cancel ' :
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' Unable to cancel the picking. ' ) )
2010-10-26 05:37:43 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancel ' } , context = context )
2008-08-24 14:45:43 +00:00
return True
2008-12-20 18:29:38 +00:00
def add_payment ( self , cr , uid , order_id , data , context = None ) :
2008-08-24 14:45:43 +00:00
""" Create a new payment for the order """
2014-07-06 14:44:26 +00:00
context = dict ( context or { } )
2010-10-26 05:37:43 +00:00
statement_line_obj = self . pool . get ( ' account.bank.statement.line ' )
property_obj = self . pool . get ( ' ir.property ' )
order = self . browse ( cr , uid , order_id , context = context )
2008-12-20 18:29:38 +00:00
args = {
' amount ' : data [ ' amount ' ] ,
2012-11-03 15:25:04 +00:00
' date ' : data . get ( ' payment_date ' , time . strftime ( ' % Y- % m- %d ' ) ) ,
' name ' : order . name + ' : ' + ( data . get ( ' payment_name ' , ' ' ) or ' ' ) ,
2014-08-22 13:29:23 +00:00
' partner_id ' : order . partner_id and self . pool . get ( " res.partner " ) . _find_accounting_partner ( order . partner_id ) . id or False ,
2010-08-13 12:20:05 +00:00
}
2014-12-16 09:16:30 +00:00
journal_id = data . get ( ' journal ' , False )
statement_id = data . get ( ' statement_id ' , False )
assert journal_id or statement_id , " No statement_id or journal_id passed to the method! "
journal = self . pool [ ' account.journal ' ] . browse ( cr , uid , journal_id , context = context )
# use the company of the journal and not of the current user
company_cxt = dict ( context , force_company = journal . company_id . id )
account_def = property_obj . get ( cr , uid , ' property_account_receivable ' , ' res.partner ' , context = company_cxt )
2014-07-18 13:43:00 +00:00
args [ ' account_id ' ] = ( order . partner_id and order . partner_id . property_account_receivable \
and order . partner_id . property_account_receivable . id ) or ( account_def and account_def . id ) or False
if not args [ ' account_id ' ] :
if not args [ ' partner_id ' ] :
msg = _ ( ' There is no receivable account defined to make payment. ' )
else :
msg = _ ( ' There is no receivable account defined to make payment for the partner: " %s " (id: %d ). ' ) % ( order . partner_id . name , order . partner_id . id , )
raise osv . except_osv ( _ ( ' Configuration Error! ' ) , msg )
2012-11-03 15:25:04 +00:00
2012-05-07 13:09:46 +00:00
context . pop ( ' pos_session_id ' , False )
2012-05-09 15:12:21 +00:00
for statement in order . session_id . statement_ids :
2012-11-03 15:25:04 +00:00
if statement . id == statement_id :
journal_id = statement . journal_id . id
break
elif statement . journal_id . id == journal_id :
2012-05-09 15:12:21 +00:00
statement_id = statement . id
break
if not statement_id :
2012-08-07 11:31:37 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' You have to open at least one cashbox. ' ) )
2012-05-09 15:12:21 +00:00
args . update ( {
2014-07-18 13:43:00 +00:00
' statement_id ' : statement_id ,
' pos_statement_id ' : order_id ,
' journal_id ' : journal_id ,
' ref ' : order . session_id . name ,
2012-05-09 15:12:21 +00:00
} )
2010-10-26 05:37:43 +00:00
statement_line_obj . create ( cr , uid , args , context = context )
2008-08-24 14:45:43 +00:00
2010-01-18 08:38:26 +00:00
return statement_id
2008-08-24 14:45:43 +00:00
2010-06-11 13:03:03 +00:00
def refund ( self , cr , uid , ids , context = None ) :
2010-10-08 06:13:09 +00:00
""" Create a copy of order for refund order """
2008-08-24 14:45:43 +00:00
clone_list = [ ]
line_obj = self . pool . get ( ' pos.order.line ' )
2013-08-28 12:39:40 +00:00
2010-10-26 05:37:43 +00:00
for order in self . browse ( cr , uid , ids , context = context ) :
2013-08-28 12:39:40 +00:00
current_session_ids = self . pool . get ( ' pos.session ' ) . search ( cr , uid , [
( ' state ' , ' != ' , ' closed ' ) ,
( ' user_id ' , ' = ' , uid ) ] , context = context )
if not current_session_ids :
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' To return product(s), you need to open a session that will be used to register the refund. ' ) )
2008-08-24 14:45:43 +00:00
clone_id = self . copy ( cr , uid , order . id , {
2013-08-28 12:39:40 +00:00
' name ' : order . name + ' REFUND ' , # not used, name forced by create
' session_id ' : current_session_ids [ 0 ] ,
' date_order ' : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
2011-09-25 14:09:30 +00:00
} , context = context )
2008-08-24 14:45:43 +00:00
clone_list . append ( clone_id )
2010-01-18 08:38:26 +00:00
2010-10-26 05:37:43 +00:00
for clone in self . browse ( cr , uid , clone_list , context = context ) :
2008-08-24 14:45:43 +00:00
for order_line in clone . lines :
line_obj . write ( cr , uid , [ order_line . id ] , {
2010-01-18 08:38:26 +00:00
' qty ' : - order_line . qty
2011-09-25 14:09:30 +00:00
} , context = context )
2011-01-17 11:20:56 +00:00
2011-09-25 14:09:30 +00:00
abs = {
' name ' : _ ( ' Return Products ' ) ,
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : ' pos.order ' ,
' res_id ' : clone_list [ 0 ] ,
' view_id ' : False ,
' context ' : context ,
' type ' : ' ir.actions.act_window ' ,
' nodestroy ' : True ,
' target ' : ' current ' ,
}
return abs
2011-01-17 11:20:56 +00:00
2011-12-18 18:33:39 +00:00
def action_invoice_state ( self , cr , uid , ids , context = None ) :
return self . write ( cr , uid , ids , { ' state ' : ' invoiced ' } , context = context )
2011-09-25 14:09:30 +00:00
def action_invoice ( self , cr , uid , ids , context = None ) :
2008-08-24 14:45:43 +00:00
inv_ref = self . pool . get ( ' account.invoice ' )
inv_line_ref = self . pool . get ( ' account.invoice.line ' )
2010-10-26 05:37:43 +00:00
product_obj = self . pool . get ( ' product.product ' )
2008-08-24 14:45:43 +00:00
inv_ids = [ ]
2010-10-26 05:37:43 +00:00
for order in self . pool . get ( ' pos.order ' ) . browse ( cr , uid , ids , context = context ) :
2008-08-24 14:45:43 +00:00
if order . invoice_id :
inv_ids . append ( order . invoice_id . id )
continue
if not order . partner_id :
2012-07-25 10:34:49 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' Please provide a partner for the sale. ' ) )
2008-08-24 14:45:43 +00:00
2010-10-26 05:37:43 +00:00
acc = order . partner_id . property_account_receivable . id
2008-08-24 14:45:43 +00:00
inv = {
2011-12-18 18:33:39 +00:00
' name ' : order . name ,
2008-08-24 14:45:43 +00:00
' origin ' : order . name ,
2010-10-26 05:37:43 +00:00
' account_id ' : acc ,
' journal_id ' : order . sale_journal . id or None ,
2008-08-24 14:45:43 +00:00
' type ' : ' out_invoice ' ,
' reference ' : order . name ,
' partner_id ' : order . partner_id . id ,
' comment ' : order . note or ' ' ,
2011-02-23 14:34:55 +00:00
' currency_id ' : order . pricelist_id . currency_id . id , # considering partner's sale pricelist's currency
2008-08-24 14:45:43 +00:00
}
inv . update ( inv_ref . onchange_partner_id ( cr , uid , [ ] , ' out_invoice ' , order . partner_id . id ) [ ' value ' ] )
2010-01-18 08:38:26 +00:00
if not inv . get ( ' account_id ' , None ) :
inv [ ' account_id ' ] = acc
2010-10-26 05:37:43 +00:00
inv_id = inv_ref . create ( cr , uid , inv , context = context )
2008-08-24 14:45:43 +00:00
2010-10-26 05:37:43 +00:00
self . write ( cr , uid , [ order . id ] , { ' invoice_id ' : inv_id , ' state ' : ' invoiced ' } , context = context )
2008-08-24 14:45:43 +00:00
inv_ids . append ( inv_id )
for line in order . lines :
inv_line = {
' invoice_id ' : inv_id ,
' product_id ' : line . product_id . id ,
' quantity ' : line . qty ,
2015-02-19 13:38:45 +00:00
' account_analytic_id ' : self . _prepare_analytic_account ( cr , uid , line , context = context ) ,
2008-08-24 14:45:43 +00:00
}
2010-04-08 09:20:32 +00:00
inv_name = product_obj . name_get ( cr , uid , [ line . product_id . id ] , context = context ) [ 0 ] [ 1 ]
2008-08-24 14:45:43 +00:00
inv_line . update ( inv_line_ref . product_id_change ( cr , uid , [ ] ,
2010-01-18 08:38:26 +00:00
line . product_id . id ,
line . product_id . uom_id . id ,
2010-11-05 01:29:52 +00:00
line . qty , partner_id = order . partner_id . id ,
fposition_id = order . partner_id . property_account_position . id ) [ ' value ' ] )
2008-08-24 14:45:43 +00:00
inv_line [ ' price_unit ' ] = line . price_unit
inv_line [ ' discount ' ] = line . discount
2010-02-03 05:47:12 +00:00
inv_line [ ' name ' ] = inv_name
2014-11-07 10:08:19 +00:00
inv_line [ ' invoice_line_tax_id ' ] = [ ( 6 , 0 , inv_line [ ' invoice_line_tax_id ' ] ) ]
2010-10-26 05:37:43 +00:00
inv_line_ref . create ( cr , uid , inv_line , context = context )
2011-09-25 17:04:16 +00:00
inv_ref . button_reset_taxes ( cr , uid , [ inv_id ] , context = context )
2014-07-07 09:50:30 +00:00
self . signal_workflow ( cr , uid , [ order . id ] , ' invoice ' )
inv_ref . signal_workflow ( cr , uid , [ inv_id ] , ' validate ' )
2008-08-24 14:45:43 +00:00
2011-09-25 14:09:30 +00:00
if not inv_ids : return { }
2012-03-30 08:27:51 +00:00
2011-09-25 14:09:30 +00:00
mod_obj = self . pool . get ( ' ir.model.data ' )
res = mod_obj . get_object_reference ( cr , uid , ' account ' , ' invoice_form ' )
2011-09-25 17:04:16 +00:00
res_id = res and res [ 1 ] or False
2011-09-25 14:09:30 +00:00
return {
2011-12-11 10:18:45 +00:00
' name ' : _ ( ' Customer Invoice ' ) ,
2011-09-25 14:09:30 +00:00
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
2011-12-28 09:06:08 +00:00
' view_id ' : [ res_id ] ,
2011-09-25 14:09:30 +00:00
' res_model ' : ' account.invoice ' ,
' context ' : " { ' type ' : ' out_invoice ' } " ,
' type ' : ' ir.actions.act_window ' ,
' nodestroy ' : True ,
' target ' : ' current ' ,
' res_id ' : inv_ids and inv_ids [ 0 ] or False ,
}
2008-08-24 14:45:43 +00:00
def create_account_move ( self , cr , uid , ids , context = None ) :
2012-06-01 15:44:29 +00:00
return self . _create_account_move_line ( cr , uid , ids , None , None , context = context )
2012-06-01 09:53:56 +00:00
2014-10-27 22:52:43 +00:00
def _prepare_analytic_account ( self , cr , uid , line , context = None ) :
''' This method is designed to be inherited in a custom module '''
return False
2015-04-13 17:43:53 +00:00
def _create_account_move ( self , cr , uid , dt , ref , journal_id , company_id , context = None ) :
local_context = dict ( context or { } , company_id = company_id )
start_at_datetime = datetime . strptime ( dt , tools . DEFAULT_SERVER_DATETIME_FORMAT )
date_tz_user = fields . datetime . context_timestamp ( cr , uid , start_at_datetime , context = context )
date_tz_user = date_tz_user . strftime ( tools . DEFAULT_SERVER_DATE_FORMAT )
period_id = self . pool [ ' account.period ' ] . find ( cr , uid , dt = date_tz_user , context = local_context )
return self . pool [ ' account.move ' ] . create ( cr , uid , { ' ref ' : ref , ' journal_id ' : journal_id , ' period_id ' : period_id [ 0 ] } , context = context )
2012-06-01 15:44:29 +00:00
def _create_account_move_line ( self , cr , uid , ids , session = None , move_id = None , context = None ) :
2012-06-01 09:53:56 +00:00
# Tricky, via the workflow, we only have one id in the ids variable
2011-09-25 14:09:30 +00:00
""" Create a account move line of order grouped by products or not. """
2008-08-24 14:45:43 +00:00
account_move_obj = self . pool . get ( ' account.move ' )
account_period_obj = self . pool . get ( ' account.period ' )
account_tax_obj = self . pool . get ( ' account.tax ' )
2012-06-01 15:44:29 +00:00
property_obj = self . pool . get ( ' ir.property ' )
2013-04-09 16:00:21 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
2012-06-01 15:44:29 +00:00
2012-06-04 10:56:10 +00:00
#session_ids = set(order.session_id for order in self.browse(cr, uid, ids, context=context))
2012-06-01 15:44:29 +00:00
if session and not all ( session . id == order . session_id . id for order in self . browse ( cr , uid , ids , context = context ) ) :
2012-07-25 10:49:32 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' Selected orders do not have the same session! ' ) )
2012-06-01 15:44:29 +00:00
grouped_data = { }
have_to_group_by = session and session . config_id . group_by or False
def compute_tax ( amount , tax , line ) :
if amount > 0 :
tax_code_id = tax [ ' base_code_id ' ]
tax_amount = line . price_subtotal * tax [ ' base_sign ' ]
else :
tax_code_id = tax [ ' ref_base_code_id ' ]
2015-04-02 14:15:19 +00:00
tax_amount = - line . price_subtotal * tax [ ' ref_base_sign ' ]
2012-06-01 15:44:29 +00:00
return ( tax_code_id , tax_amount , )
2008-08-24 14:45:43 +00:00
for order in self . browse ( cr , uid , ids , context = context ) :
2012-06-01 09:53:56 +00:00
if order . account_move :
continue
2012-05-04 12:51:58 +00:00
if order . state != ' paid ' :
continue
2011-09-25 14:09:30 +00:00
2014-02-06 16:34:44 +00:00
current_company = order . sale_journal . company_id
2012-06-01 15:44:29 +00:00
2008-08-24 14:45:43 +00:00
group_tax = { }
2013-03-15 14:42:26 +00:00
account_def = property_obj . get ( cr , uid , ' property_account_receivable ' , ' res.partner ' , context = context )
2010-07-12 13:40:45 +00:00
2012-06-01 15:44:29 +00:00
order_account = order . partner_id and \
order . partner_id . property_account_receivable and \
2013-03-15 14:42:26 +00:00
order . partner_id . property_account_receivable . id or \
account_def and account_def . id or current_company . account_receivable . id
2008-08-24 14:45:43 +00:00
2012-06-01 09:53:56 +00:00
if move_id is None :
# Create an entry for the sale
2015-04-13 17:43:53 +00:00
move_id = self . _create_account_move ( cr , uid , order . session_id . start_at , order . name , order . sale_journal . id , order . company_id . id , context = context )
move = account_move_obj . browse ( cr , uid , move_id , context = context )
2008-08-24 14:45:43 +00:00
2012-06-01 15:44:29 +00:00
def insert_data ( data_type , values ) :
# if have_to_group_by:
2012-06-04 16:08:33 +00:00
sale_journal_id = order . sale_journal . id
2012-06-01 15:44:29 +00:00
# 'quantity': line.qty,
# 'product_id': line.product_id.id,
values . update ( {
' date ' : order . date_order [ : 10 ] ,
' ref ' : order . name ,
2014-08-20 18:24:09 +00:00
' partner_id ' : order . partner_id and self . pool . get ( " res.partner " ) . _find_accounting_partner ( order . partner_id ) . id or False ,
2012-06-01 15:44:29 +00:00
' journal_id ' : sale_journal_id ,
2015-04-13 17:43:53 +00:00
' period_id ' : move . period_id . id ,
2012-06-01 15:44:29 +00:00
' move_id ' : move_id ,
2014-02-06 16:34:44 +00:00
' company_id ' : current_company . id ,
2012-06-01 15:44:29 +00:00
} )
if data_type == ' product ' :
2015-01-08 22:16:38 +00:00
key = ( ' product ' , values [ ' partner_id ' ] , values [ ' product_id ' ] , values [ ' analytic_account_id ' ] , values [ ' debit ' ] > 0 )
2012-06-01 15:44:29 +00:00
elif data_type == ' tax ' :
2013-06-26 09:34:12 +00:00
key = ( ' tax ' , values [ ' partner_id ' ] , values [ ' tax_code_id ' ] , values [ ' debit ' ] > 0 )
2012-06-01 15:44:29 +00:00
elif data_type == ' counter_part ' :
2013-06-26 09:34:12 +00:00
key = ( ' counter_part ' , values [ ' partner_id ' ] , values [ ' account_id ' ] , values [ ' debit ' ] > 0 )
2012-06-01 15:44:29 +00:00
else :
return
2012-06-04 10:56:10 +00:00
grouped_data . setdefault ( key , [ ] )
# if not have_to_group_by or (not grouped_data[key]):
# grouped_data[key].append(values)
# else:
# pass
2012-06-01 15:44:29 +00:00
if have_to_group_by :
2012-06-04 10:56:10 +00:00
if not grouped_data [ key ] :
grouped_data [ key ] . append ( values )
else :
2015-02-03 16:08:45 +00:00
for line in grouped_data [ key ] :
if line . get ( ' tax_code_id ' ) == values . get ( ' tax_code_id ' ) :
current_value = line
current_value [ ' quantity ' ] = current_value . get ( ' quantity ' , 0.0 ) + values . get ( ' quantity ' , 0.0 )
current_value [ ' credit ' ] = current_value . get ( ' credit ' , 0.0 ) + values . get ( ' credit ' , 0.0 )
current_value [ ' debit ' ] = current_value . get ( ' debit ' , 0.0 ) + values . get ( ' debit ' , 0.0 )
current_value [ ' tax_amount ' ] = current_value . get ( ' tax_amount ' , 0.0 ) + values . get ( ' tax_amount ' , 0.0 )
break
else :
grouped_data [ key ] . append ( values )
2012-06-01 15:44:29 +00:00
else :
grouped_data [ key ] . append ( values )
2013-03-06 17:46:16 +00:00
#because of the weird way the pos order is written, we need to make sure there is at least one line,
#because just after the 'for' loop there are references to 'line' and 'income_account' variables (that
#are set inside the for loop)
#TOFIX: a deep refactoring of this method (and class!) is needed in order to get rid of this stupid hack
assert order . lines , _ ( ' The POS order must have lines when calling this method ' )
2008-08-24 14:45:43 +00:00
# Create an move for each order line
2013-04-11 22:43:06 +00:00
cur = order . pricelist_id . currency_id
2008-08-24 14:45:43 +00:00
for line in order . lines :
tax_amount = 0
2014-02-06 16:34:44 +00:00
taxes = [ ]
for t in line . product_id . taxes_id :
2014-02-10 16:06:45 +00:00
if t . company_id . id == current_company . id :
2014-02-06 16:34:44 +00:00
taxes . append ( t )
2012-06-01 15:44:29 +00:00
computed_taxes = account_tax_obj . compute_all ( cr , uid , taxes , line . price_unit * ( 100.0 - line . discount ) / 100.0 , line . qty ) [ ' taxes ' ]
2008-08-24 14:45:43 +00:00
for tax in computed_taxes :
2013-04-09 16:00:21 +00:00
tax_amount + = cur_obj . round ( cr , uid , cur , tax [ ' amount ' ] )
2015-04-02 14:15:19 +00:00
if tax_amount < 0 :
group_key = ( tax [ ' ref_tax_code_id ' ] , tax [ ' base_code_id ' ] , tax [ ' account_collected_id ' ] , tax [ ' id ' ] )
else :
group_key = ( tax [ ' tax_code_id ' ] , tax [ ' base_code_id ' ] , tax [ ' account_collected_id ' ] , tax [ ' id ' ] )
2012-06-01 15:44:29 +00:00
group_tax . setdefault ( group_key , 0 )
2013-04-09 16:00:21 +00:00
group_tax [ group_key ] + = cur_obj . round ( cr , uid , cur , tax [ ' amount ' ] )
2008-08-24 14:45:43 +00:00
2011-09-25 14:09:30 +00:00
amount = line . price_subtotal
2008-08-24 14:45:43 +00:00
# Search for the income account
if line . product_id . property_account_income . id :
2011-12-22 09:49:14 +00:00
income_account = line . product_id . property_account_income . id
elif line . product_id . categ_id . property_account_income_categ . id :
income_account = line . product_id . categ_id . property_account_income_categ . id
2008-08-24 14:45:43 +00:00
else :
2012-07-25 10:49:32 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' Please define income ' \
' account for this product: " %s " (id: %d ). ' ) \
2008-08-24 14:45:43 +00:00
% ( line . product_id . name , line . product_id . id , ) )
# Empty the tax list as long as there is no tax code:
tax_code_id = False
tax_amount = 0
while computed_taxes :
tax = computed_taxes . pop ( 0 )
2012-06-01 15:44:29 +00:00
tax_code_id , tax_amount = compute_tax ( amount , tax , line )
2008-08-24 14:45:43 +00:00
# If there is one we stop
if tax_code_id :
break
# Create a move for the line
2012-06-01 15:44:29 +00:00
insert_data ( ' product ' , {
2012-05-04 12:51:58 +00:00
' name ' : line . product_id . name ,
2010-01-18 08:38:26 +00:00
' quantity ' : line . qty ,
2010-10-26 05:37:43 +00:00
' product_id ' : line . product_id . id ,
2008-08-24 14:45:43 +00:00
' account_id ' : income_account ,
2014-10-27 22:52:43 +00:00
' analytic_account_id ' : self . _prepare_analytic_account ( cr , uid , line , context = context ) ,
2008-08-24 14:45:43 +00:00
' credit ' : ( ( amount > 0 ) and amount ) or 0.0 ,
' debit ' : ( ( amount < 0 ) and - amount ) or 0.0 ,
' tax_code_id ' : tax_code_id ,
' tax_amount ' : tax_amount ,
2013-03-28 11:28:29 +00:00
' partner_id ' : order . partner_id and self . pool . get ( " res.partner " ) . _find_accounting_partner ( order . partner_id ) . id or False
2012-06-01 15:44:29 +00:00
} )
2008-08-24 14:45:43 +00:00
# For each remaining tax with a code, whe create a move line
for tax in computed_taxes :
2012-06-01 15:44:29 +00:00
tax_code_id , tax_amount = compute_tax ( amount , tax , line )
2008-08-24 14:45:43 +00:00
if not tax_code_id :
continue
2012-06-01 15:44:29 +00:00
insert_data ( ' tax ' , {
2012-05-25 12:24:15 +00:00
' name ' : _ ( ' Tax ' ) ,
2010-01-18 08:38:26 +00:00
' product_id ' : line . product_id . id ,
' quantity ' : line . qty ,
2008-08-24 14:45:43 +00:00
' account_id ' : income_account ,
' credit ' : 0.0 ,
' debit ' : 0.0 ,
' tax_code_id ' : tax_code_id ,
' tax_amount ' : tax_amount ,
2013-03-28 12:16:15 +00:00
' partner_id ' : order . partner_id and self . pool . get ( " res.partner " ) . _find_accounting_partner ( order . partner_id ) . id or False
2012-06-01 15:44:29 +00:00
} )
2008-08-24 14:45:43 +00:00
# Create a move for each tax group
2012-05-25 12:24:15 +00:00
( tax_code_pos , base_code_pos , account_pos , tax_id ) = ( 0 , 1 , 2 , 3 )
2012-06-01 15:44:29 +00:00
for key , tax_amount in group_tax . items ( ) :
2012-05-25 12:24:15 +00:00
tax = self . pool . get ( ' account.tax ' ) . browse ( cr , uid , key [ tax_id ] , context = context )
2012-06-01 15:44:29 +00:00
insert_data ( ' tax ' , {
2012-05-25 12:24:15 +00:00
' name ' : _ ( ' Tax ' ) + ' ' + tax . name ,
2010-01-18 08:38:26 +00:00
' quantity ' : line . qty ,
2010-10-26 05:37:43 +00:00
' product_id ' : line . product_id . id ,
2013-03-06 15:55:48 +00:00
' account_id ' : key [ account_pos ] or income_account ,
2012-06-01 15:44:29 +00:00
' credit ' : ( ( tax_amount > 0 ) and tax_amount ) or 0.0 ,
' debit ' : ( ( tax_amount < 0 ) and - tax_amount ) or 0.0 ,
2008-08-24 14:45:43 +00:00
' tax_code_id ' : key [ tax_code_pos ] ,
2015-04-02 14:15:19 +00:00
' tax_amount ' : abs ( tax_amount ) ,
2013-03-28 12:16:15 +00:00
' partner_id ' : order . partner_id and self . pool . get ( " res.partner " ) . _find_accounting_partner ( order . partner_id ) . id or False
2012-06-01 15:44:29 +00:00
} )
2008-08-24 14:45:43 +00:00
# counterpart
2012-06-01 15:44:29 +00:00
insert_data ( ' counter_part ' , {
2012-05-10 07:48:04 +00:00
' name ' : _ ( " Trade Receivables " ) , #order.name,
2008-08-24 14:45:43 +00:00
' account_id ' : order_account ,
2012-06-01 15:44:29 +00:00
' credit ' : ( ( order . amount_total < 0 ) and - order . amount_total ) or 0.0 ,
' debit ' : ( ( order . amount_total > 0 ) and order . amount_total ) or 0.0 ,
2013-03-28 11:28:29 +00:00
' partner_id ' : order . partner_id and self . pool . get ( " res.partner " ) . _find_accounting_partner ( order . partner_id ) . id or False
2012-06-01 15:44:29 +00:00
} )
order . write ( { ' state ' : ' done ' , ' account_move ' : move_id } )
2013-03-28 15:55:49 +00:00
all_lines = [ ]
2012-06-01 15:44:29 +00:00
for group_key , group_data in grouped_data . iteritems ( ) :
for value in group_data :
2013-03-28 15:55:49 +00:00
all_lines . append ( ( 0 , 0 , value ) , )
if move_id : #In case no order was changed
self . pool . get ( " account.move " ) . write ( cr , uid , [ move_id ] , { ' line_id ' : all_lines } , context = context )
2012-05-04 12:51:58 +00:00
2008-08-24 14:45:43 +00:00
return True
2010-01-18 08:38:26 +00:00
def action_payment ( self , cr , uid , ids , context = None ) :
2011-09-25 14:09:30 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' payment ' } , context = context )
2010-01-18 08:38:26 +00:00
2008-08-24 14:45:43 +00:00
def action_paid ( self , cr , uid , ids , context = None ) :
2011-09-25 14:09:30 +00:00
self . write ( cr , uid , ids , { ' state ' : ' paid ' } , context = context )
2014-05-07 12:01:44 +00:00
self . create_picking ( cr , uid , ids , context = context )
2008-08-24 14:45:43 +00:00
return True
def action_cancel ( self , cr , uid , ids , context = None ) :
2010-10-26 05:37:43 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancel ' } , context = context )
2008-08-24 14:45:43 +00:00
return True
def action_done ( self , cr , uid , ids , context = None ) :
2011-09-25 14:09:30 +00:00
self . create_account_move ( cr , uid , ids , context = context )
2008-08-24 14:45:43 +00:00
return True
2010-04-23 14:57:42 +00:00
class account_bank_statement ( osv . osv ) :
_inherit = ' account.bank.statement '
2010-08-13 12:20:05 +00:00
_columns = {
2011-09-25 14:09:30 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' User ' , readonly = True ) ,
2010-04-23 14:57:42 +00:00
}
_defaults = {
2011-09-25 14:09:30 +00:00
' user_id ' : lambda self , cr , uid , c = { } : uid
2010-04-23 14:57:42 +00:00
}
class account_bank_statement_line ( osv . osv ) :
_inherit = ' account.bank.statement.line '
2010-08-13 12:20:05 +00:00
_columns = {
2010-10-26 05:37:43 +00:00
' pos_statement_id ' : fields . many2one ( ' pos.order ' , ondelete = ' cascade ' ) ,
2010-04-23 14:57:42 +00:00
}
2012-08-28 11:21:16 +00:00
2010-04-23 14:57:42 +00:00
2008-08-24 14:45:43 +00:00
class pos_order_line ( osv . osv ) :
_name = " pos.order.line "
_description = " Lines of Point of Sale "
2011-09-25 14:09:30 +00:00
_rec_name = " product_id "
2008-08-24 14:45:43 +00:00
2010-11-19 13:48:01 +00:00
def _amount_line_all ( self , cr , uid , ids , field_names , arg , context = None ) :
2010-09-27 14:40:24 +00:00
res = dict ( [ ( i , { } ) for i in ids ] )
account_tax_obj = self . pool . get ( ' account.tax ' )
2011-09-25 14:09:30 +00:00
cur_obj = self . pool . get ( ' res.currency ' )
2010-11-19 13:48:01 +00:00
for line in self . browse ( cr , uid , ids , context = context ) :
2013-02-27 10:45:05 +00:00
taxes_ids = [ tax for tax in line . product_id . taxes_id if tax . company_id . id == line . order_id . company_id . id ]
2011-09-25 14:09:30 +00:00
price = line . price_unit * ( 1 - ( line . discount or 0.0 ) / 100.0 )
2013-01-22 12:56:56 +00:00
taxes = account_tax_obj . compute_all ( cr , uid , taxes_ids , price , line . qty , product = line . product_id , partner = line . order_id . partner_id or False )
2010-09-27 14:40:24 +00:00
2011-09-25 14:09:30 +00:00
cur = line . order_id . pricelist_id . currency_id
res [ line . id ] [ ' price_subtotal ' ] = cur_obj . round ( cr , uid , cur , taxes [ ' total ' ] )
res [ line . id ] [ ' price_subtotal_incl ' ] = cur_obj . round ( cr , uid , cur , taxes [ ' total_included ' ] )
return res
2010-09-29 09:57:42 +00:00
2011-09-25 14:09:30 +00:00
def onchange_product_id ( self , cr , uid , ids , pricelist , product_id , qty = 0 , partner_id = False , context = None ) :
context = context or { }
if not product_id :
return { }
if not pricelist :
2013-04-29 07:15:57 +00:00
raise osv . except_osv ( _ ( ' No Pricelist! ' ) ,
2011-09-25 14:09:30 +00:00
_ ( ' You have to select a pricelist in the sale form ! \n ' \
' Please set one before choosing a product. ' ) )
price = self . pool . get ( ' product.pricelist ' ) . price_get ( cr , uid , [ pricelist ] ,
product_id , qty or 1.0 , partner_id ) [ pricelist ]
result = self . onchange_qty ( cr , uid , ids , product_id , 0.0 , qty , price , context = context )
result [ ' value ' ] [ ' price_unit ' ] = price
return result
def onchange_qty ( self , cr , uid , ids , product , discount , qty , price_unit , context = None ) :
result = { }
if not product :
return result
account_tax_obj = self . pool . get ( ' account.tax ' )
cur_obj = self . pool . get ( ' res.currency ' )
2010-09-29 09:57:42 +00:00
2011-09-25 14:09:30 +00:00
prod = self . pool . get ( ' product.product ' ) . browse ( cr , uid , product , context = context )
2010-09-27 14:21:50 +00:00
2011-09-25 14:09:30 +00:00
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 )
2010-09-27 14:21:50 +00:00
2011-09-25 14:09:30 +00:00
result [ ' price_subtotal ' ] = taxes [ ' total ' ]
result [ ' price_subtotal_incl ' ] = taxes [ ' total_included ' ]
return { ' value ' : result }
2010-09-27 14:40:24 +00:00
2008-08-24 14:45:43 +00:00
_columns = {
2010-10-26 05:37:43 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True ) ,
2014-07-06 14:44:26 +00:00
' name ' : fields . char ( ' Line No ' , required = True , copy = False ) ,
2014-05-21 09:52:05 +00:00
' notice ' : fields . char ( ' Discount Notice ' ) ,
2008-08-24 14:45:43 +00:00
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , domain = [ ( ' sale_ok ' , ' = ' , True ) ] , required = True , change_default = True ) ,
2015-05-16 13:42:21 +00:00
' price_unit ' : fields . float ( string = ' Unit Price ' , digits_compute = dp . get_precision ( ' Product Price ' ) ) ,
2013-12-24 15:11:12 +00:00
' qty ' : fields . float ( ' Quantity ' , digits_compute = dp . get_precision ( ' Product UoS ' ) ) ,
2015-05-16 13:42:21 +00:00
' price_subtotal ' : fields . function ( _amount_line_all , multi = ' pos_order_line_amount ' , digits_compute = dp . get_precision ( ' Product Price ' ) , string = ' Subtotal w/o Tax ' , store = True ) ,
2014-11-11 17:00:24 +00:00
' price_subtotal_incl ' : fields . function ( _amount_line_all , multi = ' pos_order_line_amount ' , digits_compute = dp . get_precision ( ' Account ' ) , string = ' Subtotal ' , store = True ) ,
2013-12-24 15:11:12 +00:00
' discount ' : fields . float ( ' Discount ( % ) ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
2010-01-18 08:38:26 +00:00
' order_id ' : fields . many2one ( ' pos.order ' , ' Order Ref ' , ondelete = ' cascade ' ) ,
2009-01-27 11:15:46 +00:00
' create_date ' : fields . datetime ( ' Creation Date ' , readonly = True ) ,
2010-08-13 12:20:05 +00:00
}
2008-08-24 14:45:43 +00:00
_defaults = {
' name ' : lambda obj , cr , uid , context : obj . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' pos.order.line ' ) ,
' qty ' : lambda * a : 1 ,
' discount ' : lambda * a : 0.0 ,
2010-01-18 08:38:26 +00:00
' company_id ' : lambda self , cr , uid , c : self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , c ) . company_id . id ,
2011-09-25 14:09:30 +00:00
}
2008-08-24 14:45:43 +00:00
2012-07-20 17:00:12 +00:00
class ean_wizard ( osv . osv_memory ) :
_name = ' pos.ean_wizard '
_columns = {
2014-05-21 09:52:05 +00:00
' ean13_pattern ' : fields . char ( ' Reference ' , size = 13 , required = True , translate = True ) ,
2012-07-20 17:00:12 +00:00
}
def sanitize_ean13 ( self , cr , uid , ids , context ) :
for r in self . browse ( cr , uid , ids ) :
ean13 = openerp . addons . product . product . sanitize_ean13 ( r . ean13_pattern )
m = context . get ( ' active_model ' )
m_id = context . get ( ' active_id ' )
2013-03-29 14:37:20 +00:00
self . pool [ m ] . write ( cr , uid , [ m_id ] , { ' ean13 ' : ean13 } )
2012-07-25 12:51:15 +00:00
return { ' type ' : ' ir.actions.act_window_close ' }
2012-07-20 17:00:12 +00:00
2014-05-27 07:42:52 +00:00
class pos_category ( osv . osv ) :
_name = " pos.category "
_description = " Public Category "
_order = " sequence, name "
2012-07-20 17:00:12 +00:00
2014-05-27 07:42:52 +00:00
_constraints = [
( osv . osv . _check_recursion , ' Error ! You cannot create recursive categories. ' , [ ' parent_id ' ] )
]
2012-07-20 17:00:12 +00:00
2014-05-27 07:42:52 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
res = [ ]
2015-01-14 15:06:43 +00:00
for cat in self . browse ( cr , uid , ids , context = context ) :
names = [ cat . name ]
pcat = cat . parent_id
while pcat :
names . append ( pcat . name )
pcat = pcat . parent_id
res . append ( ( cat . id , ' / ' . join ( reversed ( names ) ) ) )
2014-05-27 07:42:52 +00:00
return res
def _name_get_fnc ( self , cr , uid , ids , prop , unknow_none , context = None ) :
res = self . name_get ( cr , uid , ids , context = context )
return dict ( res )
def _get_image ( self , cr , uid , ids , name , args , context = None ) :
result = dict . fromkeys ( ids , False )
for obj in self . browse ( cr , uid , ids , context = context ) :
result [ obj . id ] = tools . image_get_resized_images ( obj . image )
return result
def _set_image ( self , cr , uid , id , name , value , args , context = None ) :
return self . write ( cr , uid , [ id ] , { ' image ' : tools . image_resize_image_big ( value ) } , context = context )
_columns = {
' name ' : fields . char ( ' Name ' , required = True , translate = True ) ,
' complete_name ' : fields . function ( _name_get_fnc , type = " char " , string = ' Name ' ) ,
2014-05-27 08:36:08 +00:00
' parent_id ' : fields . many2one ( ' pos.category ' , ' Parent Category ' , select = True ) ,
' child_id ' : fields . one2many ( ' pos.category ' , ' parent_id ' , string = ' Children Categories ' ) ,
2014-05-27 07:42:52 +00:00
' sequence ' : fields . integer ( ' Sequence ' , help = " Gives the sequence order when displaying a list of product categories. " ) ,
# NOTE: there is no 'default image', because by default we don't show thumbnails for categories. However if we have a thumbnail
# for at least one category, then we display a default image on the other, so that the buttons have consistent styling.
# In this case, the default image is set by the js code.
# NOTE2: image: all image fields are base64 encoded and PIL-supported
' image ' : fields . binary ( " Image " ,
help = " This field holds the image used as image for the cateogry, limited to 1024x1024px. " ) ,
' image_medium ' : fields . function ( _get_image , fnct_inv = _set_image ,
string = " Medium-sized image " , type = " binary " , multi = " _get_image " ,
store = {
2014-05-27 08:36:08 +00:00
' pos.category ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' image ' ] , 10 ) ,
2014-05-27 07:42:52 +00:00
} ,
help = " Medium-sized image of the category. It is automatically " \
" resized as a 128x128px image, with aspect ratio preserved. " \
" Use this field in form views or some kanban views. " ) ,
' image_small ' : fields . function ( _get_image , fnct_inv = _set_image ,
string = " Smal-sized image " , type = " binary " , multi = " _get_image " ,
store = {
2014-05-27 08:36:08 +00:00
' pos.category ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' image ' ] , 10 ) ,
2014-05-27 07:42:52 +00:00
} ,
help = " Small-sized image of the category. It is automatically " \
" resized as a 64x64px image, with aspect ratio preserved. " \
" Use this field anywhere a small image is required. " ) ,
}
2012-02-09 14:23:55 +00:00
2014-05-27 07:42:52 +00:00
class product_template ( osv . osv ) :
_inherit = ' product.template '
2012-02-09 14:23:55 +00:00
2010-01-18 08:38:26 +00:00
_columns = {
2012-10-30 13:14:01 +00:00
' income_pdt ' : fields . boolean ( ' Point of Sale Cash In ' , help = " Check if, this is a product you can use to put cash into a statement for the point of sale backend. " ) ,
2012-10-31 07:27:58 +00:00
' expense_pdt ' : fields . boolean ( ' Point of Sale Cash Out ' , help = " Check if, this is a product you can use to take cash from a statement for the point of sale backend, example: money lost, transfer to bank, etc. " ) ,
2012-11-22 17:52:54 +00:00
' available_in_pos ' : fields . boolean ( ' Available in the Point of Sale ' , help = ' Check if you want this product to appear in the Point of Sale ' ) ,
2014-08-19 16:02:17 +00:00
' to_weight ' : fields . boolean ( ' To Weigh With Scale ' , help = " Check if the product should be weighted using the hardware scale integration " ) ,
2014-05-27 07:42:52 +00:00
' pos_categ_id ' : fields . many2one ( ' pos.category ' , ' Point of Sale Category ' , help = " Those categories are used to group similar products for point of sale. " ) ,
2010-08-13 12:20:05 +00:00
}
2012-08-29 12:25:01 +00:00
2012-05-29 12:15:56 +00:00
_defaults = {
' to_weight ' : False ,
2012-11-22 17:52:54 +00:00
' available_in_pos ' : True ,
2012-05-29 12:15:56 +00:00
}
2015-01-19 13:35:06 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2015-01-19 14:25:57 +00:00
product_ctx = dict ( context or { } , active_test = False )
if self . search_count ( cr , uid , [ ( ' id ' , ' in ' , ids ) , ( ' available_in_pos ' , ' = ' , True ) ] , context = product_ctx ) :
if self . pool [ ' pos.session ' ] . search_count ( cr , uid , [ ( ' state ' , ' != ' , ' closed ' ) ] , context = context ) :
2015-01-19 13:35:06 +00:00
raise osv . except_osv ( _ ( ' Error! ' ) ,
_ ( ' You cannot delete a product saleable in point of sale while a session is still opened. ' ) )
return super ( product_template , self ) . unlink ( cr , uid , ids , context = context )
2014-09-17 14:01:53 +00:00
class res_partner ( osv . osv ) :
_inherit = ' res.partner '
def create_from_ui ( self , cr , uid , partner , context = None ) :
""" create or modify a partner from the point of sale ui.
partner contains the partner ' s fields. " " "
#image is a dataurl, get the data after the comma
if partner . get ( ' image ' , False ) :
img = partner [ ' image ' ] . split ( ' , ' ) [ 1 ]
partner [ ' image ' ] = img
if partner . get ( ' id ' , False ) : # Modifying existing partner
partner_id = partner [ ' id ' ]
del partner [ ' id ' ]
self . write ( cr , uid , [ partner_id ] , partner , context = context )
else :
partner_id = self . create ( cr , uid , partner , context = context )
return partner_id
2011-11-22 08:51:38 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: