('deprecated', 'Deprecated')
]
+ def _get_currency(self, cr, uid, ids, fieldnames, args, context=None):
+ 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:
+ currency_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id.id
+ result[pos_config.id] = currency_id
+ return result
+
_columns = {
'name' : fields.char('Point of Sale Name', size=32, select=1,
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',
domain="[('journal_user', '=', True ), ('type', 'in', ['bank', 'cash'])]",),
- 'shop_id' : fields.many2one('sale.shop', 'Shop',
+ 'warehouse_id' : fields.many2one('stock.warehouse', 'Warehouse',
required=True),
'journal_id' : fields.many2one('account.journal', 'Sale Journal',
domain=[('type', '=', 'sale')],
help="Accounting journal used to post sales entries."),
+ 'currency_id' : fields.function(_get_currency, type="many2one", string="Currency", relation="res.currency"),
'iface_self_checkout' : fields.boolean('Self Checkout Mode',
help="Check this if this point of sale should open by default in a self checkout mode. If unchecked, OpenERP uses the normal cashier mode by default."),
- 'iface_cashdrawer' : fields.boolean('Cashdrawer Interface'),
- 'iface_payment_terminal' : fields.boolean('Payment Terminal Interface'),
- 'iface_electronic_scale' : fields.boolean('Electronic Scale Interface'),
- 'iface_vkeyboard' : fields.boolean('Virtual KeyBoard Interface'),
- 'iface_print_via_proxy' : fields.boolean('Print via Proxy'),
+ 'iface_cashdrawer' : fields.boolean('Cashdrawer',help="Automatically open the cashdrawer"),
+ '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"),
+ 'iface_invoicing': fields.boolean('Invoicing',help='Enables invoice generation from the Point of Sale'),
+ 'iface_big_scrollbars': fields.boolean('Large Scrollbars',help='For imprecise industrial touchscreens'),
+ '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"),
'state' : fields.selection(POS_CONFIG_STATE, 'Status', required=True, readonly=True),
'sequence_id' : fields.many2one('ir.sequence', 'Order IDs Sequence', readonly=True,
"to customize the reference numbers of your orders."),
'session_ids': fields.one2many('pos.session', 'config_id', 'Sessions'),
'group_by' : fields.boolean('Group Journal Items', help="Check this if you want to group the Journal Items by Product while closing a Session"),
+ 'pricelist_id': fields.many2one('product.pricelist','Pricelist', required=True)
}
def _check_cash_control(self, cr, uid, ids, context=None):
return result
def _default_sale_journal(self, cr, uid, context=None):
- res = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale')], limit=1)
+ 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)
return res and res[0] or False
- def _default_shop(self, cr, uid, context=None):
- res = self.pool.get('sale.shop').search(cr, uid, [])
+ def _default_warehouse(self, cr, uid, context=None):
+ user = self.pool.get('res.users').browse(cr, uid, uid, context)
+ res = self.pool.get('stock.warehouse').search(cr, uid, [('company_id', '=', user.company_id.id)], limit=1, context=context)
return res and res[0] or False
- def _default_payment_method(self, cr, uid, context=None):
- res = self.pool.get('account.journal').search(cr, uid, [('journal_user','=', True)], context=context)
- return res or False
+ def _default_pricelist(self, cr, uid, context=None):
+ res = self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale')], limit=1, context=context)
+ return res and res[0] or False
_defaults = {
'state' : POS_CONFIG_STATE[0][0],
- 'shop_id': _default_shop,
+ 'warehouse_id': _default_warehouse,
'journal_id': _default_sale_journal,
- 'journal_ids': _default_payment_method,
'group_by' : True,
+ 'pricelist_id': _default_pricelist,
+ 'iface_invoicing': True,
}
def set_active(self, cr, uid, ids, context=None):
readonly=True,
states={'opening_control' : [('readonly', False)]}
),
+ 'currency_id' : fields.related('config_id', 'currency_id', type="many2one", relation='res.currency', string="Currnecy"),
'start_at' : fields.datetime('Opening Date', readonly=True),
'stop_at' : fields.datetime('Closing Date', readonly=True),
type='float',
digits_compute=dp.get_precision('Account'),
string="Ending Balance",
- help="Computed using the cash control lines",
+ help="Total of closing cash control lines.",
readonly=True),
'cash_register_balance_start' : fields.related('cash_register_id', 'balance_start',
type='float',
digits_compute=dp.get_precision('Account'),
string="Starting Balance",
- help="Computed using the cash control at the opening.",
+ help="Total of opening cash control lines.",
readonly=True),
'cash_register_total_entry_encoding' : fields.related('cash_register_id', 'total_entry_encoding',
string='Total Cash Transaction',
- readonly=True),
+ readonly=True,
+ help="Total of all paid sale orders"),
'cash_register_balance_end' : fields.related('cash_register_id', 'balance_end',
type='float',
digits_compute=dp.get_precision('Account'),
- string="Computed Balance",
- help="Computed with the initial cash control and the sum of all payments.",
+ string="Theoretical Closing Balance",
+ help="Sum of opening balance and transactions.",
readonly=True),
'cash_register_difference' : fields.related('cash_register_id', 'difference',
type='float',
string='Difference',
- help="Difference between the counted cash control at the closing and the computed balance.",
+ help="Difference between the theoretical closing balance and the real closing balance.",
readonly=True),
'journal_ids' : fields.related('config_id', 'journal_ids',
# open if there is no session in 'opening_control', 'opened', 'closing_control' for one user
domain = [
('state', 'not in', ('closed','closing_control')),
- ('user_id', '=', uid)
+ ('user_id', '=', session.user_id.id)
]
count = self.search_count(cr, uid, domain, context=context)
if count>1:
# 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)
- context.update({'company_id': pos_config.shop_id.company_id.id})
+ context.update({'company_id': pos_config.warehouse_id.company_id.id})
if not pos_config.journal_id:
jid = jobj.default_get(cr, uid, ['journal_id'], context=context)['journal_id']
if jid:
bank_values = {
'journal_id' : journal.id,
'user_id' : uid,
- 'company_id' : pos_config.shop_id.company_id.id
+ 'company_id' : pos_config.warehouse_id.company_id.id
}
statement_id = self.pool.get('account.bank.statement').create(cr, uid, bank_values, context=context)
bank_statement_ids.append(statement_id)
context.update(active_id=this_record.id)
return {
- 'type' : 'ir.actions.client',
- 'name' : _('Start Point Of Sale'),
- 'tag' : 'pos.ui',
- 'context' : context,
+ 'type' : 'ir.actions.act_url',
+ 'url' : '/pos/web/',
+ 'target': 'self',
}
def wkf_action_open(self, cr, uid, ids, context=None):
# 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"):
raise osv.except_osv( _('Error!'),
- _("Your ending balance is too different from the theorical cash closing (%.2f), the maximum allowed is: %.2f. You can contact your manager to force it.") % (st.difference, st.journal_id.amount_authorized_diff))
+ _("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))
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 "))
context = {}
if not ids:
return {}
+ 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))
context.update({'active_id': ids[0]})
return {
- 'type' : 'ir.actions.client',
- 'name' : _('Start Point Of Sale'),
- 'tag' : 'pos.ui',
- 'context' : context,
+ 'type' : 'ir.actions.act_url',
+ 'target': 'self',
+ 'url': '/pos/web/',
}
class pos_order(osv.osv):
#_logger.info("orders: %r", orders)
order_ids = []
for tmp_order in orders:
+ to_invoice = tmp_order['to_invoice']
order = tmp_order['data']
+
+
order_id = self.create(cr, uid, {
'name': order['name'],
'user_id': order['user_id'] or False,
'session_id': order['pos_session_id'],
'lines': order['lines'],
- 'pos_reference':order['name']
+ 'pos_reference':order['name'],
+ 'partner_id': order['partner_id'] or False
}, context)
-
for payments in order['statement_ids']:
payment = payments[2]
self.add_payment(cr, uid, order_id, {
}, context=context)
order_ids.append(order_id)
self.signal_paid(cr, uid, [order_id])
+
+ if to_invoice:
+ self.action_invoice(cr, uid, [order_id], context)
+ order_obj = self.browse(cr, uid, order_id, context)
+ self.pool['account.invoice'].signal_invoice_open(cr, uid, [order_obj.invoice_id.id])
+
return order_ids
def write(self, cr, uid, ids, vals, context=None):
def unlink(self, cr, uid, ids, context=None):
for rec in self.browse(cr, uid, ids, context=context):
if rec.state not in ('draft','cancel'):
- raise osv.except_osv(_('Unable to Delete !'), _('In order to delete a sale, it must be new or cancelled.'))
+ raise osv.except_osv(_('Unable to Delete!'), _('In order to delete a sale, it must be new or cancelled.'))
return super(pos_order, self).unlink(cr, uid, ids, context=context)
def onchange_partner_id(self, cr, uid, ids, part=False, context=None):
_columns = {
'name': fields.char('Order Ref', size=64, required=True, readonly=True),
'company_id':fields.many2one('res.company', 'Company', required=True, readonly=True),
- 'shop_id': fields.related('session_id', 'config_id', 'shop_id', relation='sale.shop', type='many2one', string='Shop', store=True, readonly=True),
+ 'warehouse_id': fields.related('session_id', 'config_id', 'warehouse_id', relation='stock.warehouse', type='many2one', string='Warehouse', store=True, readonly=True),
'date_order': fields.datetime('Order Date', readonly=True, select=True),
'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."),
- 'amount_tax': fields.function(_amount_all, string='Taxes', digits_compute=dp.get_precision('Point Of Sale'), multi='all'),
+ 'amount_tax': fields.function(_amount_all, string='Taxes', digits_compute=dp.get_precision('Account'), multi='all'),
'amount_total': fields.function(_amount_all, string='Total', multi='all'),
- 'amount_paid': fields.function(_amount_all, string='Paid', states={'draft': [('readonly', False)]}, readonly=True, digits_compute=dp.get_precision('Point Of Sale'), multi='all'),
- 'amount_return': fields.function(_amount_all, 'Returned', digits_compute=dp.get_precision('Point Of Sale'), multi='all'),
+ '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'),
'lines': fields.one2many('pos.order.line', 'order_id', 'Order Lines', states={'draft': [('readonly', False)]}, readonly=True),
'statement_ids': fields.one2many('account.bank.statement.line', 'pos_statement_id', 'Payments', states={'draft': [('readonly', False)]}, readonly=True),
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', required=True, states={'draft': [('readonly', False)]}, readonly=True),
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)
- shop = self.pool.get('sale.shop').browse(cr, uid, session_record.config_id.shop_id.id, context=context)
- return shop.pricelist_id and shop.pricelist_id.id or False
+ return session_record.config_id.pricelist_id and session_record.config_id.pricelist_id.id or False
return False
_defaults = {
def create_picking(self, cr, uid, ids, context=None):
"""Create a picking for each order and validate it."""
- picking_obj = self.pool.get('stock.picking')
+ picking_obj = self.pool.get('stock.picking.out')
partner_obj = self.pool.get('res.partner')
move_obj = self.pool.get('stock.move')
'auto_picking': True,
}, context=context)
self.write(cr, uid, [order.id], {'picking_id': picking_id}, context=context)
- location_id = order.shop_id.warehouse_id.lot_stock_id.id
- output_id = order.shop_id.warehouse_id.lot_output_id.id
+ location_id = order.warehouse_id.lot_stock_id.id
+ if order.partner_id:
+ destination_id = order.partner_id.property_stock_customer.id
+ else:
+ destination_id = partner_obj.default_get(cr, uid, ['property_stock_customer'], context=context)['property_stock_customer']
for line in order.lines:
if line.product_id and line.product_id.type == 'service':
continue
- if line.qty < 0:
- location_id, output_id = output_id, location_id
move_obj.create(cr, uid, {
'name': line.name,
'product_qty': abs(line.qty),
'tracking_id': False,
'state': 'draft',
- 'location_id': location_id,
- 'location_dest_id': output_id,
+ 'location_id': location_id if line.qty >= 0 else destination_id,
+ 'location_dest_id': destination_id if line.qty >= 0 else location_id,
}, context=context)
- if line.qty < 0:
- location_id, output_id = output_id, location_id
picking_obj.signal_button_confirm(cr, uid, [picking_id])
picking_obj.force_assign(cr, uid, [picking_id], context)
@return: True
"""
stock_picking_obj = self.pool.get('stock.picking')
- wf_service = netsvc.LocalService("workflow")
for order in self.browse(cr, uid, ids, context=context):
stock_picking_obj.signal_button_cancel(cr, uid, [order.picking_id.id])
if stock_picking_obj.browse(cr, uid, order.picking_id.id, context=context).state <> 'cancel':
"""Create a copy of order for refund order"""
clone_list = []
line_obj = self.pool.get('pos.order.line')
+
for order in self.browse(cr, uid, ids, context=context):
+ 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.'))
+
clone_id = self.copy(cr, uid, order.id, {
- 'name': order.name + ' REFUND',
+ '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'),
}, context=context)
clone_list.append(clone_id)
inv_line_ref.create(cr, uid, inv_line, context=context)
inv_ref.button_reset_taxes(cr, uid, [inv_id], context=context)
self.signal_invoice(cr, uid, [order.id])
+ inv_ref.signal_validate(cr, uid, [inv_id])
if not inv_ids: return {}
user_company = user_proxy.browse(cr, order.user_id.id, order.user_id.id).company_id
group_tax = {}
- account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context).id
+ account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context)
order_account = order.partner_id and \
order.partner_id.property_account_receivable and \
- order.partner_id.property_account_receivable.id or account_def or current_company.account_receivable.id
+ order.partner_id.property_account_receivable.id or \
+ account_def and account_def.id or current_company.account_receivable.id
if move_id is None:
# Create an entry for the sale
})
if data_type == 'product':
- key = ('product', values['partner_id'], values['product_id'])
+ key = ('product', values['partner_id'], values['product_id'], values['debit'] > 0)
elif data_type == 'tax':
- key = ('tax', values['partner_id'], values['tax_code_id'],)
+ key = ('tax', values['partner_id'], values['tax_code_id'], values['debit'] > 0)
elif data_type == 'counter_part':
- key = ('counter_part', values['partner_id'], values['account_id'])
+ key = ('counter_part', values['partner_id'], values['account_id'], values['debit'] > 0)
else:
return
if not product_id:
return {}
if not pricelist:
- raise osv.except_osv(_('No Pricelist !'),
+ raise osv.except_osv(_('No Pricelist!'),
_('You have to select a pricelist in the sale form !\n' \
'Please set one before choosing a product.'))
'name': fields.char('Line No', size=32, required=True),
'notice': fields.char('Discount Notice', size=128),
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True, change_default=True),
- 'price_unit': fields.float(string='Unit Price', digits=(16, 2)),
- 'qty': fields.float('Quantity', digits=(16, 2)),
+ 'price_unit': fields.float(string='Unit Price', digits_compute=dp.get_precision('Account')),
+ 'qty': fields.float('Quantity', digits_compute=dp.get_precision('Product UoS')),
'price_subtotal': fields.function(_amount_line_all, multi='pos_order_line_amount', string='Subtotal w/o Tax', store=True),
'price_subtotal_incl': fields.function(_amount_line_all, multi='pos_order_line_amount', string='Subtotal', store=True),
- 'discount': fields.float('Discount (%)', digits=(16, 2)),
+ 'discount': fields.float('Discount (%)', digits_compute=dp.get_precision('Account')),
'order_id': fields.many2one('pos.order', 'Order Ref', ondelete='cascade'),
'create_date': fields.datetime('Creation Date', readonly=True),
}
'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."),
'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'),
'pos_categ_id': fields.many2one('pos.category','Point of Sale Category',
- help="The Point of Sale Category this products belongs to. Those categories are used to group similar products and are specific to the Point of Sale."),
+ help="These products belong to those categories that are used to group similar products and are specific to the Point of Sale."),
'to_weight' : fields.boolean('To Weight', help="Check if the product should be weighted (mainly used with self check-out interface)."),
}