[IMP] account: Add new wizard for the cash register "Take Money Out", "Put Money In"

[FIX] point_of_sale: Fix some bugs

bzr revid: stw@openerp.com-20120504125158-p45qfzo8mif6x9xe
This commit is contained in:
Stephane Wirtel 2012-05-04 14:51:58 +02:00
parent b9f8c8dec1
commit ec308a08e7
18 changed files with 327 additions and 44 deletions

View File

@ -100,6 +100,7 @@ module named account_voucher.
'wizard/account_reconcile_partner_process_view.xml',
'wizard/account_automatic_reconcile_view.xml',
'wizard/account_financial_report_view.xml',
'wizard/pos_box.xml',
'project/wizard/project_account_analytic_line_view.xml',
'account_end_fy.xml',
'account_invoice_view.xml',

View File

@ -739,6 +739,10 @@ class account_journal(osv.osv):
'entry_posted': fields.boolean('Skip \'Draft\' State for Manual Entries', help='Check this box if you don\'t want new journal entries to pass through the \'draft\' state and instead goes directly to the \'posted state\' without any manual validation. \nNote that journal entries that are automatically created by the system are always skipping that state.'),
'company_id': fields.many2one('res.company', 'Company', required=True, select=1, help="Company related to this journal"),
'allow_date':fields.boolean('Check Date in Period', help= 'If set to True then do not accept the entry if the entry date is not into the period dates'),
'profit_account_id' : fields.many2one('account.account', 'Profit Account'),
'loss_account_id' : fields.many2one('account.account', 'Loss Account'),
'internal_account_id' : fields.many2one('account.account', 'Internal Transfers Account', select=1),
}
_defaults = {

View File

@ -188,6 +188,14 @@ class account_cash_statement(osv.osv):
result[line.statement_id.id] = True
return result.keys()
def _compute_difference(self, cr, uid, ids, fieldnames, args, context=None):
result = dict.fromkeys(ids, 0.0)
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = obj.balance_end - obj.balance_end_cash
return result
_columns = {
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Cash Transaction", help="Total cash transactions",
store = {
@ -198,6 +206,7 @@ class account_cash_statement(osv.osv):
'balance_end_cash': fields.function(_balance_end_cash, store=False, string='Closing Balance', help="Closing balance based on cashBox"),
'details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='CashBox Lines'),
'user_id': fields.many2one('res.users', 'Responsible', required=False),
'difference' : fields.function(_compute_difference, method=True, string="Difference", type="float"),
}
_defaults = {
@ -234,7 +243,8 @@ class account_cash_statement(osv.osv):
for line in vals.get('details_ids',[]):
print "line: %r" % (line,)
if line and len(line)==3 and line[2]:
amount_total+= line[2]['pieces'] * line[2]['number_opening']
# FIXME: If there is no piece # does not work with GTK
amount_total+= line[2].get('pieces', 0) * line[2]['number_opening']
vals.update(balance_start= amount_total)
vals.update(balance_end_real=self._compute_balance_end_real(cr, uid, vals['journal_id'], context=context))
@ -287,7 +297,7 @@ class account_cash_statement(osv.osv):
balance_start = 0.0
if journal_id:
count = self.search_count(cr, uid, [('journal_id', '=', journal_id),('state', '=', 'open')], context=None)
if count:
if 0: # count:
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
raise osv.except_osv(_('Error !'), (_('The Account Journal %s is opened by an other Cash Register !') % (journal.name,)))
else:
@ -380,6 +390,33 @@ class account_cash_statement(osv.osv):
def button_confirm_cash(self, cr, uid, ids, context=None):
super(account_cash_statement, self).button_confirm_bank(cr, uid, ids, context=context)
absl_proxy = self.pool.get('account.bank.statement.line')
TABLES = (('Profit', 'profit_account_id'), ('Loss', 'loss_account_id'),)
for obj in self.browse(cr, uid, ids, context=context):
if obj.difference == 0.0:
continue
for item_label, item_account in TALBES:
if getattr(obj.journal_id, item_account):
raise osv.except_osv(_('Error !'),
_('There is no %s Account on the Journal %s') % (item_label, obj.journal_id.name,))
is_profit = obj.difference < 0.0
account = getattr(obj.journal_id, TABLES[is_profit][1])
values = {
'statement_id' : obj.id,
'journal_id' : obj.journal_id.id,
'account_id' : account.id,
'amount' : obj.difference,
'name' : 'Exceptional %s' % TABLES[is_profit][0],
}
absl_proxy.create(cr, uid, values, context=context)
return self.write(cr, uid, ids, {'closing_date': time.strftime("%Y-%m-%d %H:%M:%S")}, context=context)
def button_cancel(self, cr, uid, ids, context=None):

View File

@ -505,11 +505,17 @@
<field colspan="4" name="account_control_ids" nolabel="1"/>
</page>
<page string="Cash Box">
<field name="cashbox_line_ids" nolabel="1" string="Unit Of Currency Definition">
<field name="profit_account_id" />
<field name="loss_account_id" />
<separator string="Internal Account" colspan="4" />
<field name="internal_account_id" />
<separator string="Cash Box Lines" colspan="4" />
<field name="cashbox_line_ids" nolabel="1" string="Unit Of Currency Definition" colspan="4">
<tree string="CashBox Lines" editable="bottom">
<field name="pieces" />
</tree>
</field>
<label string="The Cashbox Lines will be used in the PoS Session" />
</page>
</notebook>
</form>
@ -2659,12 +2665,13 @@ action = pool.get('res.config').next(cr, uid, [], context)
</page>
<page string="CashBox">
<group col="2" expand="1">
<field name="details_ids" nolabel="1">
<field name="details_ids" nolabel="1" >
<!--attrs="{'readonly' : [('state', '=', 'open')]}">-->
<tree string="" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_opening" string="Opening Unit Numbers" on_change="on_change_sub_opening(pieces, number_opening, parent.balance_end)" />
<field name="number_opening" string="Opening Unit Numbers" on_change="on_change_sub_opening(pieces, number_opening, parent.balance_end)" attrs="{'readonly' : [('parent.state', '!=', 'open')]}" />
<field name="subtotal_opening" string="Opening Subtotal"/>
<field name="number_closing" string="Closing Unit Numbers" on_change="on_change_sub_closing(pieces, number_closing, parent.balance_end)" />
<field name="number_closing" string="Closing Unit Numbers" on_change="on_change_sub_closing(pieces, number_closing, parent.balance_end)" attrs="{'readonly' : [('parent.state', '!=', 'confirm')]}"/>
<field name="subtotal_closing" string="Closing Subtotal"/>
</tree>
</field>
@ -2677,7 +2684,7 @@ action = pool.get('res.config').next(cr, uid, [], context)
<group col="6" colspan="4">
<group col="2" colspan="2">
<separator string="Dates" colspan="4"/>
<field name="date" select="1" attrs="{'readonly':[('state','!=','draft')]}" on_change="onchange_date(date, company_id)"/>
<field name="date" select="1" attrs="{'readonly':[('state','!=','draft')]}" on_change="onchange_date(date, company_id)" string="Started On" />
<field name="closing_date" select="1" readonly="1"/>
</group>
<group col="2" colspan="2">
@ -2690,6 +2697,7 @@ action = pool.get('res.config').next(cr, uid, [], context)
<separator string="Closing Balance" colspan="4"/>
<field name="balance_end"/>
<field name="balance_end_cash"/>
<field name="difference" />
</group>
</group>
<group col="8" colspan="4">

View File

@ -64,6 +64,8 @@ import account_report_account_balance
import account_change_currency
import pos_box;
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,80 @@
#!/usr/bin/env python
from osv import osv, fields
import decimal_precision as dp
class CashBox(osv.osv_memory):
_register = False
_columns = {
'name' : fields.char('Reason', size=64, required=True),
# Attention, we don't set a domain, because there is a journal_type key
# in the context of the action
'amount' : fields.float('Amount',
digits_compute = dp.get_precision('Account'),
required=True),
}
def run(self, cr, uid, ids, context=None):
if not context:
context = dict()
active_model = context.get('active_model', False) or False
active_ids = context.get('active_ids', []) or []
records = self.pool.get(active_model).browse(cr, uid, active_ids, context=context)
return self._run(cr, uid, ids, records, context=None)
def _run(self, cr, uid, ids, records, context=None):
for box in self.browse(cr, uid, ids, context=context):
for record in records:
if not record.journal_id.internal_account_id:
raise osv.except_osv(_('Error !'),
_('Please check that internal account is set to %s') % (record.journal_id.name,))
self._create_bank_statement_line(cr, uid, box, record, context=context)
return {}
class CashBoxIn(CashBox):
_name = 'cash.box.in'
_columns = CashBox._columns.copy()
_columns.update({
'ref' : fields.char('Reference', size=32),
})
def _create_bank_statement_line(self, cr, uid, box, record, context=None):
absl_proxy = self.pool.get('account.bank.statement.line')
values = {
'statement_id' : record.id,
'journal_id' : record.journal_id.id,
'account_id' : record.journal_id.internal_account_id.id,
'amount' : box.amount or 0.0,
'ref' : "%s" % (box.ref or ''),
'name' : box.name,
}
return absl_proxy.create(cr, uid, values, context=context)
CashBoxIn()
class CashBoxOut(CashBox):
_name = 'cash.box.out'
def _create_bank_statement_line(self, cr, uid, box, record, context=None):
absl_proxy = self.pool.get('account.bank.statement.line')
amount = box.amount or 0.0
values = {
'statement_id' : record.id,
'journal_id' : record.journal_id.id,
'account_id' : record.journal_id.internal_account_id.id,
'amount' : -amount if amount > 0.0 else amount,
'name' : box.name,
}
return absl_proxy.create(cr, uid, values, context=context)
CashBoxOut()

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="cash_box_in_form">
<field name="name">cash_box_in</field>
<field name="model">cash.box.in</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Put Money In">
<separator string="Fill in this form if you put money in the cash register:" colspan="4" />
<field name="name" />
<field name="amount" />
<separator colspan="4" />
<group colspan="4" col="4">
<group col="2" colspan="2" />
<button icon="gtk-stop" special="cancel" string="Cancel" />
<button name="run" string="Put Money In" colspan="1" type="object" icon="gtk-apply" />
</group>
</form>
</field>
</record>
<act_window
name="Put Money In"
res_model="cash.box.in"
src_model="account.bank.statement"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_cash_box_in" />
<record model="ir.ui.view" id="cash_box_out_form">
<field name="name">cash_box_out</field>
<field name="model">cash.box.out</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Take Money Out">
<separator string="Describe why you take money from the cash register:" colspan="4" />
<field name="name" />
<field name="amount" />
<separator colspan="4" />
<group colspan="4" col="4">
<group col="2" colspan="2" />
<button icon="gtk-stop" special="cancel" string="Cancel" />
<button name="run" string="Take Money Out" colspan="1" type="object" icon="gtk-apply" />
</group>
</form>
</field>
</record>
<act_window
name="Take Money Out"
res_model="cash.box.out"
src_model="account.bank.statement"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_cash_box_out" />
</data>
</openerp>

View File

@ -51,14 +51,13 @@ Main features :
'wizard/pos_discount.xml',
'wizard/pos_open_statement.xml',
'wizard/pos_close_statement.xml',
'wizard/pos_box_entries.xml',
'wizard/pos_payment_report_user_view.xml',
'wizard/pos_box_out.xml',
'wizard/pos_sales_user.xml',
'wizard/pos_receipt_view.xml',
'wizard/pos_payment_report_user.xml',
'wizard/pos_payment_report.xml',
'wizard/pos_payment.xml',
'wizard/pos_box.xml',
'point_of_sale_report.xml',
'point_of_sale_view.xml',
'report/pos_order_report_view.xml',

View File

@ -27,10 +27,9 @@ class account_journal(osv.osv):
_columns = {
'journal_user': fields.boolean('PoS Payment Method', help="Check this box if this journal define a payment method that can be used in point of sales."),
'opening_control': fields.boolean('Opening Control'),
'closing_control': fields.boolean('Closing Control'),
'opening_control': fields.boolean('Opening Control', help="If you want the journal should be control at opening, check this option"),
'closing_control': fields.boolean('Closing Control', help="If you want the journal should be control at closing, check this option"),
'internal_account_id' : fields.many2one('account.account', 'Internal Transfers Account', select=1),
}
_defaults = {
'opening_control' : True,

View File

@ -14,7 +14,6 @@
<field name="journal_user"/>
<field name="opening_control" />
<field name="closing_control" />
<field name="internal_account_id" />
</group>
</page>
</xpath>

View File

@ -40,9 +40,9 @@ class pos_config(osv.osv):
_columns = {
'name' : fields.char('Name', size=32, select=1, required=True),
'journal_ids' : fields.many2many('account.journal', 'pos_config_journal_rel', 'pos_config_id', 'journal_id', 'Payment Methods'),
'journal_ids' : fields.many2many('account.journal', 'pos_config_journal_rel', 'pos_config_id', 'journal_id', 'Payment Methods', domain="[('journal_user', '=', True )]"),
'shop_id' : fields.many2one('sale.shop', 'Shop', required=True, select=1),
'journal_id' : fields.many2one('account.journal', 'Journal', required=True, select=1),
'journal_id' : fields.many2one('account.journal', 'Journal', required=True, select=1, domain=[('type', '=', 'sale')]),
'profit_account_id' : fields.many2one('account.account', 'Profit Account', required=True, select=1),
'loss_account_id' : fields.many2one('account.account', 'Loss Account', required=True, select=1),
@ -350,6 +350,7 @@ class pos_order(osv.osv):
'partner_id': fields.many2one('res.partner', 'Customer', change_default=True, select=1, states={'draft': [('readonly', False)], 'paid': [('readonly', False)]}),
'session_id' : fields.many2one('pos.session', 'Session',
#required=True,
select=1,
domain="[('state', '=', 'opened')]",
states={'draft' : [('readonly', False)]},
@ -654,7 +655,8 @@ class pos_order(osv.osv):
property_obj=self.pool.get('ir.property')
for order in self.browse(cr, uid, ids, context=context):
if order.state<>'paid': continue
if order.state != 'paid':
continue
curr_c = res_obj.browse(cr, uid, uid).company_id
comp_id = res_obj.browse(cr, order.user_id.id, order.user_id.id).company_id
@ -667,6 +669,7 @@ class pos_order(osv.osv):
# Create an entry for the sale
move_id = account_move_obj.create(cr, uid, {
'ref' : order.name,
'journal_id': order.sale_journal.id,
}, context=context)
@ -714,10 +717,9 @@ class pos_order(osv.osv):
if tax_code_id:
break
# Create a move for the line
account_move_line_obj.create(cr, uid, {
'name': line.name,
'name': line.product_id.name,
'date': order.date_order[:10],
'ref': order.name,
'quantity': line.qty,
@ -746,7 +748,7 @@ class pos_order(osv.osv):
continue
account_move_line_obj.create(cr, uid, {
'name': "Tax" + line.name,
'name': "Tax" + line.name + " (%s)" % (tax.name),
'date': order.date_order[:10],
'ref': order.name,
'product_id':line.product_id.id,
@ -785,7 +787,7 @@ class pos_order(osv.osv):
# counterpart
to_reconcile.append(account_move_line_obj.create(cr, uid, {
'name': order.name,
'name': "Trade Receivables", #order.name,
'date': order.date_order[:10],
'ref': order.name,
'move_id': move_id,
@ -799,6 +801,7 @@ class pos_order(osv.osv):
'period_id': period,
'partner_id': order.partner_id and order.partner_id.id or False
}, context=context))
self.write(cr, uid, order.id, {'state':'done', 'account_move': move_id}, context=context)
return True
@ -806,8 +809,7 @@ class pos_order(osv.osv):
return self.write(cr, uid, ids, {'state': 'payment'}, context=context)
def action_paid(self, cr, uid, ids, context=None):
context = context or {}
self.create_picking(cr, uid, ids, context=None)
self.create_picking(cr, uid, ids, context=context)
self.write(cr, uid, ids, {'state': 'paid'}, context=context)
return True

View File

@ -18,7 +18,7 @@
<field name="arch" type="xml">
<form string="PoS Orders">
<group col="7" colspan="4">
<field name="session_id" />
<field name="session_id" required="1" />
<field name="name"/>
<field name="date_order"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_customer':1}" attrs="{'readonly': [('state','=','invoiced')]}"/>
@ -55,7 +55,7 @@
<separator colspan="4"/>
<group colspan="4" col="8">
<field name="state" widget="statusbar" statusbar_visible="draft,paid,done" statusbar_colors='{"cancel":"red"}'/>
<button name="%(action_pos_payment)d" string="Payment" icon="gtk-apply" type="action" states="draft"/>
<button name="%(action_pos_payment)d" string="Payment" icon="gtk-apply" type="action" states="draft" context="{'pos_session_id' : session_id}"/>
<button name="refund" string="Return Products" type="object" icon="gtk-ok"
attrs="{'invisible':[('state','=','draft')]}"/>
<button name="%(action_report_pos_receipt)d" string="Reprint" icon="gtk-print" type="action" states="paid,done,invoiced"/>
@ -671,16 +671,6 @@
<menuitem name="Configuration" parent="menu_point_root"
id="menu_point_config_product" sequence="25" groups="group_pos_manager"/>
<menuitem
parent="menu_point_of_sale"
action="action_box_entries"
id="menu_wizard_enter_jrnl" sequence="2" />
<menuitem
parent="menu_point_of_sale"
action="action_box_out"
id="menu_wizard_enter_jrnl2" sequence="3" />
<record id="action_account_journal_form" model="ir.actions.act_window">
<field name="name">Payment Methods</field>
<field name="res_model">account.journal</field>
@ -770,7 +760,15 @@
<field name="name" />
<notebook colspan="4">
<page string="Payment Methods">
<field name="journal_ids" colspan="4" nolabel="1"/>
<field name="journal_ids" colspan="4" nolabel="1">
<tree string="Journals">
<field name="code" />
<field name="name" />
<field name="type" />
<field name="opening_control" />
<field name="closing_control" />
</tree>
</field>
</page>
<page string="Accounting">
<separator string="Accounting" colspan="4" />
@ -943,7 +941,16 @@
name="Orders"
src_model="pos.session"
res_model="pos.order"
domain="[('session_id', '=', active_id)]" />
domain="[('session_id', '=', active_id)]" />
<!--
TODO
<act_window
id="act_pos_session_statements"
name="Statements"
src_model="pos.session"
res_model="account.bank.statement"
domain="[]" />
-->
<record id="view_pos_order_filter" model="ir.ui.view">
<field name="name">pos.order.list.select</field>

View File

@ -23,8 +23,6 @@ import pos_confirm
import pos_discount
import pos_open_statement
import pos_close_statement
import pos_box_entries
import pos_box_out
import pos_details
import pos_sales_user
import pos_sales_user_today
@ -33,5 +31,7 @@ import pos_payment_report_user
import pos_payment_report
import pos_payment
import pos_box
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,26 @@
#!/usr/bin/env python
from osv import osv, fields
from account.wizard.pos_box import CashBox
class PosBox(CashBox):
_register = False
def run(self, cr, uid, ids, context=None):
if not context:
context = dict()
active_model = context.get('active_model', False) or False
active_ids = context.get('active_ids', []) or []
if active_model == 'pos.session':
records = self.pool.get(active_model).browse(cr, uid, context.get('active_ids', []) or [], context=context)
return self._run(cr, uid, ids, [record.cash_register_id for record in records], context=context)
else:
return super(PosBox, self).run(cr, uid, ids, context=context)
class PosBoxIn(PosBox):
_inherit = 'cash.box.in'
class PosBoxOut(PosBox):
_inherit = 'cash.box.out'

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<act_window
name="Put Money In"
res_model="cash.box.in"
src_model="pos.session"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_pos_box_in" />
<act_window
name="Take Money Out"
res_model="cash.box.out"
src_model="pos.session"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_pos_box_out" />
</data>
</openerp>

View File

@ -69,16 +69,32 @@ class pos_box_entries(osv.osv_memory):
_columns = {
'name': fields.char('Reason', size=32, required=True),
'journal_id': fields.selection(get_journal, "Cash Register", required=True, size=-1),
#'journal_id': fields.selection(get_journal, "Cash Register", required=True, size=-1),
'journal_id': fields.many2one('account.journal', 'Cash Register', required=True, domain="[('journal_id.type', '=', 'cash')]"),
'product_id': fields.selection(_get_income_product, "Operation", required=True, size=-1),
'amount': fields.float('Amount', digits=(16, 2), required=True),
'ref': fields.char('Ref', size=32),
'session_id' : fields.many2one('pos.session', 'Session'),
'user_id' : fields.many2one('res.users', 'User'),
}
def _default_session_id(self, cr, uid, context=None):
return context and context.get('active_id', False) or False
def _default_cash_register(self, cr, uid, context=None):
#import pdb
#pdb.set_trace()
if not context:
context = {}
result = context.get('active_id', False) or False
return result
_defaults = {
'journal_id': 1,
'product_id': 1,
#'session_id' : _default_session_id,
#'journal_id': _default_cash_register,
#'product_id': 1,
'user_id' : lambda obj, cr, uid, context: uid,
}

View File

@ -26,6 +26,23 @@ from tools.translate import _
import pos_box_entries
import netsvc
class account_journal(osv.osv):
_inherit = 'account.journal'
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if not context:
context = {}
session_id = context.get('pos_session_id', False) or False
if session_id:
session = self.pool.get('pos.session').browse(cr, uid, session_id, context=context)
if session:
journal_ids = [journal.id for journal in session.config_id.journal_ids]
args += [('id', 'in', journal_ids)]
return super(account_journal, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
class pos_make_payment(osv.osv_memory):
_name = 'pos.make.payment'
@ -90,7 +107,8 @@ class pos_make_payment(osv.osv_memory):
return False
_columns = {
'journal': fields.selection(pos_box_entries.get_journal, "Payment Mode", required=True),
#'journal': fields.selection(pos_box_entries.get_journal, "Payment Mode", required=True),
'journal_id' : fields.many2one('account.journal', 'Payment Mode', required=True),
'amount': fields.float('Amount', digits=(16,2), required= True),
'payment_name': fields.char('Payment Reference', size=32),
'payment_date': fields.date('Payment Date', required=True),
@ -98,7 +116,7 @@ class pos_make_payment(osv.osv_memory):
_defaults = {
'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'),
'amount': _default_amount,
'journal': _default_journal
#'journal': _default_journal
}
pos_make_payment()

View File

@ -10,7 +10,8 @@
<form string="Add payment :">
<group colspan="4" col="4" >
<group colspan="4">
<field name="journal"/>
<!--<field name="journal"/>-->
<field name="journal_id" />
<field name="amount" />
<field name="payment_name"/>
</group>