2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2008 PC Solutions (<http://pcsol.be>). All Rights Reserved
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ##############################################################################
25 from osv import osv, fields
26 from tools.translate import _
27 import decimal_precision as dp
29 class account_cashbox_line(osv.osv):
31 """ Cash Box Details """
33 _name = 'account.cashbox.line'
34 _description = 'CashBox Line'
36 def _sub_total(self, cr, uid, ids, name, arg, context=None):
38 """ Calculates Sub total
39 @param name: Names of fields.
40 @param arg: User defined arguments
41 @return: Dictionary of values.
44 for obj in self.browse(cr, uid, ids):
45 res[obj.id] = obj.pieces * obj.number
48 def on_change_sub(self, cr, uid, ids, pieces, number, *a):
50 """ Calculates Sub total on change of number
51 @param pieces: Names of fields.
55 return {'value': {'subtotal': sub or 0.0}}
58 'pieces': fields.float('Values', digits_compute=dp.get_precision('Account')),
59 'number': fields.integer('Number'),
60 'subtotal': fields.function(_sub_total, method=True, string='Sub Total', type='float', digits_compute=dp.get_precision('Account')),
61 'starting_id': fields.many2one('account.bank.statement', ondelete='cascade'),
62 'ending_id': fields.many2one('account.bank.statement', ondelete='cascade'),
65 account_cashbox_line()
67 class account_cash_statement(osv.osv):
69 _inherit = 'account.bank.statement'
71 def _get_starting_balance(self, cr, uid, ids, context=None):
73 """ Find starting balance
74 @param name: Names of fields.
75 @param arg: User defined arguments
76 @return: Dictionary of values.
79 for statement in self.browse(cr, uid, ids):
82 if statement.journal_id.type not in('cash'):
85 for line in statement.starting_details_ids:
86 amount_total+= line.pieces * line.number
88 'balance_start': amount_total
92 def _balance_end_cash(self, cr, uid, ids, name, arg, context=None):
93 """ Find ending balance "
94 @param name: Names of fields.
95 @param arg: User defined arguments
96 @return: Dictionary of values.
99 for statement in self.browse(cr, uid, ids):
101 for line in statement.ending_details_ids:
102 amount_total += line.pieces * line.number
103 res[statement.id] = amount_total
106 def _get_sum_entry_encoding(self, cr, uid, ids, name, arg, context=None):
108 """ Find encoding total of statements "
109 @param name: Names of fields.
110 @param arg: User defined arguments
111 @return: Dictionary of values.
114 for statement in self.browse(cr, uid, ids):
116 for line in statement.line_ids:
117 encoding_total += line.amount
118 res2[statement.id] = encoding_total
121 def _end_balance(self, cursor, user, ids, name, attr, context=None):
122 res_currency_obj = self.pool.get('res.currency')
123 res_users_obj = self.pool.get('res.users')
126 company_currency_id = res_users_obj.browse(cursor, user, user,
127 context=context).company_id.currency_id.id
129 statements = self.browse(cursor, user, ids, context=context)
130 for statement in statements:
131 res[statement.id] = statement.balance_start
132 currency_id = statement.currency.id
133 for line in statement.move_line_ids:
135 if line.account_id.id == \
136 statement.journal_id.default_debit_account_id.id:
137 res[statement.id] += res_currency_obj.compute(cursor,
138 user, company_currency_id, currency_id,
139 line.debit, context=context)
141 if line.account_id.id == \
142 statement.journal_id.default_credit_account_id.id:
143 res[statement.id] -= res_currency_obj.compute(cursor,
144 user, company_currency_id, currency_id,
145 line.credit, context=context)
147 if statement.state in ('draft', 'open'):
148 for line in statement.line_ids:
149 res[statement.id] += line.amount
151 res[r] = round(res[r], 2)
154 def _get_company(self, cr, uid, context=None):
155 user_pool = self.pool.get('res.users')
156 company_pool = self.pool.get('res.company')
157 user = user_pool.browse(cr, uid, uid, context=context)
158 company_id = user.company_id
160 company_id = company_pool.search(cr, uid, [])
161 return company_id and company_id[0] or False
163 def _get_cash_open_box_lines(self, cr, uid, context={}):
165 curr = [1, 2, 5, 10, 20, 50, 100, 500]
172 journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'cash')], context=context)
174 results = self.search(cr, uid, [('journal_id', 'in', journal_ids),('state', '=', 'confirm')], context=context)
176 cash_st = self.browse(cr, uid, results, context)[0]
177 for cash_line in cash_st.ending_details_ids:
179 if cash_line.pieces == r['pieces']:
180 r['number'] = cash_line.number
183 def _get_default_cash_close_box_lines(self, cr, uid, context={}):
185 curr = [1, 2, 5, 10, 20, 50, 100, 500]
194 def _get_cash_close_box_lines(self, cr, uid, context={}):
196 curr = [1, 2, 5, 10, 20, 50, 100, 500]
202 res.append((0, 0, dct))
205 def _get_cash_open_close_box_lines(self, cr, uid, context={}):
209 starting_details = self._get_cash_open_box_lines(cr, uid, context)
210 ending_details = self._get_default_cash_close_box_lines(cr, uid, context)
211 for start in starting_details:
212 start_l.append((0, 0, start))
213 for end in ending_details:
214 end_l.append((0, 0, end))
215 res['start'] = start_l
220 'balance_end_real': fields.float('Closing Balance', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}, help="closing balance entered by the cashbox verifier"),
221 'state': fields.selection(
223 ('confirm', 'Closed'),
224 ('open','Open')], 'State', required=True, states={'confirm': [('readonly', True)]}, readonly="1"),
225 'total_entry_encoding': fields.function(_get_sum_entry_encoding, method=True, store=True, string="Cash Transaction", help="Total cash transactions"),
226 'closing_date': fields.datetime("Closed On"),
227 'balance_end': fields.function(_end_balance, method=True, store=True, string='Balance', help="Closing balance based on Starting Balance and Cash Transactions"),
228 'balance_end_cash': fields.function(_balance_end_cash, method=True, store=True, string='Balance', help="Closing balance based on cashBox"),
229 'starting_details_ids': fields.one2many('account.cashbox.line', 'starting_id', string='Opening Cashbox'),
230 'ending_details_ids': fields.one2many('account.cashbox.line', 'ending_id', string='Closing Cashbox'),
231 'name': fields.char('Name', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'),
232 'user_id': fields.many2one('res.users', 'Responsible', required=False),
236 'date': time.strftime("%Y-%m-%d %H:%M:%S"),
237 'user_id': lambda self, cr, uid, context=None: uid,
238 'starting_details_ids': _get_cash_open_box_lines,
239 'ending_details_ids': _get_default_cash_close_box_lines
242 def create(self, cr, uid, vals, context=None):
243 if 'journal_id' not in vals:
244 raise osv.except_osv('Error', _('You cannot create a bank or cash register without a journal!'))
246 ('journal_id', '=', vals.get('journal_id', False)),
247 ('state', '=', 'open')
249 open_jrnl = self.search(cr, uid, sql)
251 raise osv.except_osv('Error', _('You can not have two open register for the same journal'))
253 if self.pool.get('account.journal').browse(cr, uid, vals['journal_id']).type == 'cash':
254 open_close = self._get_cash_open_close_box_lines(cr, uid, context)
255 if vals.get('starting_details_ids', False):
256 for start in vals.get('starting_details_ids'):
258 for end in open_close['end']:
259 if end[2]['pieces'] == dict_val['pieces']:
260 end[2]['number'] += dict_val['number']
262 # 'ending_details_ids': open_close['start'],
263 'starting_details_ids': open_close['end']
267 'ending_details_ids': False,
268 'starting_details_ids': False
270 res_id = super(account_cash_statement, self).create(cr, uid, vals, context=context)
271 self.write(cr, uid, [res_id], {})
274 def write(self, cr, uid, ids, vals, context=None):
276 Update redord(s) comes in {ids}, with new value comes as {vals}
277 return True on success, False otherwise
279 @param cr: cursor to database
280 @param user: id of current user
281 @param ids: list of record ids to be update
282 @param vals: dict of new values to be set
283 @param context: context arguments, like lang, time zone
285 @return: True on success, False otherwise
288 super(account_cash_statement, self).write(cr, uid, ids, vals)
289 res = self._get_starting_balance(cr, uid, ids)
291 super(account_cash_statement, self).write(cr, uid, [rs], res.get(rs))
294 def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
295 """ Changes balance start and starting details if journal_id changes"
296 @param statement_id: Changed statement_id
297 @param journal_id: Changed journal_id
298 @return: Dictionary of changed values
305 'balance_start': balance_start
308 return super(account_cash_statement, self).onchange_journal_id(cr, uid, statement_id, journal_id, context=context)
310 def _equal_balance(self, cr, uid, cash_id, context=None):
311 statement = self.browse(cr, uid, cash_id, context=context)
312 self.write(cr, uid, [cash_id], {'balance_end_real': statement.balance_end})
313 statement.balance_end_real = statement.balance_end
314 if statement.balance_end != statement.balance_end_cash:
319 def _user_allow(self, cr, uid, statement_id, context=None):
322 def button_open(self, cr, uid, ids, context=None):
323 """ Changes statement state to Running.
328 statement_pool = self.pool.get('account.bank.statement')
329 for statement in statement_pool.browse(cr, uid, ids, context=context):
331 if not self._user_allow(cr, uid, statement.id, context=context):
332 raise osv.except_osv(_('Error !'), _('User %s does not have rights to access %s journal !' % (statement.user_id.name, statement.journal_id.name)))
334 if statement.name and statement.name == '/':
335 number = self.pool.get('ir.sequence').get(cr, uid, 'account.cash.statement')
341 'date': time.strftime("%Y-%m-%d %H:%M:%S"),
345 self.write(cr, uid, [statement.id], vals)
348 def balance_check(self, cr, uid, cash_id, journal_type='bank', context=None):
349 if journal_type == 'bank':
350 return super(account_cash_statement, self).balance_check(cr, uid, cash_id, journal_type, context)
351 if not self._equal_balance(cr, uid, cash_id, context):
352 raise osv.except_osv(_('Error !'), _('CashBox Balance is not matching with Calculated Balance !'))
355 def statement_close(self, cr, uid, ids, journal_type='bank', context=None):
356 if journal_type == 'bank':
357 return super(account_cash_statement, self).statement_close(cr, uid, ids, journal_type, context)
360 'closing_date': time.strftime("%Y-%m-%d %H:%M:%S")
362 return self.write(cr, uid, ids, vals, context=context)
364 def check_status_condition(self, cr, uid, state, journal_type='bank'):
365 if journal_type == 'bank':
366 return super(account_cash_statement, self).check_status_condition(cr, uid, state, journal_type)
369 def button_confirm_cash(self, cr, uid, ids, context=None):
370 super(account_cash_statement, self).button_confirm_bank(cr, uid, ids, context=context)
371 return self.write(cr, uid, ids, {'closing_date': time.strftime("%Y-%m-%d %H:%M:%S")}, context=context)
373 def button_cancel(self, cr, uid, ids, context=None):
374 cash_box_line_pool = self.pool.get('account.cashbox.line')
375 super(account_cash_statement, self).button_cancel(cr, uid, ids, context=context)
376 for st in self.browse(cr, uid, ids, context):
377 for end in st.ending_details_ids:
378 cash_box_line_pool.write(cr, uid, [end.id], {'number': 0})
381 account_cash_statement()
383 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: