Further progress : Help Popup, Weighting

bzr revid: fva@openerp.com-20120506213439-0met6jzt93r5thry
This commit is contained in:
Frédéric van der Essen 2012-05-06 23:34:39 +02:00
commit b8427b9a85
40 changed files with 2406 additions and 247 deletions

View File

@ -100,6 +100,7 @@ module named account_voucher.
'wizard/account_reconcile_partner_process_view.xml',
'wizard/account_automatic_reconcile_view.xml',
'wizard/account_financial_report_view.xml',
'wizard/pos_box.xml',
'project/wizard/project_account_analytic_line_view.xml',
'account_end_fy.xml',
'account_invoice_view.xml',
@ -145,8 +146,8 @@ module named account_voucher.
'test/account_use_model.yml',
'test/account_validate_account_move.yml',
'test/account_fiscalyear_close.yml',
'test/account_bank_statement.yml',
'test/account_cash_statement.yml',
#'test/account_bank_statement.yml',
#'test/account_cash_statement.yml',
'test/test_edi_invoice.yml',
'test/account_report.yml',
'test/account_fiscalyear_close_state.yml', #last test, as it will definitively close the demo fiscalyear

View File

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

View File

@ -26,24 +26,18 @@ from tools.translate import _
import decimal_precision as dp
class account_bank_statement(osv.osv):
def create(self, cr, uid, vals, context=None):
seq = 0
if 'line_ids' in vals:
new_line_ids = []
for line in vals['line_ids']:
seq += 1
line[2]['sequence'] = seq
for idx, line in enumerate(vals['line_ids']):
line[2]['sequence'] = idx + 1
return super(account_bank_statement, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):
res = super(account_bank_statement, self).write(cr, uid, ids, vals, context=context)
account_bank_statement_line_obj = self.pool.get('account.bank.statement.line')
for statement in self.browse(cr, uid, ids, context):
seq = 0
for line in statement.line_ids:
seq += 1
account_bank_statement_line_obj.write(cr, uid, [line.id], {'sequence': seq}, context=context)
for idx, line in enumerate(statement.line_ids):
account_bank_statement_line_obj.write(cr, uid, [line.id], {'sequence': idx + 1}, context=context)
return res
def _default_journal_id(self, cr, uid, context=None):
@ -51,13 +45,12 @@ class account_bank_statement(osv.osv):
context = {}
journal_pool = self.pool.get('account.journal')
journal_type = context.get('journal_type', False)
journal_id = False
company_id = self.pool.get('res.company')._company_default_get(cr, uid, 'account.bank.statement',context=context)
if journal_type:
ids = journal_pool.search(cr, uid, [('type', '=', journal_type),('company_id','=',company_id)])
if ids:
journal_id = ids[0]
return journal_id
return ids[0]
return False
def _end_balance(self, cursor, user, ids, name, attr, context=None):
res_currency_obj = self.pool.get('res.currency')
@ -379,14 +372,22 @@ class account_bank_statement(osv.osv):
account_move_obj.unlink(cr, uid, ids, context)
done.append(st.id)
return self.write(cr, uid, done, {'state':'draft'}, context=context)
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
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()
balance_start = res and res[0] or 0.0
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):
balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context)
journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['default_debit_account_id', 'company_id'], context=context)
account_id = journal_data['default_debit_account_id']
company_id = journal_data['company_id']

View File

@ -43,24 +43,27 @@ class account_cashbox_line(osv.osv):
"""
res = {}
for obj in self.browse(cr, uid, ids, context=context):
res[obj.id] = obj.pieces * obj.number
res[obj.id] = {
'subtotal_opening' : obj.pieces * obj.number_opening,
'subtotal_closing' : obj.pieces * obj.number_closing,
}
return res
def on_change_sub(self, cr, uid, ids, pieces, number, *a):
def on_change_sub_opening(self, cr, uid, ids, pieces, number, *a):
""" Compute the subtotal for the opening """
return {'value' : {'subtotal_opening' : (pieces * number) or 0.0 }}
""" Calculates Sub total on change of number
@param pieces: Names of fields.
@param number:
"""
sub = pieces * number
return {'value': {'subtotal': sub or 0.0}}
def on_change_sub_closing(self, cr, uid, ids, pieces, number, *a):
""" Compute the subtotal for the closing """
return {'value' : {'subtotal_closing' : (pieces * number) or 0.0 }}
_columns = {
'pieces': fields.float('Values', digits_compute=dp.get_precision('Account')),
'number': fields.integer('Number'),
'subtotal': fields.function(_sub_total, string='Sub Total', type='float', digits_compute=dp.get_precision('Account')),
'starting_id': fields.many2one('account.bank.statement', ondelete='cascade'),
'ending_id': fields.many2one('account.bank.statement', ondelete='cascade'),
'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'),
'bank_statement_id' : fields.many2one('account.bank.statement', ondelete='cascade'),
}
account_cashbox_line()
@ -78,16 +81,14 @@ class account_cash_statement(osv.osv):
"""
res = {}
for statement in self.browse(cr, uid, ids, context=context):
amount_total = 0.0
if statement.journal_id.type not in('cash'):
continue
for line in statement.starting_details_ids:
amount_total+= line.pieces * line.number
res[statement.id] = {
'balance_start': amount_total
'balance_start': sum((line.pieces * line.number_opening
for line in statement.details_ids), 0.0)
}
print "_get_starting_balance: %r" % (res,)
return res
def _balance_end_cash(self, cr, uid, ids, name, arg, context=None):
@ -98,10 +99,9 @@ class account_cash_statement(osv.osv):
"""
res = {}
for statement in self.browse(cr, uid, ids, context=context):
amount_total = 0.0
for line in statement.ending_details_ids:
amount_total += line.pieces * line.number
res[statement.id] = amount_total
res[statement.id] = sum((line.pieces * line.number_closing
for line in statement.details_ids), 0.0)
print "_balance_end_cash: %r" % (res,)
return res
def _get_sum_entry_encoding(self, cr, uid, ids, name, arg, context=None):
@ -111,13 +111,11 @@ class account_cash_statement(osv.osv):
@param arg: User defined arguments
@return: Dictionary of values.
"""
res2 = {}
res = {}
for statement in self.browse(cr, uid, ids, context=context):
encoding_total=0.0
for line in statement.line_ids:
encoding_total += line.amount
res2[statement.id] = encoding_total
return res2
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):
user_pool = self.pool.get('res.users')
@ -190,33 +188,84 @@ class account_cash_statement(osv.osv):
result[line.statement_id.id] = True
return result.keys()
def _compute_difference(self, cr, uid, ids, fieldnames, args, context=None):
result = dict.fromkeys(ids, 0.0)
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = obj.balance_end - obj.balance_end_cash
return result
_columns = {
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Cash Transaction", help="Total cash transactions",
store = {
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids'], 10),
'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),
}),
'closing_date': fields.datetime("Closed On"),
'balance_end_cash': fields.function(_balance_end_cash, store=True, string='Closing Balance', help="Closing balance based on cashBox"),
'starting_details_ids': fields.one2many('account.cashbox.line', 'starting_id', string='Opening Cashbox'),
'ending_details_ids': fields.one2many('account.cashbox.line', 'ending_id', string='Closing Cashbox'),
'balance_end_cash': fields.function(_balance_end_cash, store=False, string='Closing Balance', help="Closing balance based on cashBox"),
'details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='CashBox Lines'),
'user_id': fields.many2one('res.users', 'Responsible', required=False),
'difference' : fields.function(_compute_difference, method=True, string="Difference", type="float"),
}
_defaults = {
'state': 'draft',
'date': lambda self,cr,uid,context={}: context.get('date', time.strftime("%Y-%m-%d %H:%M:%S")),
'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,
'starting_details_ids': _get_cash_open_box_lines,
'ending_details_ids': _get_default_cash_close_box_lines
}
}
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('starting_details_ids',[]):
for line in vals.get('details_ids',[]):
print "line: %r" % (line,)
if line and len(line)==3 and line[2]:
amount_total+= line[2]['pieces'] * line[2]['number']
# FIXME: If there is no piece # does not work with GTK
amount_total+= line[2].get('pieces', 0) * line[2]['number_opening']
vals.update(balance_start= amount_total)
vals.update(balance_end_real=self._compute_balance_end_real(cr, uid, vals['journal_id'], context=context))
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)
def write(self, cr, uid, ids, vals, context=None):
@ -245,19 +294,43 @@ class account_cash_statement(osv.osv):
@param journal_id: Changed journal_id
@return: Dictionary of changed values
"""
res = {}
balance_start = 0.0
if not journal_id:
res.update({
'balance_start': balance_start
})
return res
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})
statement.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
@ -317,16 +390,64 @@ class account_cash_statement(osv.osv):
def button_confirm_cash(self, cr, uid, ids, context=None):
super(account_cash_statement, self).button_confirm_bank(cr, uid, ids, context=context)
absl_proxy = self.pool.get('account.bank.statement.line')
TABLES = (('Profit', 'profit_account_id'), ('Loss', 'loss_account_id'),)
for obj in self.browse(cr, uid, ids, context=context):
if obj.difference == 0.0:
continue
for item_label, item_account in TALBES:
if getattr(obj.journal_id, item_account):
raise osv.except_osv(_('Error !'),
_('There is no %s Account on the Journal %s') % (item_label, obj.journal_id.name,))
is_profit = obj.difference < 0.0
account = getattr(obj.journal_id, TABLES[is_profit][1])
values = {
'statement_id' : obj.id,
'journal_id' : obj.journal_id.id,
'account_id' : account.id,
'amount' : obj.difference,
'name' : 'Exceptional %s' % TABLES[is_profit][0],
}
absl_proxy.create(cr, uid, values, context=context)
return self.write(cr, uid, ids, {'closing_date': time.strftime("%Y-%m-%d %H:%M:%S")}, context=context)
def button_cancel(self, cr, uid, ids, context=None):
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.ending_details_ids:
cash_box_line_pool.write(cr, uid, [end.id], {'number': 0})
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):
_inherit = 'account.journal'
_columns = {
'cashbox_line_ids' : fields.one2many('account.journal.cashbox.line', 'journal_id', 'CashBox'),
}
account_journal()
class account_journal_cashbox_line(osv.osv):
_name = 'account.journal.cashbox.line'
_rec_name = 'value'
_columns = {
'pieces': fields.float('Values', digits_compute=dp.get_precision('Account')),
'journal_id' : fields.many2one('account.journal', 'Journal', required=True, select=1),
}
_order = 'pieces asc'
account_journal_cashbox_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -504,6 +504,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">
<field name="profit_account_id" />
<field name="loss_account_id" />
<separator string="Internal Account" colspan="4" />
<field name="internal_account_id" />
<separator string="Cash Box Lines" colspan="4" />
<field name="cashbox_line_ids" nolabel="1" string="Unit Of Currency Definition" colspan="4">
<tree string="CashBox Lines" editable="bottom">
<field name="pieces" />
</tree>
</field>
<label string="The Cashbox Lines will be used in the PoS Session" />
</page>
</notebook>
</form>
</field>
@ -2597,7 +2610,7 @@ action = pool.get('res.config').next(cr, uid, [], context)
<field name="journal_id"/>
<field name="balance_start"/>
<field name="balance_end_real"/>
<field name="balance_end"/>
<field name="balance_end" invisible="1" />
<field name="state"/>
<button type="object" string="Cancel" name="button_cancel" states="confirm" icon="gtk-cancel"/>
<button type="object" string="Open" name="button_open" states="draft" icon="terp-camera_test"/>
@ -2615,7 +2628,7 @@ action = pool.get('res.config').next(cr, uid, [], context)
<group col="6" colspan="4">
<field name="name" select="1"/>
<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"/>
<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"/>
<field name="period_id" select="1"/>
<field name="currency" invisible="1"/>
@ -2651,32 +2664,16 @@ action = pool.get('res.config').next(cr, uid, [], context)
</field>
</page>
<page string="CashBox">
<group col="2" colspan="2" expand="1">
<field name="starting_details_ids" nolabel="1" colspan="2" attrs="{'readonly':[('state','!=','draft')]}">
<tree string = "Opening Balance" editable="bottom">
<field name="pieces"/>
<field name="number" on_change="on_change_sub(pieces,number, parent.balance_end)"/>
<field name="subtotal" sum="Total"/>
<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="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')]}"/>
<field name="subtotal_closing" string="Closing Subtotal"/>
</tree>
<form string = "Opening Balance">
<field name="pieces"/>
<field name="number" on_change="on_change_sub(pieces,number, parent.balance_end)"/>
<field name="subtotal"/>
</form>
</field>
</group>
<group col="2" colspan="2" expand="1">
<field name="ending_details_ids" nolabel="1" colspan="2" attrs="{'readonly':[('state','!=','open')]}">
<tree string = "Closing Balance" editable="bottom">
<field name="pieces"/>
<field name="number" on_change="on_change_sub(pieces,number, parent.balance_end)"/>
<field name="subtotal" sum="Total"/>
</tree>
<form string = "Closing Balance">
<field name="pieces"/>
<field name="number" on_change="on_change_sub(pieces,number, parent.balance_end)"/>
<field name="subtotal"/>
</form>
</field>
</group>
</page>
@ -2687,18 +2684,20 @@ action = pool.get('res.config').next(cr, uid, [], context)
<group col="6" colspan="4">
<group col="2" colspan="2">
<separator string="Dates" colspan="4"/>
<field name="date" select="1" attrs="{'readonly':[('state','!=','draft')]}" on_change="onchange_date(date, company_id)"/>
<field name="date" select="1" attrs="{'readonly':[('state','!=','draft')]}" on_change="onchange_date(date, company_id)" string="Started On" />
<field name="closing_date" select="1" readonly="1"/>
</group>
<group col="2" colspan="2">
<separator string="Opening Balance" colspan="4"/>
<field name="balance_start" readonly="1" string="Opening Balance"/>
<field name="total_entry_encoding"/>
<field name="balance_end_real" readonly="1" string="Last Closing Balance"/>
<field name="balance_start" readonly="1" string="Computed Amount"/>
<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" />
</group>
</group>
<group col="8" colspan="4">

View File

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

View File

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

View File

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

View File

@ -24,5 +24,7 @@ import account_bank_statement
import wizard
import report
import controllers
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -51,14 +51,13 @@ Main features :
'wizard/pos_discount.xml',
'wizard/pos_open_statement.xml',
'wizard/pos_close_statement.xml',
'wizard/pos_box_entries.xml',
'wizard/pos_payment_report_user_view.xml',
'wizard/pos_box_out.xml',
'wizard/pos_sales_user.xml',
'wizard/pos_receipt_view.xml',
'wizard/pos_payment_report_user.xml',
'wizard/pos_payment_report.xml',
'wizard/pos_payment.xml',
'wizard/pos_box.xml',
'point_of_sale_report.xml',
'point_of_sale_view.xml',
'report/pos_order_report_view.xml',
@ -92,5 +91,6 @@ Main features :
],
'css': ['static/src/css/pos.css'],
'qweb': ['static/src/xml/pos.xml'],
'auto_install': True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -25,13 +25,15 @@ from osv import fields, osv
class account_journal(osv.osv):
_inherit = 'account.journal'
_columns = {
'auto_cash': fields.boolean('Automatic Opening', help="This field authorize the automatic creation of the cashbox, without control of the initial balance."),
'check_dtls': fields.boolean('Control Balance Before Closing', help="This field authorize Validation of Cashbox without controlling the closing balance."),
'journal_user': fields.boolean('PoS Payment Method', help="Check this box if this journal define a payment method that can be used in point of sales."),
'opening_control': fields.boolean('Opening Control', 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"),
}
_defaults = {
'check_dtls': False,
'auto_cash': True,
'opening_control' : True,
'closing_control' : True,
}
account_journal()
@ -39,14 +41,14 @@ 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 _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)

View File

@ -12,8 +12,8 @@
<group col="6" colspan="4">
<separator colspan="6" string="Extended Configuration"/>
<field name="journal_user"/>
<field name="auto_cash"/>
<field name="check_dtls"/>
<field name="opening_control" />
<field name="closing_control" />
</group>
</page>
</xpath>

View File

@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
import logging
try:
import openerp.addons.web.common.http as openerpweb
except ImportError:
import web.common.http as openerpweb
class PointOfSaleController(openerpweb.Controller):
_cp_path = '/pos'
@openerpweb.jsonrequest
def dispatch(self, request, iface, **kwargs):
method = 'iface_%s' % iface
return getattr(self, method)(request, **kwargs)
def iface_light(self, request, status):
return True
@openerpweb.jsonrequest
def scan_item_success(self, request):
"""
A product has been scanned with success
"""
return False
@openerpweb.jsonrequest
def scan_item_error_unrecognized(self, request):
"""
A product has been scanned without success
"""
return False
@openerpweb.jsonrequest
def do_help(self, request, status):
if status == 1:
return help_needed(request)
else:
return help_cancelled(request)
@openerpweb.jsonrequest
def help_needed(self, request):
"""
The user wants an help (ex: light is on)
"""
return self.signal_help(request, status=True)
@openerpweb.jsonrequest
def help_cancelled(self, request):
"""
The user stops the help request
"""
return self.signal_help(request, status=False)
#@openerpweb.jsonrequest
#def weighting_start(self, request):
# return False
#@openerpweb.jsonrequest
#def weighting_read_kg(self, request):
# return 0.0
#@openerpweb.jsonrequest
#def weighting_end(self, request):
# return False
#openerpweb.jsonrequest
def do_weighting(self, request):
# Start the weighting
# Wait for 10 sec
# IDEA: Thread, Signal ?
# return a dict with the value or the error
return {'weight' : 0.5}
def do_payment(self, request, price, method, info):
#return {'status' : 'ACCEPTED', 'reason' : ''}
return {'status' : 'REFUSED', 'reason' : 'Payment blocked'}
#@openerpweb.jsonrequest
#def payment_request(self, request, price, method, info):
# """
# The PoS will activate the method payment
# """
# return False
#@openerpweb.jsonrequest
#def is_payment_accepted(self, request):
# return False
#@openerpweb.jsonrequest
#def payment_cancelled(self, request):
# return False
@openerpweb.jsonrequest
def transaction_start(self, request):
return False
@openerpweb.jsonrequest
def transaction_end(self, request):
return False
@openerpweb.jsonrequest
def cashier_mode_activated(self, request):
return False
@openerpweb.jsonrequest
def cashier_mode_deactivated(self, request):
return False

View File

@ -33,6 +33,244 @@ import decimal_precision as dp
_logger = logging.getLogger(__name__)
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),
'journal_ids' : fields.many2many('account.journal', 'pos_config_journal_rel', 'pos_config_id', 'journal_id', 'Payment Methods', domain="[('journal_user', '=', True )]"),
'shop_id' : fields.many2one('sale.shop', 'Shop', required=True, select=1),
'journal_id' : fields.many2one('account.journal', 'Journal', required=True, select=1, domain=[('type', '=', 'sale')]),
'profit_account_id' : fields.many2one('account.account', 'Profit Account', required=True, select=1),
'loss_account_id' : fields.many2one('account.account', 'Loss Account', required=True, select=1),
'authorized_cashbox_diff' : fields.integer('Authorized Cashbox Difference (%)'),
'authorized_cashbox_diff_fixed' : fields.integer('Authorized Cashbox Difference (Fixed Amount)'),
'iface_self_checkout' : fields.boolean('Self Checkout Mode'),
'iface_websql' : fields.boolean('WebSQL (to store data)'),
'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'),
'state' : fields.selection(POS_CONFIG_STATE, 'State', required=True, readonly=True),
'sequence_id' : fields.many2one('ir.sequence', 'Sequence', readonly=True),
# Add a sequence when we create a new pos.config object
'user_id' : fields.many2one('res.users', 'User'),
}
_defaults = {
'state' : 'draft',
'user_id' : lambda obj, cr, uid, context: uid,
}
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)
def set_inactive(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'inactive'}, context=context)
def set_deprecate(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'deprecated'}, context=context)
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'],
)
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'
POS_SESSION_STATE = [('new', 'New'),('opened', 'Opened'),('closed', 'Closed'),('posted', 'Posted')]
_columns = {
'config_id' : fields.many2one('pos.config', 'PoS', required=True, select=1, domain="[('state', '=', 'active')]"),
'name' : fields.char('Session Sequence', size=32, required=True, select=1, readonly=1),
'user_id' : fields.many2one('res.users', 'User', required=True, select=1),
'start_at' : fields.datetime('Opening Date'), #, readonly=True),
'stop_at' : fields.datetime('Closing Date'),
'state' : fields.selection(POS_SESSION_STATE, 'State', required=True, readonly=True, select=1),
'cash_register_id' : fields.many2one('account.bank.statement', 'Bank Account Statement'),
'details_ids' : fields.related('cash_register_id', 'details_ids',
type='one2many', relation='account.cashbox.line',
string='CashBox Lines'),
}
_defaults = {
'name' : '/',
'user_id' : lambda obj, cr, uid, context: uid,
'state' : 'new',
}
_sql_constraints = [
('uniq_name', 'unique(name)', "The name of this POS Session must be unique !"),
]
def _create_cash_register(self, cr, uid, pos_config, name, context=None):
if not pos_config:
return False
proxy = self.pool.get('account.bank.statement')
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 = {
'name' : name,
'journal_id' : journal_id,
}
cash_register_id = proxy.create(cr, uid, values, context=context)
return cash_register_id
def create(self, cr, uid, values, context=None):
config_id = values.get('config_id', False) or False
if config_id:
pos_config = self.pool.get('pos.config').browse(cr, uid, config_id, context=context)
name = pos_config.sequence_id._next()
values.update(
name=name,
cash_register_id=self._create_cash_register(cr, uid, pos_config, name, context=context),
)
else:
raise osv.except_osv(_('Error!'), _('There is no POS Config attached to this POS Session'))
return super(pos_session, self).create(cr, uid, values, context=context)
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):
values = {}
if not record.start_at:
values['start_at'] = time.strftime('%Y-%m-%d %H:%M:%S')
values['state'] = 'opened'
record.write(values, context=context)
return True
def wkf_action_close(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'close', 'stop_at' : time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
def wkf_action_post(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'post'}, context=context)
def get_current_session(self, cr, uid, context=None):
current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
domain = [
('state', '=', 'open'),
('start_at', '>=', time.strftime('%Y-%m-%d 00:00:00')),
('config_id.user_id', '=', uid),
]
session_ids = self.search(cr, uid, domain, context=context, limit=1, order='start_at desc')
session_id = session_ids[0] if session_ids else False
if not session_id:
pos_config_proxy = self.pool.get('pos.config')
pos_config_ids = pos_config_proxy.search(cr, uid, [('user_id', '=', uid),('state', '=', 'active')], limit=1, order='create_date desc')
if not pos_config_ids:
raise osv.except_osv(_('Error !'),
_('There is no active PoS Config for this User %s') % current_user.name)
config = pos_config_proxy.browse(cr, uid, pos_config_ids[0], context=context)
values = {
'state' : 'draft',
'start_at' : time.strftime('%Y-%m-%d %H:%M:%S'),
'config_id' : config.id,
'journal_id' : config.journal_id.id,
'user_id': current_user.id,
}
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)
return session_id
pos_session()
class pos_config_journal(osv.osv):
""" Point of Sale journal configuration"""
_name = 'pos.config.journal'
@ -54,6 +292,7 @@ class pos_order(osv.osv):
def create_from_ui(self, cr, uid, orders, context=None):
#_logger.info("orders: %r", orders)
list = []
session_id = self.pool.get('pos.session').get_current_session()
for order in orders:
# order :: {'name': 'Order 1329148448062', 'amount_paid': 9.42, 'lines': [[0, 0, {'discount': 0, 'price_unit': 1.46, 'product_id': 124, 'qty': 5}], [0, 0, {'discount': 0, 'price_unit': 0.53, 'product_id': 62, 'qty': 4}]], 'statement_ids': [[0, 0, {'journal_id': 7, 'amount': 9.42, 'name': '2012-02-13 15:54:12', 'account_id': 12, 'statement_id': 21}]], 'amount_tax': 0, 'amount_return': 0, 'amount_total': 9.42}
order_obj = self.pool.get('pos.order')
@ -131,8 +370,7 @@ class pos_order(osv.osv):
return super(pos_order, self).copy(cr, uid, id, d, context=context)
_columns = {
'name': fields.char('Order Ref', size=64, required=True,
states={'draft': [('readonly', False)]}, readonly=True),
'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),
@ -147,6 +385,13 @@ class pos_order(osv.osv):
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', required=True, states={'draft': [('readonly', False)]}, readonly=True),
'partner_id': fields.many2one('res.partner', 'Customer', change_default=True, select=1, states={'draft': [('readonly', False)], 'paid': [('readonly', False)]}),
'session_id' : fields.many2one('pos.session', 'Session',
#required=True,
select=1,
domain="[('state', '=', 'opened')]",
states={'draft' : [('readonly', False)]},
readonly=True),
'state': fields.selection([('draft', 'New'),
('cancel', 'Cancelled'),
('paid', 'Paid'),
@ -172,7 +417,7 @@ class pos_order(osv.osv):
_defaults = {
'user_id': lambda self, cr, uid, context: uid,
'state': 'draft',
'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'pos.order'),
'name': '/',
'date_order': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'nb_print': 0,
'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
@ -181,6 +426,10 @@ class pos_order(osv.osv):
'pricelist_id': _default_pricelist,
}
def create(self, cr, uid, values, context=None):
values['name'] = self.pool.get('ir.sequence').get(cr, uid, 'pos.order')
return super(pos_order, self).create(cr, uid, values, context=context)
def test_paid(self, cr, uid, ids, context=None):
"""A Point of Sale is paid when the sum
@return: True
@ -248,7 +497,7 @@ class pos_order(osv.osv):
if not len(ids):
return False
for order in self.browse(cr, uid, ids, context=context):
if order.state<>'cancel':
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")
@ -442,7 +691,8 @@ class pos_order(osv.osv):
property_obj=self.pool.get('ir.property')
for order in self.browse(cr, uid, ids, context=context):
if order.state<>'paid': continue
if order.state != 'paid':
continue
curr_c = res_obj.browse(cr, uid, uid).company_id
comp_id = res_obj.browse(cr, order.user_id.id, order.user_id.id).company_id
@ -455,6 +705,7 @@ class pos_order(osv.osv):
# Create an entry for the sale
move_id = account_move_obj.create(cr, uid, {
'ref' : order.name,
'journal_id': order.sale_journal.id,
}, context=context)
@ -502,10 +753,9 @@ class pos_order(osv.osv):
if tax_code_id:
break
# Create a move for the line
account_move_line_obj.create(cr, uid, {
'name': line.name,
'name': line.product_id.name,
'date': order.date_order[:10],
'ref': order.name,
'quantity': line.qty,
@ -534,7 +784,7 @@ class pos_order(osv.osv):
continue
account_move_line_obj.create(cr, uid, {
'name': "Tax" + line.name,
'name': "Tax" + line.name + " (%s)" % (tax.name),
'date': order.date_order[:10],
'ref': order.name,
'product_id':line.product_id.id,
@ -573,7 +823,7 @@ class pos_order(osv.osv):
# counterpart
to_reconcile.append(account_move_line_obj.create(cr, uid, {
'name': order.name,
'name': "Trade Receivables", #order.name,
'date': order.date_order[:10],
'ref': order.name,
'move_id': move_id,
@ -587,6 +837,7 @@ class pos_order(osv.osv):
'period_id': period,
'partner_id': order.partner_id and order.partner_id.id or False
}, context=context))
self.write(cr, uid, order.id, {'state':'done', 'account_move': move_id}, context=context)
return True
@ -594,8 +845,7 @@ class pos_order(osv.osv):
return self.write(cr, uid, ids, {'state': 'payment'}, context=context)
def action_paid(self, cr, uid, ids, context=None):
context = context or {}
self.create_picking(cr, uid, ids, context=None)
self.create_picking(cr, uid, ids, context=context)
self.write(cr, uid, ids, {'state': 'paid'}, context=context)
return True

View File

@ -134,6 +134,7 @@
<field name="location_dest_id" ref="stock.stock_location_customers"/>
<field name="picking_id" ref="stock_picking_out0"/>
</record>
<!--
<record id="pos_order_line_orderline0" model="pos.order.line">
<field name="notice">No Discount</field>
<field name="product_id" ref="product.product_product_pc1"/>
@ -143,6 +144,7 @@
<field eval="1.0" name="qty"/>
<field name="name">Order Line/07</field>
</record>
-->
<!--Resource: pos.order-->

View File

@ -28,5 +28,17 @@
<field name="padding">4</field>
</record>
<record model="ir.sequence.type" id="seq_type_pos_session">
<field name="name">POS Session</field>
<field name="code">pos.session</field>
</record>
<record model="ir.sequence" id="seq_pos_session">
<field name="name">POS Session</field>
<field name="code">pos.session</field>
<field name="prefix">POS/%(day)s/(month)s/%(year)s/</field>
<field name="padding">4</field>
</record>
</data>
</openerp>

View File

@ -18,6 +18,7 @@
<field name="arch" type="xml">
<form string="PoS Orders">
<group col="7" colspan="4">
<field name="session_id" required="1" />
<field name="name"/>
<field name="date_order"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_customer':1}" attrs="{'readonly': [('state','=','invoiced')]}"/>
@ -54,7 +55,7 @@
<separator colspan="4"/>
<group colspan="4" col="8">
<field name="state" widget="statusbar" statusbar_visible="draft,paid,done" statusbar_colors='{"cancel":"red"}'/>
<button name="%(action_pos_payment)d" string="Payment" icon="gtk-apply" type="action" states="draft"/>
<button name="%(action_pos_payment)d" string="Payment" icon="gtk-apply" type="action" states="draft" context="{'pos_session_id' : session_id}"/>
<button name="refund" string="Return Products" type="object" icon="gtk-ok"
attrs="{'invisible':[('state','=','draft')]}"/>
<button name="%(action_report_pos_receipt)d" string="Reprint" icon="gtk-print" type="action" states="paid,done,invoiced"/>
@ -670,46 +671,6 @@
<menuitem name="Configuration" parent="menu_point_root"
id="menu_point_config_product" sequence="25" groups="group_pos_manager"/>
<record model="ir.actions.act_window" id="action_product_input">
<field name="name">Products 'Take Money Out'</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.product</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('expense_pdt','=',True)]</field>
<field name="context">{'default_expense_pdt': True}</field>
</record>
<menuitem
parent="menu_point_config_product"
action="action_product_input"
id="products_for_input_operations"
groups="group_pos_manager"/>
<record model="ir.actions.act_window" id="action_product_output">
<field name="name">Products 'Put Money In'</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.product</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('income_pdt','=',True)]</field>
<field name="context">{'default_income_pdt': True}</field>
</record>
<menuitem
parent="menu_point_config_product"
action="action_product_output"
id="products_for_output_operations"
groups="group_pos_manager"/>
<menuitem
parent="menu_point_of_sale"
action="action_box_entries"
id="menu_wizard_enter_jrnl" sequence="2" />
<menuitem
parent="menu_point_of_sale"
action="action_box_out"
id="menu_wizard_enter_jrnl2" sequence="3" />
<record id="action_account_journal_form" model="ir.actions.act_window">
<field name="name">Payment Methods</field>
<field name="res_model">account.journal</field>
@ -776,8 +737,8 @@
id="menu_pos_details" parent="menu_point_of_sale_reporting" sequence="6" />
<record model="ir.actions.client" id="action_pos_pos">
<field name="name">Start Point of Sale</field>
<field name="tag">pos.ui</field>
<field name="name">Start Point of Sale</field>
<field name="tag">pos.ui</field>
</record>
<record id="menu_point_root_touchscreen" model="ir.ui.menu">
@ -790,5 +751,236 @@
<menuitem id="menu_point_root_touchscreen"
web_icon="images/pos.png" web_icon_hover="images/pos-hover.png" groups="point_of_sale.group_pos_manager,point_of_sale.group_pos_user"/>
<record model="ir.ui.view" id="view_pos_config_form">
<field name="name">pos.config.form.view</field>
<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" />
<separator string="Cash Differences" colspan="4" />
<field name="profit_account_id" />
<field name="loss_account_id" />
<field name="authorized_cashbox_diff" />
<field name="authorized_cashbox_diff_fixed" />
</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="Other">
<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"/>
<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>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_pos_config_tree">
<field name="name">pos.config.tree.view</field>
<field name="model">pos.config</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="PoS Configuration">
<field name="name" />
<field name="state" />
</tree>
</field>
</record>
<act_window
id="act_pos_config_sessions"
name="Sessions"
src_model="pos.config"
res_model="pos.session"
domain="[('config_id', '=', active_id)]" />
<record model="ir.actions.act_window" id="action_pos_config_pos">
<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>
<field name="view_mode">tree,form</field>
</record>
<menuitem
parent="menu_point_config_product"
action="action_pos_config_pos"
id="menu_pos_config_pos"
groups="group_pos_manager"/>
<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" />
<field name="name" />
<field name="user_id" />
<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">
<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"/>
</tree>
</field>
</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>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_pos_session_tree">
<field name="name">pos.session.tree.view</field>
<field name="model">pos.session</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="PoS Session">
<field name="config_id" />
<field name="name" />
<field name="user_id" />
<field name="start_at" />
<field name="stop_at" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_pos_session_search">
<field name="name">pos.session.search.view</field>
<field name="model">pos.session</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="PoS Session">
<filter string="Open" domain="[('state', '=', 'opened')]" />
<separator orientation="vertical"/>
<filter string="Today" domain="[('start_at', '>=', time.strftime('%%Y-%%m-%%d 00:00:00'))]" />
<separator orientation="vertical"/>
<field name="config_id" />
<field name="name" />
<field name="user_id" />
<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'}" />
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_pos_session">
<field name="name">Point of Sales Session</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_pos_session_search" />
</record>
<menuitem
parent="menu_point_of_sale"
action="action_pos_session"
id="menu_pos_session"
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)]" />
<!--
TODO
<act_window
id="act_pos_session_statements"
name="Statements"
src_model="pos.session"
res_model="account.bank.statement"
domain="[]" />
-->
<record id="view_pos_order_filter" model="ir.ui.view">
<field name="name">pos.order.list.select</field>
<field name="model">pos.order</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Sales Order">
<filter icon="terp-document-new" string="New" domain="[('state','=','draft')]"/>
<filter icon="gtk-apply" string="Done" domain="[('state','in',('paid','invoiced','done'))]"/>
<separator orientation="vertical"/>
<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"/>
<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'}"/>
<separator string="" orientation="vertical"/>
<filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<separator string="" orientation="vertical"/>
<filter string="Order Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_order'}"/>
</group>
</search>
</field>
</record>
</data>
</openerp>

View File

@ -76,4 +76,62 @@
</data>
<data>
<record model="workflow" id="wkf_pos_session">
<field name="name">POS Session Workflow</field>
<field name="osv">pos.session</field>
<field name="on_create">True</field>
</record>
<!-- Activities -->
<record model="workflow.activity" id="act_new">
<field name="wkf_id" ref="wkf_pos_session"/>
<field name="flow_start">True</field>
<field name="name">new</field>
</record>
<record model="workflow.activity" id="act_open">
<field name="wkf_id" ref="wkf_pos_session"/>
<field name="name">open</field>
<field name="action">wkf_action_open()</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="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"/>
<field name="signal">open</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>
<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>
</data>
</openerp>

View File

@ -375,6 +375,18 @@ body{
-webkit-border-radius: 3px;
border-radius: 3px;
}
.point-of-sale .price-subtag {
position: absolute;
top: 24px;
right: 2px;
vertical-align: top;
color: white;
background: #7f82ac;
padding: 2px 5px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
.point-of-sale .product-name {
padding: 3px;
}
@ -504,6 +516,7 @@ body{
margin: 0;
background: #f5f5f5; /*#ebebeb;*/
border-top: solid 1px #afafb6;
z-index:900;
}
.point-of-sale .pos-actionbar ul{
@ -551,6 +564,13 @@ body{
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0), to(#e2e2e2));
-webkit-box-shadow: 0px 2px 2px rgba(0,0,0, 0.3);
}
.point-of-sale .total{
line-height: 105px;
font-size: 26px;
margin: 0;
margin-left: 180px;
font-weight: bold;
}
.point-of-sale .pos-actionbar .button .label{
margin-top: 37px;
}
@ -573,6 +593,78 @@ body{
float:right;
}
.point-of-sale .modal-dialog{
position: absolute;
left: 0;
top: 0;
width: 100%;
height:100%;
background-color: rgba(0,0,0,0.5);
z-index:1000;
}
.point-of-sale .modal-dialog .popup{
position: absolute;
left:50%;
top:50%;
width:500px;
height:400px;
margin-left: -250px;
margin-top: -200px;
padding:10px;
padding-top:20px;
text-align:center;
font-size:20px;
font-weight:bold;
background-color: #F0EEEE;
border: 1px solid #E0DDDD;
-webkit-box-shadow: 0px 10px 20px rgba(0,0,0, 0.3);
z-index:1200;
}
.point-of-sale .popup .footer{
position:absolute;
bottom:0;
left:0;
width:100%;
height:60px;
border-top: 1px solid #E0DDDD;
}
.point-of-sale .popup .button{
float:right;
width: 110px;
height: 40px;
line-height:40px;
text-align:center;
margin:3px;
margin-top:10px;
margin-right:10px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
border: 1px solid #cacaca;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
background: #e2e2e2;
background: -moz-linear-gradient(#f0f0f0, #e2e2e2);
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0), to(#e2e2e2));
-webkit-box-shadow: 0px 2px 2px rgba(0,0,0, 0.3);
}
.point-of-sale .popup .button:hover {
color: white;
background: #7f82ac;
border: 1px solid #7f82ac;
background: -moz-linear-gradient(#9d9fc5, #7f82ac);
background: -webkit-gradient(linear, left top, left bottom, from(#9d9fc5), to(#7f82ac));
-webkit-transition-property: background, border;
-webkit-transition-duration: 0.2s;
-webkit-transition-timing-function: ease-out;
}
/* Onscreen Keyboard http://net.tutsplus.com/tutorials/javascript-ajax/creating-a-keyboard-with-css-and-jquery/ */
.point-of-sale .keyboard_frame{

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,797 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
overflow="visible"
enable-background="new 0 0 128 129.396"
xml:space="preserve"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="go-home.svg"
version="1.0"
inkscape:export-filename="/home/tigert/My Downloads/go-home.png"
inkscape:export-xdpi="90.000000"
inkscape:export-ydpi="90.000000"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata367"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
rdf:resource="http://creativecommons.org/licenses/publicdomain/" /><dc:title></dc:title><dc:creator><cc:Agent><dc:title>Jakub Steiner</dc:title></cc:Agent></dc:creator><dc:source>http://jimmac.musichall.cz</dc:source><dc:subject><rdf:Bag><rdf:li>home</rdf:li><rdf:li>return</rdf:li><rdf:li>go</rdf:li><rdf:li>default</rdf:li><rdf:li>user</rdf:li><rdf:li>directory</rdf:li></rdf:Bag></dc:subject><dc:contributor><cc:Agent><dc:title>Tuomas Kuosmanen</dc:title></cc:Agent></dc:contributor></cc:Work><cc:License
rdf:about="http://creativecommons.org/licenses/publicdomain/"><cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" /><cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" /><cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /></cc:License></rdf:RDF></metadata><defs
id="defs365"><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 24 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="48 : 24 : 1"
inkscape:persp3d-origin="24 : 16 : 1"
id="perspective92" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5060"
id="radialGradient5031"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
cx="605.71429"
cy="486.64789"
fx="605.71429"
fy="486.64789"
r="117.14286" /><linearGradient
inkscape:collect="always"
id="linearGradient5060"><stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop5062" /><stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop5064" /></linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5060"
id="radialGradient5029"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
cx="605.71429"
cy="486.64789"
fx="605.71429"
fy="486.64789"
r="117.14286" /><linearGradient
id="linearGradient5048"><stop
style="stop-color:black;stop-opacity:0;"
offset="0"
id="stop5050" /><stop
id="stop5056"
offset="0.5"
style="stop-color:black;stop-opacity:1;" /><stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop5052" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5048"
id="linearGradient5027"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
x1="302.85715"
y1="366.64789"
x2="302.85715"
y2="609.50507" /><linearGradient
id="linearGradient2406"><stop
style="stop-color:#7c7e79;stop-opacity:1;"
offset="0"
id="stop2408" /><stop
id="stop2414"
offset="0.1724138"
style="stop-color:#848681;stop-opacity:1;" /><stop
style="stop-color:#898c86;stop-opacity:1;"
offset="1"
id="stop2410" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient2390"><stop
style="stop-color:#919191;stop-opacity:1;"
offset="0"
id="stop2392" /><stop
style="stop-color:#919191;stop-opacity:0;"
offset="1"
id="stop2394" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient2378"><stop
style="stop-color:#575757;stop-opacity:1;"
offset="0"
id="stop2380" /><stop
style="stop-color:#575757;stop-opacity:0;"
offset="1"
id="stop2382" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient2368"><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2370" /><stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2372" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient2349"><stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop2351" /><stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop2353" /></linearGradient><linearGradient
id="linearGradient2341"><stop
id="stop2343"
offset="0"
style="stop-color:#000000;stop-opacity:1;" /><stop
id="stop2345"
offset="1"
style="stop-color:#000000;stop-opacity:0;" /></linearGradient><linearGradient
id="linearGradient2329"><stop
style="stop-color:#000000;stop-opacity:0.18556701;"
offset="0"
id="stop2331" /><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop2333" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient2319"><stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop2321" /><stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop2323" /></linearGradient><linearGradient
id="linearGradient2307"><stop
style="stop-color:#edd400;stop-opacity:1;"
offset="0"
id="stop2309" /><stop
style="stop-color:#998800;stop-opacity:1;"
offset="1"
id="stop2311" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient2299"><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2301" /><stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2303" /></linearGradient><linearGradient
id="XMLID_2_"
gradientUnits="userSpaceOnUse"
x1="80.223602"
y1="117.5205"
x2="48.046001"
y2="59.7995"
gradientTransform="matrix(0.314683,0.000000,0.000000,0.314683,4.128264,3.742874)">
<stop
offset="0"
style="stop-color:#CCCCCC"
id="stop17" />
<stop
offset="0.9831"
style="stop-color:#FFFFFF"
id="stop19" />
<midPointStop
offset="0"
style="stop-color:#CCCCCC"
id="midPointStop48" />
<midPointStop
offset="0.5"
style="stop-color:#CCCCCC"
id="midPointStop50" />
<midPointStop
offset="0.9831"
style="stop-color:#FFFFFF"
id="midPointStop52" />
</linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#XMLID_2_"
id="linearGradient1514"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.336922,0,0,0.166888,73.490762,15.46151)"
x1="52.006104"
y1="166.1331"
x2="14.049017"
y2="-42.218513" /><linearGradient
id="XMLID_39_"
gradientUnits="userSpaceOnUse"
x1="64.387703"
y1="65.124001"
x2="64.387703"
y2="35.569"
gradientTransform="matrix(0.354101,0,0,0.354101,57.146561,-0.08364921)">
<stop
offset="0"
style="stop-color:#FFFFFF"
id="stop336" />
<stop
offset="0.8539"
style="stop-color:#FF6200"
id="stop338" />
<stop
offset="1"
style="stop-color:#F25D00"
id="stop340" />
<midPointStop
offset="0"
style="stop-color:#FFFFFF"
id="midPointStop335" />
<midPointStop
offset="0.5"
style="stop-color:#FFFFFF"
id="midPointStop337" />
<midPointStop
offset="0.8539"
style="stop-color:#FF6200"
id="midPointStop339" />
<midPointStop
offset="0.5"
style="stop-color:#FF6200"
id="midPointStop341" />
<midPointStop
offset="1"
style="stop-color:#F25D00"
id="midPointStop343" />
</linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2299"
id="radialGradient2305"
cx="7.5326638"
cy="24.202574"
fx="7.5326638"
fy="24.202574"
r="8.2452128"
gradientTransform="matrix(4.100086,0,0,4.201322,30.092822,-78.53967)"
gradientUnits="userSpaceOnUse" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2307"
id="radialGradient2313"
cx="19.985598"
cy="36.77816"
fx="19.985598"
fy="36.77816"
r="1.0821035"
gradientTransform="matrix(1.125263,0,0,0.982744,52.079204,0.565787)"
gradientUnits="userSpaceOnUse" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2319"
id="radialGradient2325"
cx="20.443665"
cy="37.425829"
fx="20.443665"
fy="37.425829"
r="1.0821035"
gradientTransform="matrix(1.125263,0,0,0.982744,52.079204,0.731106)"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2329"
id="linearGradient2335"
x1="17.602522"
y1="26.057423"
x2="17.682528"
y2="32.654099"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.898789,0,0,1.071914,55.985907,-2.080838)" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2341"
id="radialGradient2339"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(4.100086,0,0,-4.201322,50.309773,105.3535)"
cx="11.68129"
cy="19.554111"
fx="11.68129"
fy="19.554111"
r="8.2452126" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2349"
id="radialGradient2355"
cx="24.023088"
cy="40.56913"
fx="24.023088"
fy="40.56913"
r="16.28684"
gradientTransform="matrix(1.000000,0.000000,0.000000,0.431250,1.157278e-15,23.07369)"
gradientUnits="userSpaceOnUse" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2368"
id="radialGradient2374"
cx="29.913452"
cy="30.442923"
fx="29.913452"
fy="30.442923"
r="4.0018832"
gradientTransform="matrix(3.751495,0,0,3.147818,-26.501188,-65.70704)"
gradientUnits="userSpaceOnUse" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2378"
id="radialGradient2384"
cx="24.195112"
cy="10.577631"
fx="24.195112"
fy="10.577631"
r="15.242914"
gradientTransform="matrix(1.125263,-3.585417e-8,4.269819e-8,1.340059,52.501178,1.355395)"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2390"
id="linearGradient2396"
x1="30.603519"
y1="37.337803"
x2="30.603519"
y2="36.112415"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.263867,0,0,0.859794,-6.499556,8.390924)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2406"
id="linearGradient2412"
x1="17.850183"
y1="28.939463"
x2="19.040216"
y2="41.03223"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.888785,0,0,1.08932,57.918872,-1.524336)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5048"
id="linearGradient4689"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
x1="302.85715"
y1="366.64789"
x2="302.85715"
y2="609.50507" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5060"
id="radialGradient4691"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
cx="605.71429"
cy="486.64789"
fx="605.71429"
fy="486.64789"
r="117.14286" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5060"
id="radialGradient4693"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
cx="605.71429"
cy="486.64789"
fx="605.71429"
fy="486.64789"
r="117.14286" /></defs><sodipodi:namedview
inkscape:cy="7.1533137"
inkscape:cx="51.448666"
inkscape:zoom="4"
inkscape:window-height="1056"
inkscape:window-width="1855"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="0.21568627"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:showpageshadow="false"
inkscape:window-x="1431"
inkscape:window-y="24"
inkscape:current-layer="svg2"
fill="#555753"
showgrid="false"
stroke="#a40000"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="false"
inkscape:window-maximized="1"><inkscape:grid
type="xygrid"
id="grid3818" /></sodipodi:namedview>
<g
style="display:inline"
id="g5022"
transform="matrix(0.02158196,0,0,0.01859457,98.630392,41.63767)"><rect
y="-150.69685"
x="-1559.2523"
height="478.35718"
width="1339.6335"
id="rect4173"
style="opacity:0.40206185;color:#000000;fill:url(#linearGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /><path
sodipodi:nodetypes="cccc"
id="path5058"
d="m -219.61876,-150.68038 c 0,0 0,478.33079 0,478.33079 142.874166,0.90045 345.40022,-107.16966 345.40014,-239.196175 0,-132.026537 -159.436816,-239.134595 -345.40014,-239.134615 z"
style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" /><path
style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
d="m -1559.2523,-150.68038 c 0,0 0,478.33079 0,478.33079 -142.8742,0.90045 -345.4002,-107.16966 -345.4002,-239.196175 0,-132.026537 159.4368,-239.134595 345.4002,-239.134615 z"
id="path5018"
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0" /></g><path
style="color:#000000;fill:url(#linearGradient1514);fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1.0000006;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
d="m 77.127458,8.1833733 5.957459,0 c 0.839732,0 13.886475,15.4353277 13.886475,16.3406587 l -0.443521,18.496745 c 0,0.905333 -0.67603,1.634177 -1.515762,1.634177 l -31.457277,0 c -0.839733,0 -1.515763,-0.728844 -1.515763,-1.634177 l 0.05648,-18.496745 c 0,-0.905331 14.192179,-16.3406587 15.031911,-16.3406587 z"
id="rect1512"
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0" /><path
style="fill:none"
id="path5"
d="m 102.47146,45.735573 -45.324901,0 0,-45.32489746 45.324901,0 0,45.32489746 z"
inkscape:connector-curvature="0" /><path
style="fill:url(#linearGradient2335);fill-opacity:1;fill-rule:evenodd"
id="path2327"
d="m 78.507882,29 -0.04574,15.090942 -11.842791,0 L 66.507882,29 l 12,0 z"
clip-rule="evenodd"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" /><path
sodipodi:nodetypes="ccccccccc"
id="path2357"
d="m 77.288341,9.405584 5.559097,0 c 0.783582,0 13.000869,14.399588 13.000869,15.244172 l -0.347158,18.212311 c 0,0.459259 -0.143737,0.653465 -0.512375,0.653465 l -31.387202,0.01428 c -0.368638,0 -0.583964,-0.07992 -0.583964,-0.45355 L 63.23295,24.649756 c 0,-0.844584 13.271812,-15.244172 14.055391,-15.244172 z"
style="opacity:0.3125;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" /><path
clip-rule="evenodd"
d="m 62.715412,27.943053 -0.05426,2.595194 18.368164,-13.179254 15.286395,11.154428 0.07131,-0.311714 L 80.016568,12.297576 62.715412,27.943053 z"
id="path23"
style="opacity:0.2;fill:url(#radialGradient2384);fill-opacity:1;fill-rule:evenodd"
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0" /><path
clip-rule="evenodd"
d="m 77.507882,30 0,14.090942 -9.811029,0 L 67.507882,30 l 10,0 z"
id="path188"
style="fill:url(#linearGradient2412);fill-opacity:1;fill-rule:evenodd"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" /><path
style="opacity:0.40909089;fill:url(#radialGradient2325);fill-opacity:1;fill-rule:evenodd"
id="path2315"
d="m 75.084738,36.44767 c 0.67279,0 1.216616,0.474605 1.216616,1.058507 0,0.589811 -0.543826,1.068355 -1.216616,1.068355 -0.672272,0 -1.218686,-0.478544 -1.218686,-1.068355 5.15e-4,-0.583902 0.546414,-1.058507 1.218686,-1.058507 z"
clip-rule="evenodd"
inkscape:connector-curvature="0" /><path
clip-rule="evenodd"
d="m 74.970196,35.932229 c 0.672789,0 1.216615,0.474605 1.216615,1.058507 0,0.589809 -0.543826,1.068353 -1.216615,1.068353 -0.672273,0 -1.218687,-0.478544 -1.218687,-1.068353 5.15e-4,-0.583902 0.546414,-1.058507 1.218687,-1.058507 z"
id="path217"
style="fill:url(#radialGradient2313);fill-opacity:1;fill-rule:evenodd"
inkscape:connector-curvature="0" /><path
d="m 79.95563,11.559337 18.92706,17.169868 0.494679,0.391991 0.403676,-0.171385 -0.37287,-0.761673 -0.277614,-0.223436 -19.174931,-15.572306 -19.389515,15.743335 -0.237602,0.14412 -0.21671,0.706786 0.43342,0.129248 0.384554,-0.308423 19.025853,-17.248125 z"
id="path342"
style="fill:url(#XMLID_39_)"
sodipodi:nodetypes="ccccccccccccc"
inkscape:connector-curvature="0" /><path
style="fill:#ef2929;stroke:#a40000"
id="path362"
d="m 79.83805,2.2713382 -21.881738,18.1013368 -0.624729,7.165928 1.999936,2.064323 c 0,0 20.407381,-17.157285 20.624093,-17.327963 l 19.63254,17.54326 1.898428,-2.323997 L 99.870785,20.382852 79.955612,2.1668788 79.83805,2.2713382 z"
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0" />
<path
style="opacity:0.40909089;color:#000000;fill:url(#radialGradient2305);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
d="M 58.349227,20.613129 58.057672,27.236494 79.877101,8.980075 79.806773,3.0867443 58.349227,20.613129 z"
id="path1536"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" /><path
sodipodi:nodetypes="ccccc"
id="path2337"
d="M 79.991645,8.7509884 80.091105,2.9098867 99.420068,20.56184 100.91188,27.062652 79.991645,8.7509884 z"
style="opacity:0.13636367;color:#000000;fill:url(#radialGradient2339);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" /><path
style="opacity:0.31818183;color:#000000;fill:none;stroke:#ffffff;stroke-width:0.99999934;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
d="m 82.61011,27.719824 9.039995,0 c 0.770595,0 1.390967,0.62037 1.390967,1.390967 l -0.008,9.079221 c 0,0.770596 -0.596322,1.265969 -1.366918,1.265969 l -9.056083,0 c -0.770597,0 -1.390967,-0.620373 -1.390967,-1.390969 l 0,-8.954221 c 0,-0.770597 0.62037,-1.390967 1.390967,-1.390967 z"
id="rect2361"
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0" /><rect
style="color:#000000;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:0.9999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
id="rect3263"
width="10.001333"
height="9.9624557"
x="82.015648"
y="28.514256"
rx="0.38128215"
ry="0.38128215" /><path
style="opacity:0.39772728;color:#000000;fill:url(#radialGradient2374);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999958;marker:none;visibility:visible;display:inline;overflow:visible"
d="m 82.615,34.408261 c 3.617983,0.331177 5.527724,-1.445704 8.868152,-1.55274 L 91.507882,29.00603 82.59627,29 82.615,34.408261 z"
id="rect2363"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" /><g
transform="translate(-4.065864,2.0108349)"
id="g4739"><path
sodipodi:type="arc"
style="fill:#6adb4d;fill-opacity:1;stroke:#34781d;stroke-width:1.05264175;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path4741"
sodipodi:cx="25.367456"
sodipodi:cy="8.2694378"
sodipodi:rx="5.3033009"
sodipodi:ry="5.3033009"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
transform="matrix(0.95416667,0,0,0.94583333,1.405743,0.73519001)" /><path
transform="matrix(0.77083333,0,0,0.77916666,6.0564434,2.1576238)"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
sodipodi:ry="5.3033009"
sodipodi:rx="5.3033009"
sodipodi:cy="8.2694378"
sodipodi:cx="25.367456"
id="path4743"
style="fill:none;stroke:#b3ff9a;stroke-width:1.29034114;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="arc" /></g><g
id="g4733"
transform="translate(6.8942911,5.0160386)"><path
transform="matrix(0.95416667,0,0,0.94583333,1.405743,0.73519001)"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
sodipodi:ry="5.3033009"
sodipodi:rx="5.3033009"
sodipodi:cy="8.2694378"
sodipodi:cx="25.367456"
id="path4735"
style="fill:#6adb4d;fill-opacity:1;stroke:#34781d;stroke-width:1.05264175;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="arc" /><path
sodipodi:type="arc"
style="fill:none;stroke:#b3ff9a;stroke-width:1.29034114;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path4737"
sodipodi:cx="25.367456"
sodipodi:cy="8.2694378"
sodipodi:rx="5.3033009"
sodipodi:ry="5.3033009"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
transform="matrix(0.77083333,0,0,0.77916666,6.0564434,2.1576238)" /></g><g
transform="translate(0.88388347,7.0268736)"
id="g4727"><path
sodipodi:type="arc"
style="fill:#6adb4d;fill-opacity:1;stroke:#34781d;stroke-width:1.05264175;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path4729"
sodipodi:cx="25.367456"
sodipodi:cy="8.2694378"
sodipodi:rx="5.3033009"
sodipodi:ry="5.3033009"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
transform="matrix(0.95416667,0,0,0.94583333,1.405743,0.73519001)" /><path
transform="matrix(0.77083333,0,0,0.77916666,6.0564434,2.1576238)"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
sodipodi:ry="5.3033009"
sodipodi:rx="5.3033009"
sodipodi:cy="8.2694378"
sodipodi:cx="25.367456"
id="path4731"
style="fill:none;stroke:#b3ff9a;stroke-width:1.29034114;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="arc" /></g><g
id="g4723"
transform="translate(-10.341437,5.9662134)"><path
transform="matrix(0.95416667,0,0,0.94583333,1.405743,0.73519001)"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
sodipodi:ry="5.3033009"
sodipodi:rx="5.3033009"
sodipodi:cy="8.2694378"
sodipodi:cx="25.367456"
id="path4719"
style="fill:#6adb4d;fill-opacity:1;stroke:#34781d;stroke-width:1.05264175;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="arc" /><path
sodipodi:type="arc"
style="fill:none;stroke:#b3ff9a;stroke-width:1.29034114;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path4721"
sodipodi:cx="25.367456"
sodipodi:cy="8.2694378"
sodipodi:rx="5.3033009"
sodipodi:ry="5.3033009"
d="m 30.670757,8.2694378 c 0,2.9289322 -2.374368,5.3033012 -5.303301,5.3033012 -2.928932,0 -5.3033,-2.374369 -5.3033,-5.3033012 0,-2.9289322 2.374368,-5.3033009 5.3033,-5.3033009 2.928933,0 5.303301,2.3743687 5.303301,5.3033009 z"
transform="matrix(0.77083333,0,0,0.77916666,6.0564434,2.1576238)" /></g><g
id="g4695"
transform="matrix(1.1326331,0,0,0.44340824,-4.4233826,2.4215088)"><rect
style="fill:#8a8a8a;fill-opacity:1;stroke:none"
id="rect4697"
width="29.256544"
height="18.119614"
x="10.297243"
y="27.449707"
rx="1.7190553"
ry="4.3911204" /><g
id="g4699"><g
id="g4701"><rect
rx="1.7051755"
y="27.517153"
x="10.510214"
height="17.982044"
width="29.020325"
id="rect4703"
style="fill:none;stroke:#646464;stroke-width:1.41005611;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
ry="4.3556657" /></g><rect
rx="0.88575488"
y="29.624025"
x="11.337327"
height="13.83156"
width="27.319036"
id="rect4705"
style="fill:none;stroke:#b3b3b3;stroke-width:1.40048993;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
ry="2.2625546" /></g></g><g
transform="matrix(0.01936185,0,0,0.01859457,41.413021,40.621203)"
id="g4681"
style="display:inline"><rect
style="opacity:0.40206185;color:#000000;fill:url(#linearGradient4689);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
id="rect4683"
width="1339.6335"
height="478.35718"
x="-1559.2523"
y="-150.69685" /><path
inkscape:connector-curvature="0"
style="opacity:0.40206185;color:#000000;fill:url(#radialGradient4691);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
d="m -219.61876,-150.68038 c 0,0 0,478.33079 0,478.33079 142.874166,0.90045 345.40022,-107.16966 345.40014,-239.196175 0,-132.026537 -159.436816,-239.134595 -345.40014,-239.134615 z"
id="path4685"
sodipodi:nodetypes="cccc" /><path
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc"
id="path4687"
d="m -1559.2523,-150.68038 c 0,0 0,478.33079 0,478.33079 -142.8742,0.90045 -345.4002,-107.16966 -345.4002,-239.196175 0,-132.026537 159.4368,-239.134595 345.4002,-239.134615 z"
style="opacity:0.40206185;color:#000000;fill:url(#radialGradient4693);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /></g><g
id="g4672"
transform="translate(-1.0606602,-2.9168155)"><rect
ry="1.9470588"
rx="1.9470588"
y="27.449707"
x="10.297243"
height="18.119614"
width="29.256544"
id="rect4658"
style="fill:#dddddd;fill-opacity:1;stroke:none" /><g
id="g4667"><g
id="g4664"><rect
ry="1.9313381"
style="fill:none;stroke:#646464;stroke-width:0.99927008;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect4660"
width="29.020325"
height="17.982044"
x="10.510214"
y="27.517153"
rx="1.9313381" /></g><rect
ry="1.0032353"
style="fill:none;stroke:#f6f6f6;stroke-width:0.99249077;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect4662"
width="26.967867"
height="16.005489"
x="11.532422"
y="28.489801"
rx="1.0032353" /></g></g><path
transform="matrix(1.0023678,0,0,0.95596394,-1.1198557,-0.0273148)"
d="m 35,33 a 10,10 0 1 1 -20,0 10,10 0 1 1 20,0 z"
sodipodi:ry="10"
sodipodi:rx="10"
sodipodi:cy="33"
sodipodi:cx="25"
id="path4679"
style="fill:#b8b8b8;fill-opacity:1;fill-rule:evenodd;stroke:none"
sodipodi:type="arc" /><path
sodipodi:type="arc"
style="fill:#b8b8b8;fill-opacity:1;fill-rule:evenodd;stroke:#646464;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path3820"
sodipodi:cx="25"
sodipodi:cy="33"
sodipodi:rx="10"
sodipodi:ry="10"
d="m 35,33 a 10,10 0 1 1 -20,0 10,10 0 1 1 20,0 z"
transform="matrix(0.94933484,0,0,0.95596394,0.2059695,-1.4857225)" /><path
transform="matrix(0.6928006,0,0,0.69727163,6.5972285,8.0344445)"
d="m 35,33 a 10,10 0 1 1 -20,0 10,10 0 1 1 20,0 z"
sodipodi:ry="10"
sodipodi:rx="10"
sodipodi:cy="33"
sodipodi:cx="25"
id="path4590"
style="fill:#f4f4f4;fill-opacity:1;fill-rule:evenodd;stroke:none"
sodipodi:type="arc" /><g
id="g4644"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,29.591021,-10.924363)"><rect
style="fill:#232323;fill-opacity:1;stroke:none"
id="rect4646"
width="0.68500972"
height="1.1490486"
x="24.638252"
y="26.853086" /><rect
y="37.990021"
x="24.660349"
height="1.1490486"
width="0.68500972"
id="rect4648"
style="fill:#232323;fill-opacity:1;stroke:none" /></g><g
id="g4600"
style="fill:#a2a2a2;fill-opacity:1"
transform="translate(-0.99436894,-2.3643883)"><rect
style="fill:#a2a2a2;fill-opacity:1;stroke:none"
id="rect4602"
width="1"
height="5.9375"
x="40.742825"
y="-1.6325631"
transform="matrix(0.67898035,0.73415645,-0.73415645,0.67898035,0,0)" /><path
sodipodi:type="arc"
style="fill:#a2a2a2;fill-opacity:1;stroke:none"
id="path4604"
sodipodi:cx="25.03125"
sodipodi:cy="33.03125"
sodipodi:rx="1.03125"
sodipodi:ry="0.96875"
d="M 26.0625,33.03125 C 26.0625,33.566276 25.600794,34 25.03125,34 24.461706,34 24,33.566276 24,33.03125 c 0,-0.535026 0.461706,-0.96875 1.03125,-0.96875 0.569544,0 1.03125,0.433724 1.03125,0.96875 z"
transform="matrix(0.95714504,0,0,1.0228099,1.028519,-0.77553647)" /></g><g
id="g4596"
transform="translate(-1.0606602,-2.9168155)"><rect
transform="matrix(0.67898035,0.73415645,-0.73415645,0.67898035,0,0)"
y="-1.6325631"
x="40.742825"
height="5.9375"
width="1"
id="rect4592"
style="fill:#ff2121;fill-opacity:1;stroke:none" /><path
transform="matrix(0.95714504,0,0,1.0228099,1.028519,-0.77553647)"
d="M 26.0625,33.03125 C 26.0625,33.566276 25.600794,34 25.03125,34 24.461706,34 24,33.566276 24,33.03125 c 0,-0.535026 0.461706,-0.96875 1.03125,-0.96875 0.569544,0 1.03125,0.433724 1.03125,0.96875 z"
sodipodi:ry="0.96875"
sodipodi:rx="1.03125"
sodipodi:cy="33.03125"
sodipodi:cx="25.03125"
id="path4594"
style="fill:#ff2121;fill-opacity:1;stroke:none"
sodipodi:type="arc" /></g><path
sodipodi:type="arc"
style="fill:none;stroke:#646464;stroke-width:1.37966764;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path4608"
sodipodi:cx="25"
sodipodi:cy="33"
sodipodi:rx="10"
sodipodi:ry="10"
d="m 35,33 a 10,10 0 1 1 -20,0 10,10 0 1 1 20,0 z"
transform="matrix(0.74693846,0,0,0.74919978,5.2548304,5.3595919)" /><g
id="g4628"
transform="translate(-1.0606602,-2.9168155)"><rect
y="26.853086"
x="24.638252"
height="1.1490486"
width="0.68500972"
id="rect4624"
style="fill:#232323;fill-opacity:1;stroke:none" /><rect
style="fill:#232323;fill-opacity:1;stroke:none"
id="rect4626"
width="0.68500972"
height="1.1490486"
x="24.660349"
y="37.990021" /></g><g
id="g4632"
transform="matrix(0,1,-1,0,56.927223,5.087457)"><rect
style="fill:#232323;fill-opacity:1;stroke:none"
id="rect4634"
width="0.68500972"
height="1.1490486"
x="24.638252"
y="26.853086" /><rect
y="37.990021"
x="24.660349"
height="1.1490486"
width="0.68500972"
id="rect4636"
style="fill:#232323;fill-opacity:1;stroke:none" /></g><rect
style="fill:#232323;fill-opacity:1;stroke:none"
id="rect4640"
width="0.68500972"
height="1.1490486"
x="3.9938221"
y="-44.334118"
transform="matrix(-0.70710678,0.70710678,-0.70710678,-0.70710678,0,0)" /><rect
y="-33.197182"
x="4.0159187"
height="1.1490486"
width="0.68500972"
id="rect4642"
style="fill:#232323;fill-opacity:1;stroke:none"
transform="matrix(-0.70710678,0.70710678,-0.70710678,-0.70710678,0,0)" /><g
transform="matrix(1.2021267,0,0,0.11694557,-6.1400423,11.401153)"
id="g4707"><rect
ry="16.649275"
rx="1.6196786"
y="27.449707"
x="10.297243"
height="18.119614"
width="29.256544"
id="rect4709"
style="fill:#d4d4d4;fill-opacity:1;stroke:none" /><g
id="g4711"><g
id="g4713"><rect
ry="16.514845"
style="fill:none;stroke:#646464;stroke-width:2.66511464;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect4715"
width="29.020325"
height="17.982044"
x="10.510214"
y="27.517153"
rx="1" /></g></g></g></svg>

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,13 @@
openerp.point_of_sale = function(instance) {
instance.point_of_sale = {};
instance.point_of_sale.test = instance.web.Widget.extend({
template: 'EmptyComponent',
start: function() {
var self = this;
this.$element.addClass('openerp');
return this.rpc('/pos/dispatch', {iface: 'light', status: 1}, function(result) {
console.log(result);
});
},
});
};

View File

@ -154,7 +154,7 @@ function openerp_pos_models(module, instance){ //module is instance.point_of_sal
},
_int_flush : function() {
var self = this;
this.dao.get_operations().pipe(function(operations) {
self.set( {'nbr_pending_operations':operations.length} );
if(operations.length === 0){
@ -269,21 +269,39 @@ function openerp_pos_models(module, instance){ //module is instance.point_of_sal
defaults: {
quantity: 1,
list_price: 0,
discount: 0
discount: 0,
weighted: false,
},
initialize: function(attributes) {
this.pos = attributes.pos;
console.log(attributes);
Backbone.Model.prototype.initialize.apply(this, arguments);
if(attributes.weight){
this.setWeight(attributes.weight);
this.set({weighted: true});
}
this.bind('change:quantity', function(unused, qty) {
if (qty == 0)
this.trigger('killme');
}, this);
},
setWeight: function(weight){
return this.set({
quantity: weight,
});
},
incrementQuantity: function() {
return this.set({
quantity: (this.get('quantity')) + 1
});
},
incrementWeight: function(weight){
return this.set({
quantity: (this.get('quantity')) + weight,
});
},
getPriceWithoutTax: function() {
return this.getAllPrices().priceWithoutTax;
},
@ -409,7 +427,12 @@ function openerp_pos_models(module, instance){ //module is instance.point_of_sal
var existing;
existing = (this.get('orderLines')).get(product.id);
if (existing != null) {
existing.incrementQuantity();
if(existing.get('weighted')){
console.log('TODO VERIFY THIS');
existing.incrementWeight(product.attributes.weight);
}else{
existing.incrementQuantity();
}
} else {
var attr = product.toJSON();
attr.pos = this.pos;

View File

@ -49,6 +49,8 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.screen_set = options.screen_set || {};
this.popup_set = options.popup_set || {};
this.default_client_screen = options.default_client_screen;
this.default_cashier_screen = options.default_cashier_screen;
@ -56,6 +58,8 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.current_cashier_screen = this.screen_set[this.default_client_screen];
this.current_popup = null;
this.default_mode = options.default_mode || 'client';
this.current_mode = this.default_mode;
@ -72,6 +76,11 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
screen.hide();
}
}
for(popup_name in this.popup_set){
this.popup_set[popup_name].hide();
}
if(current){
current.show();
}
@ -90,8 +99,22 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.screen_set[screen_name] = screen;
return this;
},
show_popup: function(name){
if(this.current_popup){
this.close_popup();
}
this.current_popup = this.popup_set[name];
this.current_popup.show();
},
close_popup: function(){
if(this.current_popup){
this.current_popup.hide();
this.current_popup = null;
}
},
load_saved_screen: function(){
console.log('load_saved_screen');
this.close_popup();
if(true || this.selected_order != this.pos.get('selectedOrder')){
var selectedOrder = this.pos.get('selectedOrder');
@ -123,6 +146,7 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
set_user_mode: function(user_mode){
console.log('set user mode:',user_mode);
if(user_mode !== this.current_mode){
this.close_popup();
this.current_mode = user_mode;
this.pos.get('selectedOrder').set({ user_mode : this.current_mode });
this.load_saved_screen();
@ -131,6 +155,7 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
set_current_screen: function(screen_name){
var screen = this.screen_set[screen_name];
this.close_popup();
var selectedOrder = this.pos.get('selectedOrder');
if(this.current_mode === 'client'){
selectedOrder.set({'client_screen': screen_name});
@ -174,6 +199,25 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
},
});
module.HelpPopupWidget = module.ScreenWidget.extend({
template:'HelpPopupWidget',
show: function(){
this._super();
this.pos.proxy.help_needed();
var self = this;
this.$element.find('.button').off('click').click(function(){
self.pos.screen_selector.close_popup();
self.pos.proxy.help_canceled();
});
},
hide:function(){
if(this.$element){
this.$element.hide();
}
},
});
module.ScaleInviteScreenWidget = module.ScreenWidget.extend({
template:'ScaleInviteScreenWidget',
show: function(){
@ -183,13 +227,16 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.set_numpad_visible(false);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
self.pos.proxy.weighting_start();
this.intervalID = setInterval(function(){
var weight = self.pos.proxy.weighting_read_kg();
if(weight > 0.001){
clearInterval(intervalID);
clearInterval(this.intervalID);
self.pos.screen_selector.set_current_screen('scale_product');
}
},500);
@ -197,6 +244,7 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.action_bar.add_new_button(
{
label: 'back',
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){ //TODO Go to ask for weighting screen
clearInterval(this.intervalID);
self.pos.proxy.weighting_end();
@ -221,6 +269,7 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.product_list_widget = new module.ProductListWidget(null,{
pos:this.pos,
weight: this.pos.proxy.weighting_read_kg(),
});
this.product_list_widget.replace($('.placeholder-ProductListWidget'));
},
@ -231,11 +280,15 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.set_numpad_visible(false);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
this.pos_widget.orderView.setNumpadState(this.pos_widget.numpadView.state);
this.pos_widget.action_bar.add_new_button(
{
label: 'back',
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){
self.pos.screen_selector.set_current_screen('scan');
}
@ -247,11 +300,23 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
self.proxy.cashier_mode_activated();
},
});
this.pos.proxy.weighting_start();
this.last_weight = this.product_list_widget.weight;
this.intervalID = setInterval(function(){
var weight = self.pos.proxy.weighting_read_kg();
if(weight != self.last_weight){
self.product_list_widget.setWeight(weight);
self.last_weight = weight;
}
},500);
},
hide: function(){
this._super();
this.pos_widget.orderView.setNumpadState(null);
this.pos_widget.payment_screen.setNumpadState(null);
clearInterval(this.intervalID);
this.pos.proxy.weighting_end();
},
});
@ -265,18 +330,21 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.set_numpad_visible(false);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
this.pos.proxy.payment_request(0,'card','info'); //TODO TOTAL
var intervalID = setInterval(function(){
this.intervalID = setInterval(function(){
var payment = self.pos.proxy.is_payment_accepted();
if(payment === 'payment_accepted'){
clearInterval(intervalID);
clearInterval(this.intervalID);
//TODO process the payment stuff
self.pos.proxy.transaction_end();
self.pos.screen_selector.set_current_screen('welcome');
}else if(payment === 'payment_rejected'){
clearInterval(intervalID);
clearInterval(this.intervalID);
//TODO show a tryagain thingie ?
}
},500);
@ -284,8 +352,9 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.action_bar.add_new_button(
{
label: 'back',
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
click: function(){ //TODO Go to ask for weighting screen
clearInterval(intervalID);
clearInterval(this.intervalID);
self.pos.proxy.payment_canceled();
self.pos.screen_selector.set_current_screen('scan');
}
@ -295,7 +364,7 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos.barcode_reader.set_action_callbacks({
'cashier': function(ean){
//TODO 'switch to cashier mode'
clearInterval(intervalID);
clearInterval(this.intervalID);
self.proxy.cashier_mode_activated();
self.pos.screen_selector.set_current_screen('products');
},
@ -312,6 +381,9 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.set_numpad_visible(false);
this.pos_widget.set_leftpane_visible(false);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(false);
this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
this.pos_widget.action_bar.add_new_button(
{
@ -320,7 +392,8 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
self.pos.screen_selector.set_current_screen('scan');
}
},{
label: 'peser',
label: 'weight',
icon: '/point_of_sale/static/src/img/icons/png48/scale.png',
click: function(){ //TODO Go to ask for weighting screen
self.pos.screen_selector.set_current_screen('scale_invite');
}
@ -363,15 +436,20 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.set_numpad_visible(false);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(false);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(true,function(){self.pos.screen_selector.show_popup('help');});
this.pos_widget.action_bar.set_logout_visible(false);
this.pos_widget.action_bar.add_new_button(
{
label: 'weight',
icon: '/point_of_sale/static/src/img/icons/png48/scale.png',
click: function(){ //TODO Go to ask for weighting screen
self.pos.screen_selector.set_current_screen('scale_invite');
}
},{
label: 'pay',
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
click: function(){
self.pos.screen_selector.set_current_screen('client_payment'); //TODO what stuff ?
}
@ -417,18 +495,19 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
this.pos_widget.set_numpad_visible(true);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(true);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(false);
this.pos_widget.action_bar.set_logout_visible(true, function(){
self.pos.screen_selector.set_user_mode('client');
});
this.pos_widget.orderView.setNumpadState(this.pos_widget.numpadView.state);
this.pos_widget.action_bar.add_new_button(
{
label: 'weight',
icon: '/point_of_sale/static/src/img/icons/png48/scale.png',
click: function(){ //TODO Go to ask for weighting screen
}
},{
label: 'pay',
click: function(){
self.pos.screen_selector.set_current_screen('payment'); //TODO what stuff ?
}
}
);
this.pos.barcode_reader.set_action_callbacks({
@ -474,10 +553,16 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
},
show: function(){
this._super();
var self = this;
this.pos_widget.set_numpad_visible(true);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(true);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(false);
this.pos_widget.action_bar.set_logout_visible(true, function(){
self.pos.screen_selector.set_user_mode('client');
});
},
print: function() {
window.print();
@ -515,10 +600,16 @@ function openerp_pos_screens(module, instance){ //module is instance.point_of_sa
},
show: function(){
this._super();
var self = this;
this.pos_widget.set_numpad_visible(true);
this.pos_widget.set_leftpane_visible(true);
this.pos_widget.set_cashier_controls_visible(true);
this.pos_widget.action_bar.set_total_visible(true);
this.pos_widget.action_bar.set_help_visible(false);
this.pos_widget.action_bar.set_logout_visible(true, function(){
self.pos.screen_selector.set_user_mode('client');
});
this.setNumpadState(this.pos_widget.numpadView.state);
},

View File

@ -17,7 +17,7 @@ function openerp_pos_widgets(module, instance){ //module is instance.point_of_sa
'currency': pos.get('currency'),
'format_amount': function(amount) {
if (pos.get('currency').position == 'after') {
return amount + ' ' + pos.get('currency').symbol;
return Math.round(amount*100)/100 + ' ' + pos.get('currency').symbol;
} else {
return pos.get('currency').symbol + ' ' + amount;
}
@ -236,23 +236,26 @@ function openerp_pos_widgets(module, instance){ //module is instance.point_of_sa
module.ProductWidget = instance.web.Widget.extend({
tagName:'li',
template_fct: qweb_template('pos-product-template'),
template_fct: qweb_template('ProductWidget'),
init: function(parent, options) {
this._super(parent);
this.model = options.model;
this.pos = options.pos;
},
start: function(options) {
$("a", this.$element).click(_.bind(this.addToOrder, this));
this.model.attributes.weight = options.weight || undefined;
},
addToOrder: function(event) {
/* Preserve the category URL */
event.preventDefault();
return (this.pos.get('selectedOrder')).addProduct(this.model);
},
setWeight: function(weight){
this.model.attributes.weight = weight;
this.renderElement();
},
renderElement: function() {
this.$element.addClass("product");
this.$element.html(this.template_fct(this.model.toJSON()));
$("a", this.$element).click(_.bind(this.addToOrder, this));
return this;
},
});
@ -358,6 +361,9 @@ function openerp_pos_widgets(module, instance){ //module is instance.point_of_sa
init: function(parent, options){
this._super(parent,options);
this.button_list = [];
this.total_visibility = true;
this.help_visibility = true;
this.logout_visibility = true;
},
destroy_buttons:function(){
for(var i = 0; i < this.button_list.length; i++){
@ -377,7 +383,46 @@ function openerp_pos_widgets(module, instance){ //module is instance.point_of_sa
}
}
return this;
}
},
set_total_visible: function(visible){
if(visible !== this.total_visibility){
this.total_visibility = visible;
if(visible){
this.$element.find('.total').show();
}else{
this.$element.find('.total').hide();
}
}
},
set_help_visible: function(visible,action){
if(visible !== this.help_visibility){
this.help_visibility = visible;
if(visible){
this.$element.find('.help-button').show();
}else{
this.$element.find('.help-button').hide();
}
}
if(visible && action){
this.$element.find('.help-button').off('click').click(action);
}
},
set_logout_visible: function(visible,action){
if(visible !== this.logout_visibility){
this.logout_visibility = visible;
if(visible){
this.$element.find('.logout-button').show();
}else{
this.$element.find('.logout-button').hide();
}
}
if(visible && action){
this.$element.find('.logout-button').off('click').click(action);
}
},
set_total_value: function(value){
this.$element.find('.value').hltml(value);
},
});
module.ProductCategoriesWidget = instance.web.Widget.extend({
@ -478,15 +523,26 @@ function openerp_pos_widgets(module, instance){ //module is instance.point_of_sa
this.model = options.model;
this.pos = options.pos;
this.pos.get('products').bind('reset', this.renderElement, this);
this.product_list = [];
this.weight = options.weight;
},
setWeight: function(weight){
for(var i = 0; i < this.product_list.length; i++){
this.product_list[i].setWeight(weight);
}
},
renderElement: function() {
var self = this;
this._super();
this.product_list = [];
this.pos.get('products').chain().map(function(product) {
return new module.ProductWidget(this, {
var product = new module.ProductWidget(this, {
model: product,
pos: self.pos
pos: self.pos,
weight: self.weight,
})
self.product_list.push(product);
return product;
}).invoke('appendTo', this.$element);
return this;
},
@ -821,6 +877,12 @@ function openerp_pos_widgets(module, instance){ //module is instance.point_of_sa
});
this.scale_product_screen.appendTo($('#rightpane'));
this.help_popup = new module.HelpPopupWidget(this, {
pos: this.pos,
pos_widget: this,
});
this.help_popup.appendTo($('.point-of-sale'));
this.paypadView = new module.PaypadWidget(null, {
pos: this.pos
});
@ -856,6 +918,9 @@ function openerp_pos_widgets(module, instance){ //module is instance.point_of_sa
'receipt' : this.receipt_screen,
'welcome' : this.welcome_screen,
},
popup_set:{
'help': this.help_popup,
},
default_client_screen: 'welcome',
default_cashier_screen: 'products',
default_mode: 'client',

View File

@ -221,30 +221,31 @@
<t t-name="WelcomeScreenWidget">
<div class="welcome-screen step-screen">
<header><h2>WELCUM</h2></header>
<p> plz scan ur card or thingie </p>
<header><h2>Welcome</h2></header>
<p> please scan an item or your member card </p>
</div>
</t>
<t t-name="ScanProductScreenWidget">
<div class="scan-product-screen step-screen">
<header><h2>SCAN YOUR PRODUCT</h2></header>
<p> please scan another product ! fun !</p>
<header><h2>Scan your item</h2></header>
<p>Please scan an item</p>
</div>
</t>
<t t-name="ClientPaymentScreenWidget">
<div class="scan-product-screen step-screen">
<header><h2>GIMME UR MONEY!!!11</h2></header>
<p> It's a rubbery </p>
<header><h2>Payment</h2></header>
<p>Please insert your card in the reader and follow the instructions to complete
your purchase</p>
</div>
</t>
<t t-name="ScaleInviteScreenWidget">
<div class="scale-invite-screen step-screen">
<header><h2>Put ur loot on the scale</h2></header>
<p> Is it worth a ton ? </p>
<header><h2>Please put your product on the scale</h2></header>
<p></p>
</div>
</t>
@ -255,13 +256,44 @@
</div>
</t>
<t t-name="pos-product-template">
<t t-name="HelpPopupWidget">
<div class="modal-dialog">
<div class="popup popup-help">
<p class="message">Please be patient, help is on the way</p>
<div class="footer">
<div class="button">
Cancel
</div>
</div>
</div>
</div>
</t>
<t t-name="ErrorPopupWidget">
<div class="modal-dialog">
<div class="popup popup-help">
<p class="message">An unexpected error has occured. A technician is on the way</p>
</div>
</div>
</t>
<t t-name="ProductWidget">
<a href="#">
<div class="product-img">
<img t-att-src="'data:image/gif;base64,'+ product_image_small" />
<span class="price-tag">
<t t-esc="format_amount(list_price)"/>
</span>
<t t-if="!weight">
<span class="price-tag">
<t t-esc="format_amount(list_price)"/>
</span>
</t>
<t t-if="weight">
<span class="price-tag">
<t t-esc="format_amount(list_price)+'/Kg'"/>
</span>
<span class="price-subtag">
<t t-esc="format_amount(list_price *weight)"/>
</span>
</t>
</div>
<div class="product-name">
<t t-esc="name"/>
@ -279,7 +311,12 @@
<t t-esc="discount.toFixed(2)"/>
</td>
<td>
<t t-esc="quantity.toFixed(0)"/>
<t t-if="weighted">
<t t-esc="Math.round(quantity*100)/100+' Kg'"/>
</t>
<t t-if="!weighted">
<t t-esc="Math.round(quantity*100)/100"/>
</t>
</td>
<td>
<t t-esc="format_amount((list_price * (1 - discount/100) * quantity).toFixed(2))"/>
@ -358,10 +395,19 @@
<div class="pos-actionbar">
<div class="pos-actionbar-left-pane">
<div class="button help-button">
Help
<div class='icon'>
<img src="/point_of_sale/static/src/img/icons/png48/help.png" />
<div class='iconlabel'>Help</div>
</div>
</div>
<div class="button logout-button">
<div class='icon'>
<img src="/point_of_sale/static/src/img/icons/png48/system-log-out.png" />
<div class='iconlabel'>Exit</div>
</div>
</div>
<p class="total">
Total: <span class="value"> 1234 </span>
Total: <span class="value"> 1234 </span>
</p>
</div>
<ul class="pos-actionbar-button-list">
@ -371,6 +417,7 @@
</ul>
</div>
</t>
<t t-name="pos-action-button">
<li t-att-class=" 'button '+ (widget.rightalign ? 'rightalign ' : '')">
<div class='label'>

View File

@ -0,0 +1,22 @@
<!doctype html>
<html>
<head>
<title>JSON</title>
<script type="text/javascript" src="http://localhost:8069/web/webclient/js"></script>
</head>
<body>
<h1>JSON</h1>
<p id="response"></p>
<script type="text/javascript">
var c = new openerp.init(['web', 'point_of_sale']);
c.connection.session_bind('http://localhost:8069').then(function() {
var w = new c.point_of_sale.test();
w.appendTo($("#response"));
});
</script>
</body>
</html>

View File

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

View File

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

View File

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

View File

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

View File

@ -10,10 +10,12 @@
<field name="arch" type="xml">
<form string="Put Money">
<separator string="Fill in this form if you put money in the cash register:" colspan="4"/>
<field name="name"/>
<field name="product_id"/>
<field name="journal_id"/>
<field name="product_id"/>
<field name="amount"/>
<field name="session_id" />
<field name="name"/>
<field name="user_id" invisible="1" />
<separator colspan="4"/>
<group colspan="4" col="4">
<group col="2" colspan="2"/>
@ -21,19 +23,27 @@
string="Cancel" />
<button name="get_in" string="Put Money"
colspan="1" type="object" icon="gtk-apply" />
</group>
</group>
</form>
</field>
</record>
<record id="action_box_entries" model="ir.actions.act_window">
<field name="name">Put Money In</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.box.entries</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<act_window name="Put Money In"
res_model="pos.box.entries"
src_model="account.bank.statement"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_box_entries" />
<act_window name="Put Money In"
res_model="pos.box.entries"
src_model="pos.session"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_pos_session_box_entries" />
</data>
</openerp>

View File

@ -52,10 +52,13 @@ class pos_box_out(osv.osv_memory):
'journal_id': fields.selection(pos_box_entries.get_journal, "Cash Register", required=True, size=-1),
'product_id': fields.selection(_get_expense_product, "Operation", required=True, size=-1),
'amount': fields.float('Amount', digits=(16, 2), required=True),
'session_id' : fields.many2one('pos.session', 'Session'),
'user_id' : fields.many2one('res.users', 'User'),
}
_defaults = {
'journal_id': 1,
'product_id': 1,
'journal_id': 1,
'product_id': 1,
'user_id' : lambda obj, cr, uid, context: uid,
}
def get_out(self, cr, uid, ids, context=None):

View File

@ -9,31 +9,40 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Output Operation">
<separator string="Describe why you take money from the cash register:" colspan="4"/>
<field name="name"/>
<field name="product_id"/>
<field name="journal_id"/>
<field name="amount"/>
<separator colspan="4"/>
<group colspan="4" col="4">
<group col="2" colspan="2"/>
<button icon="gtk-stop" special="cancel"
string="Cancel" />
<button name="get_out" string="Take Money"
colspan="1" type="object" icon="gtk-apply" />
</group>
<separator string="Describe why you take money from the cash register:" colspan="4"/>
<field name="journal_id"/>
<field name="product_id"/>
<field name="amount"/>
<field name="session_id" />
<field name="name"/>
<field name="user_id" invisible="1" />
<separator colspan="4"/>
<group colspan="4" col="4">
<group col="2" colspan="2"/>
<button icon="gtk-stop" special="cancel"
string="Cancel" />
<button name="get_out" string="Take Money"
colspan="1" type="object" icon="gtk-apply" />
</group>
</form>
</field>
</record>
<record id="action_box_out" model="ir.actions.act_window">
<field name="name">Take Money Out</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.box.out</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<act_window name="Take Money Out"
res_model="pos.box.out"
src_model="account.bank.statement"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_box_out" />
<act_window name="Take Money Out"
res_model="pos.box.out"
src_model="pos.session"
view_mode="form"
target="new"
key2="client_action_multi"
id="action_pos_session_box_out" />
</data>
</openerp>

View File

@ -65,7 +65,7 @@ class pos_open_statement(osv.osv_memory):
statement_id = statement_obj.create(cr, uid, data, context=context)
st_ids.append(int(statement_id))
if journal.auto_cash:
if journal.opening_control:
statement_obj.button_open(cr, uid, [statement_id], context)
tree_res = mod_obj.get_object_reference(cr, uid, 'point_of_sale', 'view_cash_statement_pos_tree')

View File

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

View File

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