[MERGE] point_of_sale: merging pos backend updates from fp

bzr revid: fva@openerp.com-20120514140751-mqmhjf9oejyub3x5
This commit is contained in:
Frédéric van der Essen 2012-05-14 16:07:51 +02:00
commit e4b1260ace
33 changed files with 745 additions and 980 deletions

View File

@ -716,6 +716,7 @@ class account_journal(osv.osv):
_name = "account.journal"
_description = "Journal"
_columns = {
'with_last_closing_balance' : fields.boolean('Opening With Last Closing Balance'),
'name': fields.char('Journal Name', size=64, required=True),
'code': fields.char('Code', size=5, required=True, help="The code will be displayed on reports."),
'type': fields.selection([('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Cheques'), ('general', 'General'), ('situation', 'Opening/Closing Situation')], 'Type', size=32, required=True,
@ -746,6 +747,7 @@ class account_journal(osv.osv):
}
_defaults = {
'with_last_closing_balance' : False,
'user_id': lambda self, cr, uid, context: uid,
'company_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
}

View File

@ -53,36 +53,11 @@ class account_bank_statement(osv.osv):
return False
def _end_balance(self, cursor, user, ids, name, attr, context=None):
res_currency_obj = self.pool.get('res.currency')
res_users_obj = self.pool.get('res.users')
res = {}
company_currency_id = res_users_obj.browse(cursor, user, user,
context=context).company_id.currency_id.id
statements = self.browse(cursor, user, ids, context=context)
for statement in statements:
for statement in self.browse(cursor, user, ids, context=context):
res[statement.id] = statement.balance_start
currency_id = statement.currency.id
for line in statement.move_line_ids:
if line.debit > 0:
if line.account_id.id == \
statement.journal_id.default_debit_account_id.id:
res[statement.id] += res_currency_obj.compute(cursor,
user, company_currency_id, currency_id,
line.debit, context=context)
else:
if line.account_id.id == \
statement.journal_id.default_credit_account_id.id:
res[statement.id] -= res_currency_obj.compute(cursor,
user, company_currency_id, currency_id,
line.credit, context=context)
if statement.state in ('draft', 'open'):
for line in statement.line_ids:
res[statement.id] += line.amount
for r in res:
res[r] = round(res[r], 2)
for line in statement.line_ids:
res[statement.id] += line.amount
return res
def _get_period(self, cr, uid, context=None):
@ -122,7 +97,7 @@ class account_bank_statement(osv.osv):
_description = "Bank Statement"
_columns = {
'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'), # readonly for account_cash_statement
'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True),
'date': fields.date('Creation Date', required=True, states={'confirm': [('readonly', True)]}, select=True),
'journal_id': fields.many2one('account.journal', 'Journal', required=True,
readonly=True, states={'draft':[('readonly',False)]}),
'period_id': fields.many2one('account.period', 'Period', required=True,
@ -133,7 +108,7 @@ class account_bank_statement(osv.osv):
states={'confirm': [('readonly', True)]}),
'balance_end': fields.function(_end_balance,
store = {
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids'], 10),
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids','balance_start'], 10),
'account.bank.statement.line': (_get_statement, ['amount'], 10),
},
string="Computed Balance", help='Balance as calculated based on Starting Balance and transaction lines'),
@ -303,7 +278,7 @@ class account_bank_statement(osv.osv):
def balance_check(self, cr, uid, st_id, journal_type='bank', context=None):
st = self.browse(cr, uid, st_id, context=context)
if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_cash) < 0.0001)):
if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001)):
raise osv.except_osv(_('Error !'),
_('The statement balance is incorrect !\nThe expected balance (%.2f) is different than the computed one. (%.2f)') % (st.balance_end_real, st.balance_end))
return True
@ -374,15 +349,11 @@ class account_bank_statement(osv.osv):
return self.write(cr, uid, done, {'state':'draft'}, context=context)
def _compute_balance_end_real(self, cr, uid, journal_id, context=None):
cr.execute('SELECT balance_end_real \
FROM account_bank_statement \
WHERE journal_id = %s AND NOT state = %s \
ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft'))
res = cr.fetchone()
print "res: %r" % (res,)
return res and res[0] or 0.0
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):

View File

@ -61,8 +61,8 @@ class account_cashbox_line(osv.osv):
'pieces': fields.float('Unit of Currency', digits_compute=dp.get_precision('Account')),
'number_opening' : fields.integer('Number of Units', help='Opening Unit Numbers'),
'number_closing' : fields.integer('Number of Units', help='Closing Unit Numbers'),
'subtotal_opening': fields.function(_sub_total, string='Subtotal Opening', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
'subtotal_closing': fields.function(_sub_total, string='Subtotal Closing', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
'subtotal_opening': fields.function(_sub_total, string='Opening Subtotal', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
'subtotal_closing': fields.function(_sub_total, string='Closing Subtotal', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
'bank_statement_id' : fields.many2one('account.bank.statement', ondelete='cascade'),
}
@ -72,36 +72,24 @@ class account_cash_statement(osv.osv):
_inherit = 'account.bank.statement'
def _get_starting_balance(self, cr, uid, ids, context=None):
""" Find starting balance
@param name: Names of fields.
@param arg: User defined arguments
@return: Dictionary of values.
def _update_balances(self, cr, uid, ids, context=None):
"""
Set starting and ending balances according to pieces count
"""
res = {}
for statement in self.browse(cr, uid, ids, context=context):
if statement.journal_id.type not in('cash'):
if statement.journal_id.type not in ('cash',):
continue
res[statement.id] = {
'balance_start': sum((line.pieces * line.number_opening
for line in statement.details_ids), 0.0)
start = end = 0
for line in statement.details_ids:
start += line.subtotal_opening
end += line.subtotal_closing
data = {
'balance_start': start,
'balance_end_real': end,
}
print "_get_starting_balance: %r" % (res,)
return res
def _balance_end_cash(self, cr, uid, ids, name, arg, context=None):
""" Find ending balance "
@param name: Names of fields.
@param arg: User defined arguments
@return: Dictionary of values.
"""
res = {}
for statement in self.browse(cr, uid, ids, context=context):
res[statement.id] = sum((line.pieces * line.number_closing
for line in statement.details_ids), 0.0)
print "_balance_end_cash: %r" % (res,)
res[statement.id] = data
super(account_cash_statement, self).write(cr, uid, [statement.id], data, context=context)
return res
def _get_sum_entry_encoding(self, cr, uid, ids, name, arg, context=None):
@ -114,7 +102,6 @@ class account_cash_statement(osv.osv):
res = {}
for statement in self.browse(cr, uid, ids, context=context):
res[statement.id] = sum((line.amount for line in statement.line_ids), 0.0)
print "_get_sum_entry_encoding: %r" % (res,)
return res
def _get_company(self, cr, uid, context=None):
@ -126,63 +113,7 @@ class account_cash_statement(osv.osv):
company_id = company_pool.search(cr, uid, [])
return company_id and company_id[0] or False
def _get_cash_open_box_lines(self, cr, uid, context=None):
res = []
curr = [1, 2, 5, 10, 20, 50, 100, 500]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append(dct)
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'cash')], context=context)
if journal_ids:
results = self.search(cr, uid, [('journal_id', 'in', journal_ids),('state', '=', 'confirm')], context=context)
if results:
cash_st = self.browse(cr, uid, results, context=context)[0]
for cash_line in cash_st.ending_details_ids:
for r in res:
if cash_line.pieces == r['pieces']:
r['number'] = cash_line.number
return res
def _get_default_cash_close_box_lines(self, cr, uid, context=None):
res = []
curr = [1, 2, 5, 10, 20, 50, 100, 500]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append(dct)
return res
def _get_cash_close_box_lines(self, cr, uid, context=None):
res = []
curr = [1, 2, 5, 10, 20, 50, 100, 500]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append((0, 0, dct))
return res
def _get_cash_open_close_box_lines(self, cr, uid, context=None):
res = {}
start_l = []
end_l = []
starting_details = self._get_cash_open_box_lines(cr, uid, context=context)
ending_details = self._get_default_cash_close_box_lines(cr, uid, context)
for start in starting_details:
start_l.append((0, 0, start))
for end in ending_details:
end_l.append((0, 0, end))
res['start'] = start_l
res['end'] = end_l
return res
def _get_statement(self, cr, uid, ids, context=None):
def _get_statement_from_line(self, cr, uid, ids, context=None):
result = {}
for line in self.pool.get('account.bank.statement.line').browse(cr, uid, ids, context=context):
result[line.statement_id.id] = True
@ -192,81 +123,46 @@ class account_cash_statement(osv.osv):
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
result[obj.id] = obj.balance_end_real - obj.balance_end
return result
_columns = {
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Cash Transaction", help="Total cash transactions",
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Cash Transactions",
store = {
'account.bank.statement': (lambda self, cr, uid, ids, context=None: ids, ['line_ids','move_line_ids'], 10),
'account.bank.statement.line': (_get_statement, ['amount'], 10),
'account.bank.statement.line': (_get_statement_from_line, ['amount'], 10),
}),
'closing_date': fields.datetime("Closed On"),
'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'),
'opening_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Opening Cashbox Lines'),
'closing_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Closing Cashbox Lines'),
'user_id': fields.many2one('res.users', 'Responsible', required=False),
'difference' : fields.function(_compute_difference, method=True, string="Difference", type="float"),
}
_defaults = {
'state': 'draft',
'date': lambda self, cr, uid, context={}: context.get('date', time.strftime("%Y-%m-%d %H:%M:%S")),
'user_id': lambda self, cr, uid, context=None: uid,
}
def check_opening_journal(self, cr, uid, ids, context=None):
"""
This constraint will check than the journal is not used twice in the system,
to avoid a concurrency opening of this journal.
"""
for cash in self.browse(cr, uid, ids, context=None):
domain = [
('id', '!=', cash.id),
('journal_id', '=', cash.journal_id.id),
('journal_id.type', '=', 'cash'),
('state', 'in', ('open',)),
]
count = self.search_count(cr, uid, domain, context=context)
if count:
return False
return True
_constraints = [
#(check_opening_journal, "The selected journal has been opened !", ['journal_id']),
]
def create(self, cr, uid, vals, context=None):
if self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context).type == 'cash':
amount_total = 0.0
for line in vals.get('details_ids',[]):
print "line: %r" % (line,)
if line and len(line)==3 and line[2]:
# FIXME: If there is no piece # does not work with GTK
amount_total+= line[2].get('pieces', 0) * line[2]['number_opening']
journal = False
if vals.get('journal_id'):
journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context)
if journal and (journal.type == 'cash') and not vals.get('details_ids'):
vals['details_ids'] = []
for value in journal.cashbox_line_ids:
nested_values = {
'number_closing' : 0,
'number_opening' : 0,
'pieces' : value.pieces
}
vals['details_ids'].append([0, False, nested_values])
vals.update(balance_start= amount_total)
vals.update(balance_end_real=self._compute_balance_end_real(cr, uid, vals['journal_id'], context=context))
details = vals.get('details_ids')
if not details:
result = self.onchange_journal_id(cr, uid, None, vals['journal_id'], context=context)
vals['details_ids'] = []
for value in (result['value']['details_ids'] or []):
print "value: %r" % (value,)
nested_values = {
'number_closing' : False,
'number_opening' : False,
'pieces' : value['pieces'],
'subtotal_closing' : False,
'subtotal_opening' : False,
}
vals['details_ids'].append([0, False, nested_values])
return super(account_cash_statement, self).create(cr, uid, vals, context=context)
res_id = super(account_cash_statement, self).create(cr, uid, vals, context=context)
self._update_balances(cr, uid, [res_id], context)
return res_id
def write(self, cr, uid, ids, vals, context=None):
"""
@ -282,58 +178,9 @@ class account_cash_statement(osv.osv):
@return: True on success, False otherwise
"""
super(account_cash_statement, self).write(cr, uid, ids, vals, context=context)
res = self._get_starting_balance(cr, uid, ids)
for rs in res:
super(account_cash_statement, self).write(cr, uid, [rs], res.get(rs))
return True
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
""" Changes balance start and starting details if journal_id changes"
@param statement_id: Changed statement_id
@param journal_id: Changed journal_id
@return: Dictionary of changed values
"""
balance_start = 0.0
if journal_id:
count = self.search_count(cr, uid, [('journal_id', '=', journal_id),('state', '=', 'open')], context=None)
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:
values = super(account_cash_statement, self).onchange_journal_id(cr, uid, statement_id, journal_id, context=context)
proxy_line = self.pool.get('account.cashbox.line')
values.setdefault('value', {})
values['value']['details_ids'] = []
values['value']['balance_end_real'] = self._compute_balance_end_real(cr, uid, journal_id, context=context)
values['value']['balance_start'] = 0.0
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
for line in journal.cashbox_line_ids:
values['value']['details_ids'].append({'pieces' : line.pieces})
return values
else:
return {
'value' : {
'balance_start': balance_start,
'details_ids' : [],
}
}
return super(account_cash_statement, self).onchange_journal_id(cr, uid, statement_id, journal_id, context=context)
def _equal_balance(self, cr, uid, cash_id, context=None):
statement = self.browse(cr, uid, cash_id, context=context)
self.write(cr, uid, [cash_id], {'balance_end_real': statement.balance_end})
print "balance_end_real: %r" % (statement.balance_end,)
print "balance_end: %r" % (statement.balance_end,)
print "balance_end_cash: %r" % (statement.balance_end_cash,)
if statement.balance_end != statement.balance_end_cash:
return False
return True
res = super(account_cash_statement, self).write(cr, uid, ids, vals, context=context)
self._update_balances(cr, uid, ids, context)
return res
def _user_allow(self, cr, uid, statement_id, context=None):
return True
@ -349,7 +196,7 @@ class account_cash_statement(osv.osv):
for statement in statement_pool.browse(cr, uid, ids, context=context):
vals = {}
if not self._user_allow(cr, uid, statement.id, context=context):
raise osv.except_osv(_('Error !'), (_('User %s does not have rights to access %s journal !') % (statement.user_id.name, statement.journal_id.name)))
raise osv.except_osv(_('Error !'), (_('You do not have rights to open this %s journal !') % (statement.journal_id.name, )))
if statement.name and statement.name == '/':
c = {'fiscalyear_id': statement.period_id.fiscalyear_id.id}
@ -367,13 +214,6 @@ class account_cash_statement(osv.osv):
self.write(cr, uid, [statement.id], vals, context=context)
return True
def balance_check(self, cr, uid, cash_id, journal_type='bank', context=None):
if journal_type == 'bank':
return super(account_cash_statement, self).balance_check(cr, uid, cash_id, journal_type, context)
if not self._equal_balance(cr, uid, cash_id, context):
raise osv.except_osv(_('Error !'), _('The closing balance should be the same than the computed balance!'))
return True
def statement_close(self, cr, uid, ids, journal_type='bank', context=None):
if journal_type == 'bank':
return super(account_cash_statement, self).statement_close(cr, uid, ids, journal_type, context)
@ -419,14 +259,6 @@ class account_cash_statement(osv.osv):
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):
cash_box_line_pool = self.pool.get('account.cashbox.line')
super(account_cash_statement, self).button_cancel(cr, uid, ids, context=context)
for st in self.browse(cr, uid, ids, context):
for end in st.details_ids:
cash_box_line_pool.write(cr, uid, [end.id], {'number_closing': 0})
return True
account_cash_statement()
class account_journal(osv.osv):

View File

@ -32,7 +32,7 @@
</field>
<separator colspan="4" string="States"/>
<group>
<field name="state" select="1" readonly="1"/>
<field name="state" readonly="1"/>
<button name="create_period" states="draft" string="Create Monthly Periods" type="object" icon="terp-document-new"/>
<button name="create_period3" states="draft" string="Create 3 Months Periods" type="object" icon="terp-document-new"/>
</group>
@ -162,13 +162,13 @@
<field name="arch" type="xml">
<form string="Account">
<group col="6" colspan="4">
<field name="name" select="1"/>
<field name="code" select="1"/>
<field name="name"/>
<field name="code" />
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
<newline/>
<field name="parent_id"/>
<field name="type" select="1"/>
<field name="user_type" select="1"/>
<field name="type"/>
<field name="user_type"/>
<field name="active"/>
<newline/>
<field name="debit" invisible="context.get('config_invisible', True)" attrs="{'readonly':[('type','=','view')]}"/>
@ -345,8 +345,8 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Journal Column">
<field colspan="4" name="name" select="1"/>
<field name="field" select="1"/>
<field colspan="4" name="name"/>
<field name="field"/>
<field name="sequence"/>
</form>
</field>
@ -455,8 +455,8 @@
<field name="arch" type="xml">
<form string="Account Journal">
<group colspan="4" col="6">
<field name="name" select="1"/>
<field name="code" select="1"/>
<field name="name"/>
<field name="code"/>
<field name="type" on_change="onchange_type(type, currency, context)"/>
</group>
<notebook colspan="4">
@ -487,6 +487,7 @@
<separator string="Other Configuration" colspan="4"/>
<field name="centralisation"/>
<field name="entry_posted"/>
<field name="with_last_closing_balance" />
</group>
<group colspan="2" col="2">
<separator string="Invoicing Data" colspan="4"/>
@ -504,18 +505,19 @@
<separator colspan="4" string="Accounts Allowed (empty for no control)"/>
<field colspan="4" name="account_control_ids" nolabel="1"/>
</page>
<page string="Cash Box">
<page string="Cash">
<separator string="Profit &amp; Loss Accounts" colspan="4" />
<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" />
<separator string="Available Currencies" 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>
@ -607,9 +609,9 @@
<field name="arch" type="xml">
<form string="Bank Statement">
<group col="7" colspan="4">
<field name="name" select="1"/>
<field name="date" select="1" on_change="onchange_date(date, company_id)"/>
<field name="journal_id" domain="[('type', '=', 'bank')]" on_change="onchange_journal_id(journal_id)" select="1" widget="selection"/>
<field name="name"/>
<field name="date" on_change="onchange_date(date, company_id)"/>
<field name="journal_id" domain="[('type', '=', 'bank')]" on_change="onchange_journal_id(journal_id)" widget="selection"/>
<newline/>
<field name="period_id"/>
<field name="balance_start"/>
@ -668,8 +670,8 @@
<field name="arch" type="xml">
<form string="Bank Statement">
<group col="7" colspan="4">
<field name="name" select="1"/>
<field name="date" select="1" on_change="onchange_date(date, company_id)"/>
<field name="name"/>
<field name="date" on_change="onchange_date(date, company_id)"/>
<field name='company_id' widget="selection" groups="base.group_multi_company" />
<field name="journal_id" domain="[('type', '=', 'bank')]" on_change="onchange_journal_id(journal_id)" widget="selection"/>
<newline/>
@ -799,12 +801,12 @@
<field name="arch" type="xml">
<form string="Account Type">
<group col="6" colspan="4">
<field name="name" select="1"/>
<field name="code" select="1"/>
<field name="name"/>
<field name="code"/>
</group>
<group col="2" colspan="2">
<separator string="Reporting Configuration" colspan="4"/>
<field name="report_type" select="2"/>
<field name="report_type"/>
</group>
<group col="2" colspan="2">
<separator string="Closing Method" colspan="4"/>
@ -856,9 +858,9 @@
<field name="arch" type="xml">
<form string="Journal Entry Reconcile">
<group col="6" colspan="4">
<field name="name" select="1"/>
<field name="create_date" select="1"/>
<field name="type" select="1"/>
<field name="name"/>
<field name="create_date"/>
<field name="type"/>
</group>
<separator colspan="4" string="Reconcile Entries"/>
<field colspan="4" name="line_id" nolabel="1"/>
@ -1094,9 +1096,9 @@
<field name="arch" type="xml">
<form string="Journal Item">
<group col="6" colspan="4">
<field name="name" select="1"/>
<field name="name"/>
<field name="ref"/>
<field name="partner_id" select="1" on_change="onchange_partner_id(False,partner_id,account_id,debit,credit,date)"/>
<field name="partner_id" on_change="onchange_partner_id(False,partner_id,account_id,debit,credit,date)"/>
<field name="journal_id"/>
<field name="period_id"/>
@ -1106,7 +1108,7 @@
<page string="Information">
<group col="2" colspan="2">
<separator colspan="2" string="Amount"/>
<field name="account_id" select="1" domain="[('company_id', '=', company_id), ('type','&lt;&gt;','view'), ('type','&lt;&gt;','consolidation')]"/>
<field name="account_id" domain="[('company_id', '=', company_id), ('type','&lt;&gt;','view'), ('type','&lt;&gt;','consolidation')]"/>
<field name="debit"/>
<field name="credit"/>
<field name="quantity"/>
@ -1121,7 +1123,7 @@
<group col="2" colspan="2">
<separator colspan="2" string="Dates"/>
<field name="date" select="1"/>
<field name="date"/>
<field name="date_maturity"/>
<field name="date_created" readonly="True"/>
</group>
@ -1176,11 +1178,11 @@
<notebook colspan="4">
<page string="Information">
<separator colspan="4" string="General Information"/>
<field name="name" select="1"/>
<field name="name"/>
<field name="date"/>
<field name="journal_id" readonly="False" select="1"/>
<field name="journal_id" readonly="False"/>
<field name="period_id" readonly="False"/>
<field name="account_id" select="1" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation'),('company_id', '=', company_id)]"/>
<field name="account_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation'),('company_id', '=', company_id)]"/>
<field name="partner_id" on_change="onchange_partner_id(False,partner_id,account_id,debit,credit,date)"/>
<newline/>
<field name="debit"/>
@ -1189,13 +1191,13 @@
<separator colspan="4" string="Optional Information"/>
<field name="currency_id"/>
<field name="amount_currency"/>
<field name="quantity" select="3"/>
<field name="quantity"/>
<field name="move_id" required="False"/>
<newline/>
<field name="date_maturity"/>
<field name="date_created"/>
<field name="date_created"/>
<field name="blocked" select="3"/>
<field name="blocked"/>
<newline/>
<field name="account_tax_id" domain="[('parent_id','=',False)]"/>
<field name="analytic_account_id" domain="[('parent_id','!=',False)]" groups="analytic.group_analytic_accounting"/>
@ -2624,9 +2626,18 @@ action = pool.get('res.config').next(cr, uid, [], context)
<field name="model">account.bank.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Statement">
<form string="Statement" layout="manual">
<div class="oe_form_topbar">
<button name="button_cancel" states="confirm,open" string="Cancel" icon="terp-gtk-stop" type="object"/>
<button name="button_confirm_cash" states="open" string="Close CashBox" icon="terp-dialog-close" type="object"/>
<button name="button_open" states="draft" string="Open CashBox" icon="gtk-go-forward" type="object"/>
<div class="oe_right">
<field name="state" widget="statusbar" statusbar_visible="draft,open,confirm" nolabel="1"/>
</div>
</div>
<sheet layout="auto">
<group col="6" colspan="4">
<field name="name" select="1"/>
<field name="name"/>
<field name='company_id' widget="selection" groups="base.group_multi_company" />
<field name="journal_id" on_change="onchange_journal_id(journal_id)" select="1" widget="selection" domain="[('type', '=', 'cash')]"/>
<field name="user_id" select="1" readonly="1"/>
@ -2663,15 +2674,22 @@ action = pool.get('res.config').next(cr, uid, [], context)
</form>
</field>
</page>
<page string="CashBox">
<page string="Cash Control">
<group col="2" expand="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)" attrs="{'readonly' : [('parent.state', '!=', 'open')]}" />
<field name="opening_details_ids" nolabel="1" colspan="4" attrs="{'invisible' : [('state', '!=', 'draft')]}">
<tree string="Opening Cashbox Lines" editable="bottom">
<field name="pieces"/>
<field name="number_opening" string="Opening Unit Numbers" on_change="on_change_sub_opening(pieces, number_opening, parent.balance_end)"/>
<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)" attrs="{'readonly' : [('parent.state', '!=', 'confirm')]}"/>
</tree>
</field>
<field name="closing_details_ids" nolabel="1" colspan="4" attrs="{'invisible' : [('state', '=', 'draft')]}">
<tree string="Closing Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_opening" string="Opening Unit Numbers" readonly="1" />
<field name="subtotal_opening" string="Opening Subtotal" readonly="1" />
<field name="number_closing" string="Closing Unit Numbers" on_change="on_change_sub_closing(pieces, number_closing, parent.balance_end)"/>
<field name="subtotal_closing" string="Closing Subtotal"/>
</tree>
</field>
@ -2682,30 +2700,23 @@ action = pool.get('res.config').next(cr, uid, [], context)
</page>
</notebook>
<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)" string="Started On" />
<field name="closing_date" select="1" readonly="1"/>
</group>
<group col="2" colspan="2">
<separator string="Opening Balance" colspan="4"/>
<field name="balance_end_real" readonly="1" string="Last Closing Balance"/>
<field name="balance_start" readonly="1" string="Computed Amount"/>
<field name="balance_start" readonly="1" string="Opening Cash Control"/>
<field name="total_entry_encoding" />
</group>
<group col="2" colspan="2">
<separator string="Closing Balance" colspan="4"/>
<field name="balance_end"/>
<field name="balance_end_cash"/>
<field name="difference" />
<field name="balance_end_real" readonly="1" string="Closing Cash Control"/>
<field name="balance_end" string="Theorical Cash Closing"/>
</group>
<group col="2" colspan="2">
<separator string="Dates" colspan="4"/>
<field name="date" readonly="1"/>
<field name="closing_date" readonly="1"/>
</group>
</group>
<group col="8" colspan="4">
<field name="state" widget="statusbar" statusbar_visible="draft,confirm" colspan="4"/>
<button name="button_cancel" states="confirm,open" string="Cancel" icon="terp-gtk-stop" type="object"/>
<button name="button_confirm_cash" states="open" string="Close CashBox" icon="terp-dialog-close" type="object"/>
<button name="button_open" states="draft" string="Open CashBox" icon="gtk-go-forward" type="object"/>
</group>
</sheet>
</form>
</field>
</record>

View File

@ -57,7 +57,6 @@
- pieces: 500.0
number: 2
subtotal: 1000.0
balance_end_cash: 1120.0
-
I clicked on Close CashBox button to close the cashbox

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
from osv import osv, fields
import decimal_precision as dp
from tools.translate import _
class CashBox(osv.osv_memory):
_register = False
@ -29,7 +30,7 @@ class CashBox(osv.osv_memory):
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,))
_("Please check that the field 'Internal Transfers Account' is set on the payment method '%s'.") % (record.journal_id.name,))
self._create_bank_statement_line(cr, uid, box, record, context=context)

View File

@ -42,9 +42,10 @@ class account_bank_statement(osv.osv):
def button_confirm_bank(self, cr, uid, ids, context=None):
super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context)
for st in self.browse(cr, uid, ids, context=context):
cr.execute("UPDATE account_bank_statement_line \
SET state='confirm' WHERE id in %s ",
(tuple([x.id for x in st.line_ids]),))
if st.line_ids:
cr.execute("UPDATE account_bank_statement_line \
SET state='confirm' WHERE id in %s ",
(tuple([x.id for x in st.line_ids]),))
return True
def button_cancel(self, cr, uid, ids, context=None):

View File

@ -218,7 +218,7 @@
<field name="type">form</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page[@name='statement_line_ids']/field[@name='line_ids']/tree/field[@name='amount']" position="after">
<xpath expr="//notebook/page[@name='statement_line_ids']/field[@name='line_ids']/tree/field[@name='amount']" position="after">
<field name="voucher_id" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name}"/>
</xpath>
</field>
@ -230,7 +230,7 @@
<field name="type">form</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page[@name='statement_line_ids']/field[@name='line_ids']/form/field[@name='sequence']" position="before">
<xpath expr="//notebook/page[@name='statement_line_ids']/field[@name='line_ids']/form/field[@name='sequence']" position="before">
<field name="voucher_id" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name}"/>
</xpath>
</field>
@ -241,7 +241,7 @@
<field name="type">form</field>
<field name="inherit_id" ref="account.view_bank_statement_form2"/>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='amount']" position="after">
<xpath expr="//field[@name='line_ids']/tree/field[@name='amount']" position="after">
<field name="voucher_id" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name}"/>
</xpath>
</field>
@ -253,7 +253,7 @@
<field name="type">form</field>
<field name="inherit_id" ref="account.view_bank_statement_form2"/>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='line_ids']/form/field[@name='amount']" position="after">
<xpath expr="//field[@name='line_ids']/form/field[@name='amount']" position="after">
<field name="voucher_id" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name}"/>
</xpath>
</field>

View File

@ -21,7 +21,6 @@
import point_of_sale
import account_bank_statement
import product
import res_users
import wizard
import report

View File

@ -58,15 +58,14 @@ Main features :
'wizard/pos_payment_report.xml',
'wizard/pos_payment.xml',
'wizard/pos_box.xml',
'wizard/pos_session_opening.xml',
'point_of_sale_report.xml',
'point_of_sale_view.xml',
'report/pos_order_report_view.xml',
'report/report_cash_register_view.xml',
'point_of_sale_sequence.xml',
'point_of_sale_workflow.xml',
'account_statement_view.xml',
'account_statement_report.xml',
'product_view.xml',
'res_users_view.xml',
],
'demo_xml': [

View File

@ -30,6 +30,7 @@ class account_journal(osv.osv):
'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"),
'amount_authorized_diff' : fields.float('Amount Authorized Difference'),
}
_defaults = {
'opening_control' : True,
@ -40,53 +41,9 @@ account_journal()
class account_cash_statement(osv.osv):
_inherit = 'account.bank.statement'
#def _equal_balance(self, cr, uid, cash_id, context=None):
# statement = self.browse(cr, uid, cash_id, context=context)
# if not statement.journal_id.check_dtls:
# return True
# if statement.journal_id.check_dtls and (statement.balance_end != statement.balance_end_cash):
# return False
# else:
# return True
def _get_cash_open_box_lines(self, cr, uid, context=None):
res = super(account_cash_statement,self)._get_cash_open_box_lines(cr, uid, context)
curr = [0.01, 0.02, 0.05, 0.10, 0.20, 0.50]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append(dct)
res.sort()
return res
def _get_default_cash_close_box_lines(self, cr, uid, context=None):
res = super(account_cash_statement,self)._get_default_cash_close_box_lines(cr, uid, context=context)
curr = [0.01, 0.02, 0.05, 0.10, 0.20, 0.50]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append(dct)
res.sort()
return res
def search(self, cr, uid, domain, offset=0, limit=None, order=None, context=None, count=False):
if not context:
context = {}
pos_session_id = context.pop('pos_session_id', False) or False
if pos_session_id and isinstance(pos_session_id, (int, long)):
session = self.pool.get('pos.session').browse(cr, uid, pos_session_id, context=context)
return [
statement.id
for order in session.order_ids
for statement in order.statement_ids
]
return super(account_cash_statement, self).search(cr, uid, domain, offset=offset, limit=limit, order=order, context=context, count=count)
_columns = {
'pos_session_id' : fields.many2one('pos.session'),
}
account_cash_statement()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -9,11 +9,11 @@
<field name="arch" type="xml">
<xpath expr="//notebook[last()]" position="inside">
<page string="Point of Sale">
<group col="6" colspan="4">
<separator colspan="6" string="Extended Configuration"/>
<group col="4" colspan="4">
<field name="journal_user"/>
<field name="opening_control" />
<field name="closing_control" />
<field name="opening_control"/>
<field name="closing_control"/>
<field name="amount_authorized_diff"/>
</group>
</page>
</xpath>
@ -129,6 +129,7 @@
<field name="act_window_id" ref="action_new_bank_statement_all_tree"/>
</record>
<!--
<menuitem name="Cash Register Management" parent="point_of_sale.menu_point_root"
id="menu_point_open_config" sequence="10"/>
<menuitem
@ -156,6 +157,7 @@
id="menu_all_menu_all_register"
sequence="4"
/>
-->
</data>

View File

@ -37,87 +37,76 @@ class pos_config(osv.osv):
_name = 'pos.config'
POS_CONFIG_STATE = [
('draft', 'Draft'),
('active', 'Active'),
('inactive', 'Inactive'),
('deprecated', 'Deprecated')
]
_columns = {
'name' : fields.char('Name', size=32,
select=1,
required=True,
readonly=True,
states={'draft' : [('readonly', False)]}
),
'journal_ids' : fields.many2many('account.journal',
'pos_config_journal_rel',
'pos_config_id',
'journal_id',
'Payment Methods',
domain="[('journal_user', '=', True )]",
readonly=True,
states={'draft' : [('readonly', False)]}
),
'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 )]",),
'shop_id' : fields.many2one('sale.shop', 'Shop',
required=True,
select=1,
readonly=True,
states={'draft' : [('readonly', False)]}
),
'journal_id' : fields.many2one('account.journal', 'Journal',
required=True,
select=1,
domain=[('type', '=', 'sale')],
readonly=True,
states={'draft' : [('readonly', False)]}
),
'iface_self_checkout' : fields.boolean('Self Checkout Mode'),
'iface_websql' : fields.boolean('WebSQL (to store data)'),
required=True),
'journal_id' : fields.many2one('account.journal', 'Sale Journal',
required=True, domain=[('type', '=', 'sale')],
help="Accounting journal used to post sales entries."),
'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_websql' : fields.boolean('WebSQL (Faster but Chrome Only)',
help="If have more than 200 products, it's highly suggested to use WebSQL "\
"to store the data in the browser, instead of localStore mechanism. "\
"It's more efficient but works on the Chrome browser only."
),
'iface_led' : fields.boolean('LED Interface'),
'iface_cashdrawer' : fields.boolean('Cashdrawer Interface'),
'iface_payment_terminal' : fields.boolean('Payment Terminal Interface'),
'iface_electronic_scale' : fields.boolean('Electronic Scale Interface'),
'iface_barscan' : fields.boolean('BarScan Interface'),
'iface_vkeyboard' : fields.boolean('Virtual KeyBoard Interface'),
'iface_print_via_proxy' : fields.boolean('Print via Proxy'),
'state' : fields.selection(POS_CONFIG_STATE, 'State',
required=True,
readonly=True),
'sequence_id' : fields.many2one('ir.sequence', 'Sequence',
readonly=True),
'user_id' : fields.many2one('res.users', 'User',
readonly=True,
states={'draft' : [('readonly', False)]}
),
'state' : fields.selection(POS_CONFIG_STATE, 'State', required=True, readonly=True),
'sequence_id' : fields.many2one('ir.sequence', 'Order IDs Sequence', readonly=True,
help="This sequence is automatically created by OpenERP but you can change it "\
"to customize the reference numbers of your orders."),
'session_ids': fields.one2many('pos.session', 'config_id', 'Sessions'),
}
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]
result.append((record.id, record.name + ' ('+session.user_id.name+', '+states[session.state]+')'))
return result
def _default_sale_journal(self, cr, uid, context=None):
res = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale')], limit=1)
return res and res[0] or False
def _default_shop(self, cr, uid, context=None):
res = self.pool.get('sale.shop').search(cr, uid, [])
return res and res[0] or False
_defaults = {
'state' : 'draft',
'user_id' : lambda obj, cr, uid, context: uid,
'state' : POS_CONFIG_STATE[0][0],
'shop_id': _default_shop,
'journal_id': _default_sale_journal
}
def _check_only_one_cash_journal(self, cr, uid, ids, context=None):
for record in self.browse(cr, uid, ids, context=context):
has_cash_journal = False
for journal in record.journal_ids:
if journal.type == 'cash':
if has_cash_journal:
return False
else:
has_cash_journal = True
return True
_constraints = [
(_check_only_one_cash_journal, "You should have only one Cash Journal !", ['journal_id']),
]
def set_draft(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'draft'}, context=context)
def set_active(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'active'}, context=context)
@ -128,173 +117,187 @@ class pos_config(osv.osv):
return self.write(cr, uid, ids, {'state' : 'deprecated'}, context=context)
def create(self, cr, uid, values, context=None):
proxy = self.pool.get('ir.sequence.type')
sequence_values = dict(
code='pos_%s_sequence' % values['name'].lower(),
name='POS %s Sequence' % values['name'],
)
proxy.create(cr, uid, sequence_values, context=context)
proxy = self.pool.get('ir.sequence')
sequence_values = dict(
code='pos_%s_sequence' % values['name'].lower(),
name='POS %s Sequence' % values['name'],
padding=4,
prefix="%s/%%(year)s/%%(month)s/%%(day)s/" % values['name'],
name='PoS %s' % values['name'],
padding=5,
prefix="%s/" % values['name'],
)
sequence_id = proxy.create(cr, uid, sequence_values, context=context)
values['sequence_id'] = sequence_id
return super(pos_config, self).create(cr, uid, values, context=context)
def write(self, cr, uid, ids, values, context=None):
for obj in self.browse(cr, uid, ids, context=context):
if obj.sequence_id and values.get('name', False):
prefixes = obj.sequence_id.prefix.split('/')
if len(prefixes) >= 4 and prefixes[0] == obj.name:
prefixes[0] = values['name']
sequence_values = dict(
code='pos_%s_sequence' % values['name'].lower(),
name='POS %s Sequence' % values['name'],
prefix="/".join(prefixes),
)
obj.sequence_id.write(sequence_values)
return super(pos_config, self).write(cr, uid, ids, 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)
pos_config()
class pos_session(osv.osv):
_name = 'pos.session'
_order = 'id desc'
#"status [BUTTON TEXT]" -> utiliser
# "opening control (open) -> opened (cashbox control) -> closing control (close) -> closed & posted"
POS_SESSION_STATE = [('new', 'New'),('opened', 'Opened'),('closed', 'Closed'),('posted', 'Posted')]
#POS_SESSION_STATE = [
# ('new', 'Opening Control'),
# ('opened', 'Opened'),
# ('closed', 'Closing Control'),
# ('posted', 'Closed & Posted'),
#]
POS_SESSION_STATE = [
('opening_control', 'Opening Control'), # Signal open
('opened', 'In Progress'), # Signal closing
('closing_control', 'Closing Control'), # Signal close
('closed', 'Closed & Posted'),
]
def _compute_cash_register_id(self, cr, uid, ids, fieldnames, args, context=None):
result = dict.fromkeys(ids, False)
for record in self.browse(cr, uid, ids, context=context):
for st in record.statement_ids:
if st.journal_id.type == 'cash':
result[record.id] = st.id
break
return result
_columns = {
'config_id' : fields.many2one('pos.config', 'PoS',
'config_id' : fields.many2one('pos.config', 'Point of Sale',
help="The physical point of sale you will use.",
required=True,
select=1,
domain="[('state', '=', 'active')]",
readonly=True,
states={'draft' : [('readonly', False)]}
# readonly=True,
# states={'draft' : [('readonly', False)]}
),
'name' : fields.char('Session Sequence', size=32,
'name' : fields.char('Session ID', size=32,
required=True,
select=1,
readonly=True,
states={'draft' : [('readonly', False)]}
# readonly=True,
# states={'draft' : [('readonly', False)]}
),
'user_id' : fields.many2one('res.users', 'User',
'user_id' : fields.many2one('res.users', 'Responsible',
required=True,
select=1,
readonly=True,
states={'draft' : [('readonly', False)]}
# readonly=True,
# states={'draft' : [('readonly', False)]}
),
'start_at' : fields.datetime('Opening Date'),
'stop_at' : fields.datetime('Closing Date'),
'state' : fields.selection(POS_SESSION_STATE, 'State',
required=True,
readonly=True,
select=1),
required=True, readonly=True,
select=1),
'cash_register_id' : fields.many2one('account.bank.statement', 'Bank Account Statement',
ondelete='cascade'),
'cash_register_id' : fields.function(_compute_cash_register_id, method=True,
type='many2one', relation='account.bank.statement',
string='Cash Register', store=True),
'opening_details_ids' : fields.related('cash_register_id', 'opening_details_ids',
type='one2many', relation='account.cashbox.line',
string='Opening Cash Control'),
'details_ids' : fields.related('cash_register_id', 'details_ids',
type='one2many', relation='account.cashbox.line',
string='CashBox Lines'),
type='one2many', relation='account.cashbox.line',
string='Cash Control'),
'cash_register_balance_end_real' : fields.related('cash_register_id', 'balance_end_real',
type='float',
digits_compute=dp.get_precision('Account'),
string="Ending Balance",
help="Computed using the 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.",
readonly=True),
'cash_register_total_entry_encoding' : fields.related('cash_register_id', 'total_entry_encoding',
string='Total Cash Transaction',
readonly=True),
'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.",
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.",
readonly=True),
'journal_ids' : fields.related('config_id', 'journal_ids',
type='many2many',
readonly=True,
relation='account.journal',
string='Journals'),
string='Available Payment Methods'),
'order_ids' : fields.one2many('pos.order', 'session_id', 'Orders'),
'statement_ids' : fields.one2many('account.bank.statement', 'pos_session_id', 'Bank Statement', readonly=True),
}
_defaults = {
'name' : '/',
'user_id' : lambda obj, cr, uid, context: uid,
'state' : 'new',
'state' : 'opening_control',
}
_sql_constraints = [
('uniq_name', 'unique(name)', "The name of this POS Session must be unique !"),
]
def _create_cash_register(self, cr, uid, pos_config, user_id, context=None):
if not pos_config:
return False
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 = [
('state', '!=', 'closed'),
('user_id', '=', uid)
]
count = self.search_count(cr, uid, domain, context=context)
if count>1:
return False
return True
proxy = self.pool.get('account.bank.statement')
def _check_pos_config(self, cr, uid, ids, context=None):
for session in self.browse(cr, uid, ids, context=None):
domain = [
('state', '!=', 'closed'),
('config_id', '=', session.config_id.id)
]
count = self.search_count(cr, uid, domain, context=context)
if count>1:
return False
return True
journal_id = False
for journal in pos_config.journal_ids:
if journal.type == 'cash':
journal_id = journal.id
break
if not journal_id:
return False
values = {
'journal_id' : journal_id,
'user_id' : pos_config.user_id and pos_config.user_id.id or uid,
}
cash_register_id = proxy.create(cr, uid, values, context=context)
return cash_register_id
_constraints = [
(_check_unicity, "You can not create two active sessions with the same responsible!", ['user_id', 'state']),
(_check_pos_config, "You can not create two active sessions related to the same point of sale!", ['config_id']),
]
def create(self, cr, uid, values, context=None):
config_id = values.get('config_id', False) or False
pos_config = None
if config_id:
pos_config = self.pool.get('pos.config').browse(cr, uid, config_id, context=context)
name = pos_config.sequence_id._next()
user_id = values.get('user_id', uid) or uid
values.update(
name=name,
cash_register_id=self._create_cash_register(cr, uid, pos_config, user_id=user_id, context=context),
)
else:
raise osv.except_osv(_('Error!'), _('There is no POS Config attached to this POS Session'))
bank_statement_ids = []
for journal in pos_config.journal_ids:
bank_values = {
'journal_id' : journal.id,
'user_id' : uid,
}
statement_id = self.pool.get('account.bank.statement').create(cr, uid, bank_values, context=context)
bank_statement_ids.append(statement_id)
values.update({
'name' : pos_config.sequence_id._next(),
'statement_ids' : [(6, 0, bank_statement_ids)]
})
return super(pos_session, 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.cash_register_id:
obj.cash_register_id.unlink(context=context)
for statement in obj.statement_ids:
statement.unlink(context=context)
return True
def on_change_config(self, cr, uid, ids, config_id, context=None):
result = dict(value=dict())
if not config_id:
result['value']['user_id'] = uid
else:
result['value']['user_id'] = self.pool.get('pos.config').browse(cr, uid, config_id, context=context).user_id.id
return result
def wkf_action_open(self, cr, uid, ids, context=None):
# si pas de date start_at, je balance une date, sinon on utilise celle de l'utilisateur
for record in self.browse(cr, uid, ids, context=context):
@ -302,21 +305,62 @@ class pos_session(osv.osv):
if not record.start_at:
values['start_at'] = time.strftime('%Y-%m-%d %H:%M:%S')
values['state'] = 'opened'
record.write(values, context=context)
record.cash_register_id.button_open(context=context)
for st in record.statement_ids:
st.button_open(context=context)
return True
def wkf_action_closing_control(self, cr, uid, ids, context=None):
for session in self.browse(cr, uid, ids, context=context):
for statement in session.statement_ids:
if not statement.journal_id.closing_control:
if statement.balance_end<>statement.balance_end_real:
self.pool.get('account.bank.statement').write(cr, uid,
[statement.id], {'balance_end_real': statement.balance_end})
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):
# Close CashBox
record.cash_register_id.button_confirm_cash(context=context)
return self.write(cr, uid, ids, {'state' : 'close', 'stop_at' : time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
bsl = self.pool.get('account.bank.statement.line')
for record in self.browse(cr, uid, ids, context=context):
for st in record.statement_ids:
if abs(st.difference) > st.journal_id.amount_authorized_diff:
# 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))
if st.difference:
if st.difference > 0.0:
name= _('Point of Sale Profit')
account_id = st.journal_id.profit_account_id.id
else:
account_id = st.journal_id.loss_account_id.id
name= _('Point of Sale Loss')
if not account_id:
raise osv.except_osv( _('Error !'),
_("Please set your profit and loss accounts on your payment method '%s'.") % (st.journal_id.name,))
bsl.create(cr, uid, {
'statement_id': st.id,
'amount': st.difference,
'ref': record.name,
'name': name,
'account_id': account_id
}, context=context)
def wkf_action_post(self, cr, uid, ids, context=None):
getattr(st, 'button_confirm_%s' % st.journal_id.type)(context=context)
self._confirm_orders(cr, uid, ids, context=context)
return self.write(cr, uid, ids, {'state' : 'post'}, context=context)
return self.write(cr, uid, ids, {'state' : 'closed'}, context=context)
def has_opening_control(self, cr, uid, ids, context=None):
return any(journal.opening_control == True
for session in self.browse(cr, uid, ids, context=context)
for journal in session.config_id.journal_ids)
def has_closing_control(self, cr, uid, ids, context=None):
result = any(journal.closing_control == True
for session in self.browse(cr, uid, ids, context=context)
for journal in session.config_id.journal_ids)
return result
def _confirm_orders(self, cr, uid, ids, context=None):
wf_service = netsvc.LocalService("workflow")
@ -355,7 +399,7 @@ class pos_session(osv.osv):
if not pos_config_ids:
raise osv.except_osv(_('Error !'),
_('There is no active PoS Config for this User %s') % current_user.name)
_('There is no active Point of Sale Config for this User %s') % current_user.name)
config = pos_config_proxy.browse(cr, uid, pos_config_ids[0], context=context)
@ -369,25 +413,11 @@ class pos_session(osv.osv):
session_id = self.create(cr, uid, values, context=context)
wkf_service = netsvc.LocalService('workflow')
wkf_service.trg_validate(uid, 'pos.session', session_id, 'open', cr)
wkf_service.trg_validate(uid, 'pos.session', session_id, 'opening_control', cr)
return session_id
pos_session()
class pos_config_journal(osv.osv):
""" Point of Sale journal configuration"""
_name = 'pos.config.journal'
_description = "Journal Configuration"
_columns = {
'name': fields.char('Description', size=64),
'code': fields.char('Code', size=64),
'journal_id': fields.many2one('account.journal', "Journal")
}
pos_config_journal()
class pos_order(osv.osv):
_name = "pos.order"
_description = "Point of Sale"
@ -453,14 +483,6 @@ class pos_order(osv.osv):
res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1)
return res
def _default_sale_journal(self, cr, uid, context=None):
res = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale')], limit=1)
return res and res[0] or False
def _default_shop(self, cr, uid, context=None):
res = self.pool.get('sale.shop').search(cr, uid, [])
return res and res[0] or False
def copy(self, cr, uid, id, default=None, context=None):
if not default:
default = {}
@ -479,10 +501,9 @@ class pos_order(osv.osv):
_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.many2one('sale.shop', 'Shop', required=True,
states={'draft': [('readonly', False)]}, readonly=True),
'date_order': fields.datetime('Date Ordered', readonly=True, select=True),
'user_id': fields.many2one('res.users', 'Connected Salesman', help="Person who uses the the cash register. It could be a reliever, a student or an interim employee."),
'shop_id': fields.related('session_id', 'config_id', 'shop_id', relation='sale.shop', type='many2one', string='Shop', 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 could 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_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'),
@ -511,9 +532,15 @@ class pos_order(osv.osv):
'picking_id': fields.many2one('stock.picking', 'Picking', readonly=True),
'note': fields.text('Internal Notes'),
'nb_print': fields.integer('Number of Print', readonly=True),
'sale_journal': fields.many2one('account.journal', 'Journal', required=True, states={'draft': [('readonly', False)]}, readonly=True),
'sale_journal': fields.related('session_id', 'config_id', 'journal_id', relation='account.journal', type='many2one', string='Sale Journal', store=True, readonly=True),
}
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
def _default_pricelist(self, cr, uid, context=None):
res = self.pool.get('sale.shop').search(cr, uid, [], context=context)
if res:
@ -527,9 +554,8 @@ class pos_order(osv.osv):
'name': '/',
'date_order': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'nb_print': 0,
'session_id': _default_session,
'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
'sale_journal': _default_sale_journal,
'shop_id': _default_shop,
'pricelist_id': _default_pricelist,
}
@ -600,18 +626,6 @@ class pos_order(osv.osv):
picking_obj.force_assign(cr, uid, [picking_id], context)
return True
def set_to_draft(self, cr, uid, ids, *args):
if not len(ids):
return False
for order in self.browse(cr, uid, ids, context=context):
if order.state != 'cancel':
raise osv.except_osv(_('Error!'), _('In order to set to draft a sale, it must be cancelled.'))
self.write(cr, uid, ids, {'state': 'draft'})
wf_service = netsvc.LocalService("workflow")
for i in ids:
wf_service.trg_create(uid, 'pos.order', i, cr)
return True
def cancel_order(self, cr, uid, ids, context=None):
""" Changes order state to cancel
@return: True
@ -657,22 +671,29 @@ class pos_order(osv.osv):
raise osv.except_osv(_('Configuration Error !'), msg)
context.pop('pos_session_id', False)
domain = [
('journal_id', '=', int(data['journal'])),
('company_id', '=', curr_company),
('user_id', '=', uid),
('state', '=', 'open')
]
statement_id = statement_obj.search(cr,uid, domain, context=context)
if len(statement_id) == 0:
try:
journal_id = long(data['journal'])
except Exception:
journal_id = False
statement_id = False
for statement in order.session_id.statement_ids:
if statement.journal_id.id == journal_id:
statement_id = statement.id
break
if not statement_id:
raise osv.except_osv(_('Error !'), _('You have to open at least one cashbox'))
if statement_id:
statement_id = statement_id[0]
args['statement_id'] = statement_id
args['pos_statement_id'] = order_id
args['journal_id'] = int(data['journal'])
args['type'] = 'customer'
args['ref'] = order.name
args.update({
'statement_id' : statement_id,
'pos_statement_id' : order_id,
'journal_id' : journal_id,
'type' : 'customer',
'ref' : order.name,
})
statement_line_obj.create(cr, uid, args, context=context)
ids_new.append(statement_id)
@ -896,7 +917,7 @@ class pos_order(osv.osv):
continue
account_move_line_obj.create(cr, uid, {
'name': "Tax" + line.name + " (%s)" % (tax.name),
'name': _("Tax") + line.name + " (%s)" % (tax.name),
'date': order.date_order[:10],
'ref': order.name,
'product_id':line.product_id.id,
@ -935,7 +956,7 @@ class pos_order(osv.osv):
# counterpart
to_reconcile.append(account_move_line_obj.create(cr, uid, {
'name': "Trade Receivables", #order.name,
'name': _("Trade Receivables"), #order.name,
'date': order.date_order[:10],
'ref': order.name,
'move_id': move_id,
@ -1073,7 +1094,7 @@ pos_order_line()
class pos_category(osv.osv):
_name = 'pos.category'
_description = "PoS Category"
_description = "Point of Sale Category"
_order = "sequence, name"
def _check_recursion(self, cr, uid, ids, context=None):
level = 100
@ -1111,6 +1132,10 @@ class pos_category(osv.osv):
'parent_id': fields.many2one('pos.category','Parent Category', select=True),
'child_id': fields.one2many('pos.category', 'parent_id', string='Children Categories'),
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of product categories."),
'to_weight' : fields.boolean('To Weight', help="This category contains products that should be weighted, mainly used for the self-checkout interface"),
}
_defaults = {
'to_weight' : False,
}
pos_category()
@ -1134,9 +1159,9 @@ class product_product(osv.osv):
return result
_columns = {
'income_pdt': fields.boolean('PoS Cash Input', help="This is a product you can use to put cash into a statement for the point of sale backend."),
'expense_pdt': fields.boolean('PoS Cash Output', help="This is a product you can use to take cash from a statement for the point of sale backend, exemple: money lost, transfer to bank, etc."),
'pos_categ_id': fields.many2one('pos.category','PoS Category',
'income_pdt': fields.boolean('Point of Sale Cash In', help="This is a product you can use to put cash into a statement for the point of sale backend."),
'expense_pdt': fields.boolean('Point of Sale Cash Out', help="This is a product you can use to take cash from a statement for the point of sale backend, exemple: money lost, transfer to bank, etc."),
'pos_categ_id': fields.many2one('pos.category','Point of Sale Category',
help="If you want to sell this product through the point of sale, select the category it belongs to."),
'product_image_small': fields.function(_get_small_image, string='Small Image', type="binary",
store = {

View File

@ -16,16 +16,27 @@
<field name="model">pos.order</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="PoS Orders">
<group col="7" colspan="4">
<field name="session_id" required="1" />
<form string="Point of Sale Orders" layout="manual">
<div class="oe_form_topbar">
<button name="%(action_pos_payment)d" string="Payment" icon="gtk-apply" type="action" states="draft" context="{'pos_session_id' : session_id}"/>
<button name="action_invoice" string="Invoice" icon="gtk-apply" type="object" states="paid" attrs="{'readonly': [('partner_id','=',False)]}"/>
<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"/>
<div class="oe_right">
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,paid,done" statusbar_colors='{"cancel":"red"}'/>
</div>
</div>
<sheet layout="auto">
<group col="4" colspan="4">
<field name="name"/>
<field name="date_order"/>
<field name="session_id" required="1" />
<field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_customer':1}" attrs="{'readonly': [('state','=','invoiced')]}"/>
<button name="action_invoice" string="Invoice" icon="gtk-apply" type="object" states="paid" attrs="{'readonly': [('partner_id','=',False)]}"/>
</group>
<notebook colspan="4">
<page string="Sale Order">
<page string="Products">
<field name="lines" colspan="4" nolabel="1">
<tree string="Order lines" editable="bottom">
<field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,qty,parent.partner_id)"/>
@ -52,16 +63,8 @@
<button name="%(action_pos_discount)d" string="Discount" icon="gtk-remove" type="action" states="draft" />
</group>
<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" 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"/>
</group>
</page>
<page string="Payment">
<page string="Payments">
<field name="statement_ids" colspan="4" nolabel="1">
<tree editable="bottom" string="Statement lines">
<field name="journal_id"/>
@ -100,11 +103,12 @@
<field colspan="4" name="note" nolabel="1"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_pos_pos_form">
<field name="name">PoS Orders</field>
<field name="name">Orders</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.order</field>
<field name="view_type">form</field>
@ -622,11 +626,13 @@
<field name="type">form</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<field name="company_id" position="after">
<separator string="Point of Sale" colspan="2"/>
<field name="income_pdt"/>
<field name="expense_pdt"/>
</field>
<group name="misc" position="after">
<group name="pos" colspan="2" col="2">
<separator string="Point of Sale" colspan="2"/>
<field name="income_pdt"/>
<field name="expense_pdt"/>
</group>
</group>
</field>
</record>
@ -636,11 +642,12 @@
<field name="model">pos.category</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="PoS Categories">
<form string="Product PoS Categories">
<group colspan="4" col="6">
<field name="name"/>
<field name="parent_id"/>
<field name="sequence"/>
<field name="to_weight" />
</group>
</form>
</field>
@ -651,14 +658,14 @@
<field name="type">tree</field>
<field name="field_parent" eval="False"/>
<field name="arch" type="xml">
<tree string="PoS Categories">
<tree string="Product PoS Categories">
<field name="sequence" invisible="1"/>
<field name="complete_name"/>
</tree>
</field>
</record>
<record id="pos_category_action" model="ir.actions.act_window">
<field name="name">PoS Categories</field>
<field name="name">Product Categories</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.category</field>
<field name="view_type">form</field>
@ -676,7 +683,7 @@
<field name="res_model">account.journal</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context" eval="{'default_journal_user': 1, 'default_view_id': ref('account.account_journal_bank_view'), 'default_type': 'cash'}"/>
<field name="context" eval="{'default_journal_user': 1, 'default_type': 'cash'}"/>
<field name="domain">[('journal_user','=', 1)]</field>
<field name="help">Payment methods are defined by accounting journals having the field Payment Method checked.</field>
</record>
@ -712,16 +719,6 @@
<menuitem name="Point of Sale" parent="base.menu_reporting" id="menu_point_rep" sequence="50" groups="group_pos_manager"/>
<!-- Invoice -->
<record model="ir.actions.act_window" id="action_pos_sale_all">
<field name="name">All Sales Orders</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.order</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[]</field>
</record>
<menuitem parent="menu_point_rep" id="menu_point_ofsale_all" action="action_pos_sale_all" sequence="1"/>
<record model="ir.actions.act_window" id="action_pos_invoice">
<field name="name">Invoices</field>
<field name="type">ir.actions.act_window</field>
@ -731,10 +728,8 @@
<field name="domain">[('origin','like','POS')]</field>
</record>
<menuitem name="Reporting" id="menu_point_of_sale_reporting" parent="menu_point_root" sequence="20" />
<menuitem icon="STOCK_PRINT" action="action_report_pos_details"
id="menu_pos_details" parent="menu_point_of_sale_reporting" sequence="6" />
id="menu_pos_details" parent="menu_point_rep" sequence="6" />
<record model="ir.actions.client" id="action_pos_pos">
<field name="name">Start Point of Sale</field>
@ -756,48 +751,43 @@
<field name="model">pos.config</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="PoS Configuration">
<field name="name" />
<notebook colspan="4">
<page string="Payment Methods">
<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" />
<field name="shop_id" widget="selection" />
<field name="journal_id" widget="selection" />
</page>
<page string="Interfaces">
<field name="iface_self_checkout" />
<field name="iface_websql" />
<field name="iface_led" />
<field name="iface_cashdrawer" />
<field name="iface_payment_terminal" />
<field name="iface_electronic_scale" />
<field name="iface_barscan" />
<field name="iface_vkeyboard" />
</page>
<page string="Others">
<field name="user_id" />
<field name="sequence_id" />
</page>
</notebook>
<group colspan="4" col="6">
<field name="state" widget="statusbar" statusbar_visible="draft,active,inactive,deprecated" statusbar_colors='{"active":"green", "deprecated" : "red"}'/>
<button string="Set to Draft" name="set_draft" type="object" states="deprecated"/>
<button string="Set to Active" name="set_active" type="object" states="draft,inactive"/>
<form string="Point of Sale Configuration" layout="manual">
<div class="oe_form_topbar">
<button string="Set to Active" name="set_active" type="object" states="inactive,deprecated"/>
<button string="Set to Inactive" name="set_inactive" type="object" states="active" />
<button string="Set to Deprecated" name="set_deprecate" type="object" states="active,inactive" />
</group>
<div class="oe_right">
<field name="state" widget="statusbar" statusbar_visible="active,inactive,deprecated" statusbar_colors='{"deprecated" : "red"}' nolabel="1"/>
</div>
</div>
<sheet layout="auto">
<field name="name" placeholder="POS/0001"/>
<field name="shop_id" widget="selection" />
<field name="journal_id" widget="selection" />
<field name="sequence_id" readonly="1"/>
<separator string="Available Payment Methods" colspan="4"/>
<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>
<separator string="Material Interfaces" colspan="4"/>
<field name="iface_self_checkout" />
<field name="iface_websql" />
<field name="iface_led" />
<field name="iface_cashdrawer" />
<field name="iface_payment_terminal" />
<field name="iface_electronic_scale" />
<field name="iface_barscan" />
<field name="iface_vkeyboard" />
<field name="iface_print_via_proxy" />
</sheet>
</form>
</field>
</record>
@ -807,10 +797,8 @@
<field name="model">pos.config</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="PoS Configuration" colors="grey:state == 'inactive'">
<tree string="Point of Sale Configuration" colors="grey:state == 'inactive'">
<field name="name" />
<field name="user_id" />
<field name="journal_id" />
<field name="shop_id" />
<field name="state" />
</tree>
@ -822,21 +810,13 @@
<field name="model">pos.config</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="PoS Config">
<search string="Point of Sale Config">
<filter string="Active" domain="[('state', '=', 'active')]" />
<filter string="Inactive" domain="[('state', '=', 'inactive')]" />
<separator orientation="vertical"/>
<field name="name" />
<field name="user_id" />
<field name="journal_id" />
<field name="shop_id" />
<newline />
<group expand="0" string="Group By...">
<filter string="User" icon="terp-personal" domain="[]" context="{'group_by' : 'user_id'}" />
<filter string="Journal" icon="terp-folder-orange" domain="[]" context="{'group_by' : 'journal_id'}" />
<filter string="Shop" icon="terp-go-home" domain="[]" context="{'group_by' : 'shop_id'}" />
</group>
</search>
</field>
</record>
@ -850,7 +830,7 @@
domain="[('config_id', '=', active_id)]" />
<record model="ir.actions.act_window" id="action_pos_config_pos">
<field name="name">PoS Config</field>
<field name="name">Point of Sales</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.config</field>
<field name="view_type">form</field>
@ -864,42 +844,95 @@
id="menu_pos_config_pos"
groups="group_pos_manager"/>
<act_window
id="act_pos_session_orders"
name="Orders"
src_model="pos.session"
res_model="pos.order"
context="{'search_default_session_id': active_id, 'default_session_id' : active_id }" />
<record model="ir.ui.view" id="view_pos_session_form">
<field name="name">pos.session.form.view</field>
<field name="model">pos.session</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="PoS Session">
<group colspan="4" col="6">
<field name="config_id" on_change="on_change_config(config_id)" />
<field name="name" />
<form string="Point of Sale Session" layout="manual">
<div class="oe_form_topbar">
<button name="open" type="workflow" string="Validate &amp; Open Session" states="opening_control" />
<button name="cashbox_control" type="workflow" string="End of Session" states="opened" />
<button name="close" type="workflow" string="Validate &amp; Close" states="closing_control" />
<div class="oe_right">
<field name="state" widget="statusbar" statusbar_visible="opening_control,opened,closing_control,closed" nolabel="1"/>
</div>
</div>
<sheet layout="auto">
<group colspan="4" col="4">
<field name="config_id"/>
<group colspan="2" col="3">
<button name="%(action_pos_box_in)d" string="Put Money In" type="action" states="opened"/>
<button name="%(action_pos_box_out)d" string="Take Money Out" type="action" states="opened"/>
<button name="%(act_pos_session_orders)d" string="Orders" type="action"/>
</group>
<newline/>
<field name="user_id" />
<field name="name" />
<newline/>
<field name="start_at" />
<field name="stop_at" />
</group>
<notebook colspan="4">
<page string="Cash">
<field name="cash_register_id" invisible="0" />
<field name="details_ids" colspan="4" nolabel="1">
<tree string="" editable="bottom">
<separator string="Cash Control" colspan="4"/>
<field name="cash_register_id" invisible="1" />
<field name="opening_details_ids" colspan="4" nolabel="1" attrs="{'invisible' : [('state', 'not in', ('opening_control',))]}">
<tree string="Opening Cashbox Lines" 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="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="subtotal_closing" string="Closing Subtotal"/>
<field name="subtotal_opening" string="Opening Subtotal" sum="Total"/>
</tree>
</field>
<field name="journal_ids" colspan="4" nolabel="1" />
</page>
</notebook>
<group colspan="4" col="5">
<field name="state" widget="statusbar" statusbar_visible="new,opened,closed,posted" statusbar_colors='{"posted":"green"}'/>
<button name="open" type="workflow" string="Open" states="new" />
<button name="close" type="workflow" string="Close" states="opened" />
<button name="post" type="workflow" string="Post" states="closed" />
</group>
<field name="details_ids" colspan="4" nolabel="1" attrs="{'invisible': [('state', '=', 'opening_control')]}">
<tree string="Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_opening" readonly="1"/>
<field name="subtotal_opening"/>
<field name="number_closing"/>
<field name="subtotal_closing"/>
</tree>
</field>
<group col="4" colspan="4">
<group col="2" colspan="2">
<separator string="Cash Balance" colspan="2"/>
<field name="cash_register_balance_start" readonly="1" string="Opening Cash Control"/>
<field name="cash_register_total_entry_encoding" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="+ Transactions"/>
<field name="cash_register_balance_end" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="= Theorical Cash Closing"/>
</group>
<group col="2" colspan="2" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
<separator string="Cash Closing Balance" colspan="2"/>
<field name="cash_register_balance_end_real"/>
<field name="cash_register_difference" />
</group>
</group>
<separator string="Summary by Payment Methods" colspan="4"/>
<field name="statement_ids" colspan="4" nolabel="1">
<tree string="Statements">
<field name="name" />
<field name="journal_id" />
<field name="balance_start" />
<field name="total_entry_encoding" />
<field name="balance_end_real" />
<field name="difference" />
<field name="currency" />
<field name="state" />
</tree>
</field>
</group>
</sheet>
</form>
</field>
</record>
@ -909,7 +942,7 @@
<field name="model">pos.session</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="PoS Session">
<tree string="Point of Sale Session">
<field name="config_id" />
<field name="name" />
<field name="user_id" />
@ -924,7 +957,7 @@
<field name="model">pos.session</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="PoS Session">
<search string="Point of Sale Session">
<filter string="Open" domain="[('state', '=', 'opened')]" />
<separator orientation="vertical"/>
<filter string="Today" domain="[('start_at', '>=', time.strftime('%%Y-%%m-%%d 00:00:00'))]" />
@ -936,7 +969,7 @@
<newline />
<group expand="0" string="Group By...">
<filter string="User" icon="terp-personal" domain="[]" context="{'group_by' : 'user_id'}" />
<filter string="PoS" domain="[]" context="{'group_by': 'user_id'}" />
<filter string="Point of Sales" domain="[]" context="{'group_by': 'user_id'}" />
</group>
</search>
</field>
@ -944,7 +977,7 @@
<record model="ir.actions.act_window" id="action_pos_session">
<field name="name">PoS Sessions</field>
<field name="name">All Sessions</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.session</field>
<field name="view_type">form</field>
@ -953,26 +986,12 @@
</record>
<menuitem
parent="menu_point_of_sale"
parent="menu_point_rep"
action="action_pos_session"
id="menu_pos_session"
sequence="0"
groups="group_pos_manager"/>
<act_window
id="act_pos_session_orders"
name="Orders"
src_model="pos.session"
res_model="pos.order"
domain="[('session_id', '=', active_id)]" />
<act_window
id="act_pos_session_statements"
name="Statements"
src_model="pos.session"
res_model="account.bank.statement"
domain="[]"
context="{'pos_session_id' : active_id}" />
<record id="view_pos_order_filter" model="ir.ui.view">
<field name="name">pos.order.list.select</field>
<field name="model">pos.order</field>
@ -985,15 +1004,15 @@
<filter icon="terp-check" string="Invoiced" domain="[('state','=','invoiced')]"/>
<filter icon="gtk-convert" string="Posted" domain="[('state','=','done')]"/>
<separator orientation="vertical"/>
<filter icon="terp-go-month" string="Today" domain="[('date_order','&gt;=',datetime.date.today().strftime('%%Y-%%m-%%d 00:00:00')),('date_order','&lt;=',datetime.date.today().strftime('%%Y-%%m-%%d 23:59:59'))]"/>
<filter icon="gtk-go-forward" string="Yesterday" domain="[('date_order','&lt;',datetime.date.today().strftime('%%Y-%%m-%%d 00:00:00')),('date_order','&gt;=',(datetime.date.today() - relativedelta(days=1)).strftime('%%Y-%%m-%%d 00:00:00'))]"/>
<separator orientation="vertical"/>
<field name="name"/>
<field name="user_id"/>
<field name="date_order"/>
<field name="session_id"/>
<newline/>
<group expand="0" string="Group By..." groups="base.group_extended">
<filter string="Customer" icon="terp-personal" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Salesman" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Session" icon="terp-personal" domain="[]" context="{'group_by':'session_id'}"/>
<separator string="" orientation="vertical"/>
<filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<separator string="" orientation="vertical"/>
@ -1002,5 +1021,8 @@
</search>
</field>
</record>
<menuitem action="action_pos_session_opening" parent="menu_point_of_sale" id="menu_pos_session_opening" />
</data>
</openerp>

View File

@ -86,51 +86,70 @@
<!-- Activities -->
<record model="workflow.activity" id="act_new">
<record model="workflow.activity" id="act_opening_control">
<field name="wkf_id" ref="wkf_pos_session"/>
<field name="flow_start">True</field>
<field name="name">new</field>
<field name="name">opening_control</field>
</record>
<record model="workflow.activity" id="act_open">
<field name="wkf_id" ref="wkf_pos_session"/>
<field name="name">open</field>
<field name="name">opened</field>
<field name="action">wkf_action_open()</field>
<field name="kind">function</field>
</record>
<record model="workflow.activity" id="act_closing_control">
<field name="wkf_id" ref="wkf_pos_session"/>
<field name="name">closing_control</field>
<field name="action">wkf_action_closing_control()</field>
<field name="kind">function</field>
</record>
<record model="workflow.activity" id="act_close">
<field name="wkf_id" ref="wkf_pos_session"/>
<field name="name">close</field>
<field name="flow_stop">True</field>
<field name="name">closed</field>
<field name="action">wkf_action_close()</field>
<field name="kind">function</field>
</record>
<record model="workflow.activity" id="act_post">
<field name="wkf_id" ref="wkf_pos_session"/>
<field name="flow_stop">True</field>
<field name="name">post</field>
<field name="action">wkf_action_post()</field>
<field name="kind">function</field>
</record>
<!-- Transitions -->
<record model="workflow.transition" id="trans_new_open">
<field name="act_from" ref="act_new"/>
<field name="act_to" ref="act_open"/>
<!-- state:opening_control -> signal:open -> state:opened -> signal:cashbox_control -> state:closing_control -> signal:close -> state:close -->
<record model="workflow.transition" id="trans_opening_control_to_open">
<field name="act_from" ref="act_opening_control" />
<field name="act_to" ref="act_open" />
<field name="signal">open</field>
</record>
<!--
<record model="workflow.transition" id="trans_opening_control_to_open_automatic">
<field name="act_from" ref="act_opening_control" />
<field name="act_to" ref="act_open" />
<field name="signal" eval="False" />
<field name="condition">not has_opening_control()</field>
</record>
-->
<record model="workflow.transition" id="trans_open_close">
<field name="act_from" ref="act_open"/>
<field name="act_to" ref="act_close"/>
<field name="signal">close</field>
<record model="workflow.transition" id="trans_open_to_closing_control">
<field name="act_from" ref="act_open" />
<field name="act_to" ref="act_closing_control" />
<field name="signal">cashbox_control</field>
</record>
<record model="workflow.transition" id="trans_close_post">
<field name="act_from" ref="act_close"/>
<field name="act_to" ref="act_post"/>
<field name="signal">post</field>
<!--
<record model="workflow.transition" id="trans_closing_control_to_close_automatic">
<field name="act_from" ref="act_closing_control" />
<field name="act_to" ref="act_close" />
<field name="signal" eval="False" />
<field name="condition">not has_closing_control()</field>
</record>
-->
<record model="workflow.transition" id="trans_closing_control_to_close">
<field name="act_from" ref="act_closing_control" />
<field name="act_to" ref="act_close" />
<field name="signal">close</field>
</record>
</data>

View File

@ -1,13 +0,0 @@
#!/usr/bin/env python
from osv import osv, fields
class product_category(osv.osv):
_inherit = 'product.category'
_columns = {
'to_weight' : fields.boolean('To Weight'),
}
_defaults = {
'to_weight' : False,
}

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="product_category_form_view" model="ir.ui.view">
<field name="name">product.category.form</field>
<field name="model">product.category</field>
<field name="type">form</field>
<field name="inherit_id" ref="product.product_category_form_view" />
<field name="arch" type="xml">
<field name="type" position="after">
<field name="to_weight" />
</field>
</field>
</record>
</data>
</openerp>

View File

@ -33,6 +33,5 @@ import pos_sales_user_today
import pos_payment_report_user
import pos_report
import pos_order_report
import report_cash_register
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -69,13 +69,6 @@ class pos_details_summary(report_sxw.rml_parse):
0.0 )
def _get_payments(self, objects):
# gift_journal_id = None
# if ignore_gift:
# config_journal_ids = self.pool.get("pos.config.journal").search(self.cr, self.uid, [('code', '=', 'GIFT')])
# if len(config_journal_ids):
# config_journal = self.pool.get("pos.config.journal").browse(self.cr, self.uid, config_journal_ids, {})[0]
# gift_journal_id = config_journal.journal_id.id
result = {}
for obj in objects:
for statement in obj.statement_ids:
@ -136,4 +129,4 @@ report_sxw.report_sxw('report.pos.details_summary',
parser=pos_details_summary,
header='internal')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -38,15 +38,6 @@
<filter icon="terp-go-year" string="Year" name="year"
domain="[('year','=',time.strftime('%%Y'))]"
help="POS ordered created during current year"/>
<separator orientation="vertical"/>
<filter icon="terp-go-month" string="Month" name="This Month"
domain="[('date','&lt;=',(datetime.date.today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"
help="POS ordered created during current month"/>
<filter icon="terp-go-month"
string="Month -1"
domain="[('date','&lt;=', (datetime.date.today() - relativedelta(day=31, months=1)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today() - relativedelta(day=1,months=1)).strftime('%%Y-%%m-%%d'))]"
help="POS ordered created last month"/>
<separator orientation="vertical"/>
<filter icon="terp-go-today"
string="Today"
name="today"
@ -59,9 +50,10 @@
<filter icon="terp-dolar"
string="Not Invoiced"
domain="[('state','=',('paid'))]"/>
<separator orientation="vertical"/>
<field name="partner_id"/>
<field name="user_id" widget="selection">
<separator orientation="vertical"/>
<field name="partner_id"/>
<field name="date"/>
<field name="user_id" widget="selection">
<filter icon="terp-personal"
string="My Sales"
help="My Sales"
@ -84,12 +76,12 @@
</record>
<record id="action_report_pos_order_all" model="ir.actions.act_window">
<field name="name">Point of Sale Analysis</field>
<field name="name">Orders Analysis</field>
<field name="res_model">report.pos.order</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="search_view_id" ref="view_report_pos_order_search"/>
<field name="context">{'search_default_year':1,'search_default_This Month':1,'search_default_today':1,'search_default_User':1,'group_by_no_leaf':1,'group_by':[]}</field>
<field name="context">{'search_default_year':1,'search_default_today':1,'group_by_no_leaf':1,'group_by':['product_id']}</field>
</record>
<menuitem action="action_report_pos_order_all" id="menu_report_pos_order_all" parent="menu_point_rep" sequence="3"/>

View File

@ -1,68 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# 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.
#
# 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
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import tools
from osv import fields,osv
class report_cash_register(osv.osv):
_name = "report.cash.register"
_description = "Point of Sale Cash Register Analysis"
_auto = False
_columns = {
'date': fields.date('Create Date', readonly=True),
'year': fields.char('Year', size=4),
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'),
('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'),
('10','October'), ('11','November'), ('12','December')], 'Month',readonly=True),
'day': fields.char('Day', size=128, readonly=True),
'user_id':fields.many2one('res.users', 'User', readonly=True),
'state': fields.selection([('draft', 'Quotation'),('open','Open'),('confirm', 'Confirmed')],'State'),
'journal_id': fields.many2one('account.journal', 'Journal'),
'balance_start': fields.float('Opening Balance'),
'balance_end_real': fields.float('Closing Balance'),
}
_order = 'date desc'
def init(self, cr):
tools.drop_view_if_exists(cr, 'report_cash_register')
cr.execute("""
create or replace view report_cash_register as (
select
min(s.id) as id,
to_date(to_char(s.create_date, 'dd-MM-YYYY'),'dd-MM-YYYY') as date,
s.user_id as user_id,
s.journal_id as journal_id,
s.state as state,
s.balance_start as balance_start,
s.balance_end_real as balance_end_real,
to_char(s.create_date, 'YYYY') as year,
to_char(s.create_date, 'MM') as month,
to_char(s.create_date, 'YYYY-MM-DD') as day
from account_bank_statement as s
group by
s.user_id,s.journal_id, s.balance_start, s.balance_end_real,s.state,to_char(s.create_date, 'dd-MM-YYYY'),
to_char(s.create_date, 'YYYY'),
to_char(s.create_date, 'MM'),
to_char(s.create_date, 'YYYY-MM-DD'))""")
report_cash_register()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,89 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_report_cash_register_tree" model="ir.ui.view">
<field name="name">report.cash.register.tree</field>
<field name="model">report.cash.register</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Point of Sale Cash Register Analysis">
<field name="date" invisible="1"/>
<field name="user_id" invisible="1"/>
<field name="state" invisible="1"/>
<field name="year" invisible="1"/>
<field name="month" invisible="1"/>
<field name="day" invisible="1"/>
<field name="journal_id" invisible="1"/>
<field name="balance_start" />
<field name="balance_end_real" />
</tree>
</field>
</record>
<record id="view_report_cash_register_search" model="ir.ui.view">
<field name="name">report.cash.register.search</field>
<field name="model">report.cash.register</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Point of Sale Cash Register Analysis">
<group>
<filter icon="terp-go-year" string="Year" name="year"
domain="[('year','=',time.strftime('%%Y'))]"
help="Cash Analysis created during this year"/>
<separator orientation="vertical"/>
<filter icon="terp-go-month" string="Month" name="This Month"
domain="[('date','&lt;=',(datetime.date.today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"
help="Cash Analysis created in current month"/>
<filter icon="terp-go-month"
string="Month -1"
domain="[('date','&lt;=', (datetime.date.today() - relativedelta(day=31, months=1)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today() - relativedelta(day=1,months=1)).strftime('%%Y-%%m-%%d'))]"
help="Cash Analysis created in last month"/>
<separator orientation="vertical"/>
<filter icon="terp-go-today"
string=" Today "
name="today"
domain="[('date','=', time.strftime('%%Y-%%m-%%d'))]"
help="Cash Analysis created by today"/>
<separator orientation="vertical"/>
<filter icon="terp-document-new"
string="Draft"
domain="[('state','=',('draft'))]"/>
<filter icon="terp-camera_test"
string="Confirm"
domain="[('state','=',('confirm'))]"/>
<separator orientation="vertical"/>
<field name="user_id" widget="selection">
<filter icon="terp-personal"
string="My Sales"
help="My Sales"
domain="[('user_id','=',uid)]"/>
</field>
</group>
<newline/>
<group expand="1" string="Group By...">
<filter string="User" name="User" icon="terp-personal" context="{'group_by':'user_id'}"/>
<filter string="Journal" icon="terp-folder-orange" context="{'group_by':'journal_id'}"/>
<separator orientation="vertical"/>
<filter string="state" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
<separator orientation="vertical"/>
<filter string="Day" icon="terp-go-today" context="{'group_by':'day'}" help="Day from Creation date of cash register"/>
<filter string="Month" icon="terp-go-month" context="{'group_by':'month'}" help="Month from Creation date of cash register"/>
<filter string="Year" icon="terp-go-year" context="{'group_by':'year'}" help="Year from Creation date of cash register"/>
</group>
</search>
</field>
</record>
<record id="action_report_cash_register_all" model="ir.actions.act_window">
<field name="name">Register Analysis</field>
<field name="res_model">report.cash.register</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_report_cash_register_search"/>
<field name="context">{'search_default_year':1,'search_default_This Month':1,'search_default_today':1,'search_default_User':1,'group_by_no_leaf':1,'group_by':[]}</field>
</record>
<menuitem action="action_report_cash_register_all" id="menu_report_cash_register_all" parent="menu_point_rep" sequence="1"/>
</data>
</openerp>

View File

@ -36,19 +36,18 @@ def check_ean(eancode):
class res_users(osv.osv):
_inherit = 'res.users'
_columns = {
'ean13' : fields.char('EAN13', size=13, help="BarCode"),
'pos_config' : fields.many2one('pos.config', 'Default Point of Sale', domain=[('state', '=', 'active')]),
}
def _check_ean(self, cr, uid, ids, context=None):
return all(
check_ean(user.ean13) == True
for user in self.browse(cr, uid, ids, context=context)
)
)
_constraints = [
(_check_ean, "Error: Invalid ean code", ['ean13'],),
]

View File

@ -1,18 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<data>
<record id="res_users_form_preference_view" model="ir.ui.view">
<field name="name">res.users.form.view</field>
<field name="model">res.users</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif" />
<field name="arch" type="xml">
<group name="preferences" position="inside">
<field name="pos_config" />
</group>
</field>
</record>
<record id="res_users_form_view" model="ir.ui.view">
<field name="name">res.users.form.view</field>
<field name="model">res.users</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_users_form" />
<field name="arch" type="xml">
<notebook position="inside">
<page string="Point Of Sale">
<field name="ean13" />
</page>
</notebook>
<notebook position="inside">
<page string="Point Of Sale">
<field name="ean13" />
<field name="pos_config" />
</page>
</notebook>
</field>
</record>
</data>
</openerp>
</data>
</openerp>

View File

@ -1,11 +1,9 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_pos_config_journal,pos.config.journal,model_pos_config_journal,group_pos_user,1,0,0,0
access_pos_order,pos.order,model_pos_order,group_pos_user,1,1,1,1
access_pos_order_line,pos.order.line,model_pos_order_line,group_pos_user,1,1,1,1
access_pos_order_manager,pos.order manager,model_pos_order,group_pos_manager,1,0,0,0
access_pos_order_line_manager,pos.order.line manager,model_pos_order_line,group_pos_manager,1,0,0,0
access_report_transaction_pos,report.transaction.pos,model_report_transaction_pos,group_pos_manager,1,1,1,1
access_pos_config_journal_manager,pos.config.journal.manager,model_pos_config_journal,group_pos_manager,1,1,1,1
access_account_journal_pos_user,account.journal pos_user,account.model_account_journal,group_pos_user,1,0,0,0
access_account_move_pos_user,account.move pos_user,account.model_account_move,group_pos_user,1,1,1,0
access_account_account_pos_user,account.account pos_user,account.model_account_account,group_pos_user,1,0,0,0
@ -66,4 +64,4 @@ access_product_pricelist_manager,product.pricelist manager,product.model_product
access_product_category_pos_manager,pos.category manager,model_pos_category,group_pos_manager,1,1,1,"1"""
access_product_category_pos_user,pos.category user,model_pos_category,group_pos_user,1,0,0,"0"""
access_pos_session_user,pos.session user,model_pos_session,group_pos_user,1,1,1,0
access_pos_config_user,pos.config user,model_pos_config,group_pos_user,1,1,1,0
access_pos_config_user,pos.config user,model_pos_config,group_pos_user,1,1,1,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
access_pos_config_journal pos.config.journal model_pos_config_journal group_pos_user 1 0 0 0
2 access_pos_order pos.order model_pos_order group_pos_user 1 1 1 1
3 access_pos_order_line pos.order.line model_pos_order_line group_pos_user 1 1 1 1
4 access_pos_order_manager pos.order manager model_pos_order group_pos_manager 1 0 0 0
5 access_pos_order_line_manager pos.order.line manager model_pos_order_line group_pos_manager 1 0 0 0
6 access_report_transaction_pos report.transaction.pos model_report_transaction_pos group_pos_manager 1 1 1 1
access_pos_config_journal_manager pos.config.journal.manager model_pos_config_journal group_pos_manager 1 1 1 1
7 access_account_journal_pos_user account.journal pos_user account.model_account_journal group_pos_user 1 0 0 0
8 access_account_move_pos_user account.move pos_user account.model_account_move group_pos_user 1 1 1 0
9 access_account_account_pos_user account.account pos_user account.model_account_account group_pos_user 1 0 0 0
64 access_product_category_pos_manager pos.category manager model_pos_category group_pos_manager 1 1 1 1"
65 access_product_category_pos_user pos.category user model_pos_category group_pos_user 1 0 0 0"
66 access_pos_session_user pos.session user model_pos_session group_pos_user 1 1 1 0
67 access_pos_config_user pos.config user model_pos_config group_pos_user 1 1 1 0

View File

@ -793,6 +793,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.build_widgets();
instance.webclient.set_content_full_screen(true);
if (self.pos.get('account_journals').length === 0) {
// TODO: Create a popup to inform there is no PoSSession for this user
self.pos.screen_selector.show_popup('error');
}
}, this));
},

View File

@ -30,7 +30,7 @@ import pos_receipt
import pos_payment_report_user
import pos_payment_report
import pos_payment
import pos_session_opening
import pos_box
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -69,7 +69,6 @@ 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.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),

View File

@ -25,6 +25,7 @@
</field>
</record>
<!--
<act_window name="Close Statements"
res_model="pos.close.statement"
src_model="account.bank.statement"
@ -32,6 +33,7 @@
target="new"
key2="client_action_multi"
id="act_pos_open_statement"/>
-->
<record id="action_pos_close_statement" model="ir.actions.act_window">
<field name="name">Close Cash Register</field>

View File

@ -23,7 +23,7 @@
</form>
</field>
</record>
<!--
<record id="action_pos_confirm" model="ir.actions.act_window">
<field name="name">Post Sale Entries</field>
<field name="type">ir.actions.act_window</field>
@ -32,6 +32,7 @@
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
-->
</data>
</openerp>

View File

@ -0,0 +1,76 @@
#!/usr/bin/env python
from osv import osv, fields
from tools.translate import _
import netsvc
class pos_session_opening(osv.osv_memory):
_name = 'pos.session.opening'
_columns = {
'pos_config_id' : fields.many2one('pos.config', 'Point of Sale', required=True),
'pos_session_id' : fields.many2one('pos.session', 'PoS Session'),
}
def open_session_cb(self, cr, uid, ids, context=None):
assert len(ids) == 1, "you can open only one session at a time"
proxy = self.pool.get('pos.session')
wizard = self.browse(cr, uid, ids[0], context=context)
if not wizard.pos_session_id:
values = {
'user_id' : uid,
'config_id' : wizard.pos_config_id.id,
}
session_id = proxy.create(cr, uid, values, context=context)
if all(journal.opening_control == False
for journal in wizard.pos_config_id.journal_ids):
wkf_service = netsvc.LocalService('workflow')
wkf_service.trg_validate(uid, 'pos.session', session_id, 'open', cr)
return self._open_session(session_id)
return self._open_session(wizard.pos_session_id.id)
def open_existing_session_cb(self, cr, uid, ids, context=None):
assert len(ids) == 1
wizard = self.browse(cr, uid, ids[0], context=context)
return self._open_session(wizard.pos_session_id.id)
def _open_session(self, session_id):
return {
'name': _('Session'),
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'pos.session',
'res_id': session_id,
'view_id': False,
'type': 'ir.actions.act_window',
}
def on_change_config(self, cr, uid, ids, config_id, context=None):
if not config_id:
return {}
proxy = self.pool.get('pos.session')
session_ids = proxy.search(cr, uid, [
('state', '<>', 'closed'),
('config_id', '=', config_id),
], context=context)
return {
'value' : {
'pos_session_id' : session_ids and session_ids[0] or False,
}
}
def default_get(self, cr, uid, fieldnames, context=None):
so = self.pool.get('pos.session')
session_ids = so.search(cr, uid, [('state','<>','closed'), ('user_id','=',uid)], context=context)
if session_ids:
result = so.browse(cr, uid, session_ids[0], context=context).config_id.id
else:
current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
result = current_user.pos_config and current_user.pos_config.id or False
return {
'pos_config_id' : result,
'pos_session_id': session_ids and session_ids[0] or False
}
pos_session_opening()

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="pos_session_opening_form_view">
<field name="name">pos.session.opening.form.view</field>
<field name="model">pos.session.opening</field>
<field name="arch" type="xml">
<form string="PoS Session Opening" layout="auto">
<separator string="Select your Point of Sale" colspan="4" />
<field name="pos_config_id" on_change="on_change_config(pos_config_id)" widget="selection" domain="[('state','=','active')]"/>
<field name="pos_session_id" invisible="1"/>
<group colspan="4">
<button special="cancel" icon="gtk-cancel" string="Cancel" />
<button name="open_existing_session_cb" type="object" string="Open Session" icon="gtk-ok"
attrs="{'invisible' : [('pos_session_id', '=', False)]}"
/>
<button name="open_session_cb" type="object" string="New Session" icon="gtk-ok"
attrs="{'invisible' : [('pos_session_id', '&lt;&gt;', False)]}"
/>
</group>
</form>
</field>
</record>
<record id="action_pos_session_opening" model="ir.actions.act_window">
<field name="name">Open/Close a Session</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.session.opening</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -283,7 +283,7 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<group name="misc" position="after">
<group col="2" colspan="2" attrs="{'invisible':[('type', '=', 'service')]}">
<group col="2" colspan="4" attrs="{'invisible':[('type', '=', 'service')]}">
<separator string="Minimum Stock Rules" colspan="2"/>
<field name="orderpoint_ids" context="{'default_product_uom': uom_id}" nolabel="1">
<tree string="Minimum Stock Rule" editable="bottom">