[Merge] Merge with main addons.
bzr revid: mdi@tinyerp.com-20120717042839-rft65wt60b1gas6m
|
@ -99,6 +99,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
|
||||
|
|
|
@ -474,7 +474,7 @@ class account_account(osv.osv):
|
|||
'shortcut': fields.char('Shortcut', size=12),
|
||||
'tax_ids': fields.many2many('account.tax', 'account_account_tax_default_rel',
|
||||
'account_id', 'tax_id', 'Default Taxes'),
|
||||
'note': fields.text('Note'),
|
||||
'note': fields.text('Internal Notes'),
|
||||
'company_currency_id': fields.function(_get_company_currency, type='many2one', relation='res.currency', string='Company Currency'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True),
|
||||
'active': fields.boolean('Active', select=2, help="If the active field is set to False, it will allow you to hide the account without removing it."),
|
||||
|
@ -714,6 +714,7 @@ class account_journal(osv.osv):
|
|||
_name = "account.journal"
|
||||
_description = "Journal"
|
||||
_columns = {
|
||||
'with_last_closing_balance' : fields.boolean('Opening With Last Closing Balance'),
|
||||
'name': fields.char('Journal Name', size=64, required=True),
|
||||
'code': fields.char('Code', size=5, required=True, help="The code will be displayed on reports."),
|
||||
'type': fields.selection([('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Cheques'), ('general', 'General'), ('situation', 'Opening/Closing Situation')], 'Type', size=32, required=True,
|
||||
|
@ -737,9 +738,14 @@ 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 = {
|
||||
'with_last_closing_balance' : False,
|
||||
'user_id': lambda self, cr, uid, context: uid,
|
||||
'company_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
|
||||
}
|
||||
|
|
|
@ -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,45 +45,19 @@ 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')
|
||||
res_users_obj = self.pool.get('res.users')
|
||||
res = {}
|
||||
|
||||
company_currency_id = res_users_obj.browse(cursor, user, user,
|
||||
context=context).company_id.currency_id.id
|
||||
|
||||
statements = self.browse(cursor, user, ids, context=context)
|
||||
for statement in statements:
|
||||
for statement in self.browse(cursor, user, ids, context=context):
|
||||
res[statement.id] = statement.balance_start
|
||||
currency_id = statement.currency.id
|
||||
for line in statement.move_line_ids:
|
||||
if line.debit > 0:
|
||||
if line.account_id.id == \
|
||||
statement.journal_id.default_debit_account_id.id:
|
||||
res[statement.id] += res_currency_obj.compute(cursor,
|
||||
user, company_currency_id, currency_id,
|
||||
line.debit, context=context)
|
||||
else:
|
||||
if line.account_id.id == \
|
||||
statement.journal_id.default_credit_account_id.id:
|
||||
res[statement.id] -= res_currency_obj.compute(cursor,
|
||||
user, company_currency_id, currency_id,
|
||||
line.credit, context=context)
|
||||
|
||||
if statement.state in ('draft', 'open'):
|
||||
for line in statement.line_ids:
|
||||
res[statement.id] += line.amount
|
||||
for r in res:
|
||||
res[r] = round(res[r], 2)
|
||||
for line in statement.line_ids:
|
||||
res[statement.id] += line.amount
|
||||
return res
|
||||
|
||||
def _get_period(self, cr, uid, context=None):
|
||||
|
@ -129,7 +97,7 @@ class account_bank_statement(osv.osv):
|
|||
_description = "Bank Statement"
|
||||
_inherit = ['mail.thread']
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement
|
||||
'name': fields.char('Reference', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement
|
||||
'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True),
|
||||
'journal_id': fields.many2one('account.journal', 'Journal', required=True,
|
||||
readonly=True, states={'draft':[('readonly',False)]}),
|
||||
|
@ -141,7 +109,7 @@ class account_bank_statement(osv.osv):
|
|||
states={'confirm': [('readonly', True)]}),
|
||||
'balance_end': fields.function(_end_balance,
|
||||
store = {
|
||||
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids'], 10),
|
||||
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids','balance_start'], 10),
|
||||
'account.bank.statement.line': (_get_statement, ['amount'], 10),
|
||||
},
|
||||
string="Computed Balance", help='Balance as calculated based on Starting Balance and transaction lines'),
|
||||
|
@ -311,7 +279,7 @@ class account_bank_statement(osv.osv):
|
|||
|
||||
def balance_check(self, cr, uid, st_id, journal_type='bank', context=None):
|
||||
st = self.browse(cr, uid, st_id, context=context)
|
||||
if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_cash) < 0.0001)):
|
||||
if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001)):
|
||||
raise osv.except_osv(_('Error !'),
|
||||
_('The statement balance is incorrect !\nThe expected balance (%.2f) is different than the computed one. (%.2f)') % (st.balance_end_real, st.balance_end))
|
||||
return True
|
||||
|
@ -380,14 +348,18 @@ 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
|
||||
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']
|
||||
|
|
|
@ -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='Opening Subtotal', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
|
||||
'subtotal_closing': fields.function(_sub_total, string='Closing Subtotal', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
|
||||
'bank_statement_id' : fields.many2one('account.bank.statement', ondelete='cascade'),
|
||||
}
|
||||
|
||||
account_cashbox_line()
|
||||
|
@ -69,39 +72,24 @@ class account_cash_statement(osv.osv):
|
|||
|
||||
_inherit = 'account.bank.statement'
|
||||
|
||||
def _get_starting_balance(self, cr, uid, ids, context=None):
|
||||
|
||||
""" Find starting balance
|
||||
@param name: Names of fields.
|
||||
@param arg: User defined arguments
|
||||
@return: Dictionary of values.
|
||||
def _update_balances(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Set starting and ending balances according to pieces count
|
||||
"""
|
||||
res = {}
|
||||
for statement in self.browse(cr, uid, ids, context=context):
|
||||
amount_total = 0.0
|
||||
|
||||
if statement.journal_id.type not in('cash'):
|
||||
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
|
||||
start = end = 0
|
||||
for line in statement.details_ids:
|
||||
start += line.subtotal_opening
|
||||
end += line.subtotal_closing
|
||||
data = {
|
||||
'balance_start': start,
|
||||
'balance_end_real': end,
|
||||
}
|
||||
return res
|
||||
|
||||
def _balance_end_cash(self, cr, uid, ids, name, arg, context=None):
|
||||
""" Find ending balance "
|
||||
@param name: Names of fields.
|
||||
@param arg: User defined arguments
|
||||
@return: Dictionary of values.
|
||||
"""
|
||||
res = {}
|
||||
for statement in self.browse(cr, uid, ids, context=context):
|
||||
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] = data
|
||||
super(account_cash_statement, self).write(cr, uid, [statement.id], data, context=context)
|
||||
return res
|
||||
|
||||
def _get_sum_entry_encoding(self, cr, uid, ids, name, arg, context=None):
|
||||
|
@ -111,13 +99,10 @@ 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)
|
||||
return res
|
||||
|
||||
def _get_company(self, cr, uid, context=None):
|
||||
user_pool = self.pool.get('res.users')
|
||||
|
@ -128,96 +113,98 @@ class account_cash_statement(osv.osv):
|
|||
company_id = company_pool.search(cr, uid, [])
|
||||
return company_id and company_id[0] or False
|
||||
|
||||
def _get_cash_open_box_lines(self, cr, uid, context=None):
|
||||
res = []
|
||||
curr = [1, 2, 5, 10, 20, 50, 100, 500]
|
||||
for rs in curr:
|
||||
dct = {
|
||||
'pieces': rs,
|
||||
'number': 0
|
||||
}
|
||||
res.append(dct)
|
||||
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'cash')], context=context)
|
||||
if journal_ids:
|
||||
results = self.search(cr, uid, [('journal_id', 'in', journal_ids),('state', '=', 'confirm')], context=context)
|
||||
if results:
|
||||
cash_st = self.browse(cr, uid, results, context=context)[0]
|
||||
for cash_line in cash_st.ending_details_ids:
|
||||
for r in res:
|
||||
if cash_line.pieces == r['pieces']:
|
||||
r['number'] = cash_line.number
|
||||
return res
|
||||
|
||||
def _get_default_cash_close_box_lines(self, cr, uid, context=None):
|
||||
res = []
|
||||
curr = [1, 2, 5, 10, 20, 50, 100, 500]
|
||||
for rs in curr:
|
||||
dct = {
|
||||
'pieces': rs,
|
||||
'number': 0
|
||||
}
|
||||
res.append(dct)
|
||||
return res
|
||||
|
||||
def _get_cash_close_box_lines(self, cr, uid, context=None):
|
||||
res = []
|
||||
curr = [1, 2, 5, 10, 20, 50, 100, 500]
|
||||
for rs in curr:
|
||||
dct = {
|
||||
'pieces': rs,
|
||||
'number': 0
|
||||
}
|
||||
res.append((0, 0, dct))
|
||||
return res
|
||||
|
||||
def _get_cash_open_close_box_lines(self, cr, uid, context=None):
|
||||
res = {}
|
||||
start_l = []
|
||||
end_l = []
|
||||
starting_details = self._get_cash_open_box_lines(cr, uid, context=context)
|
||||
ending_details = self._get_default_cash_close_box_lines(cr, uid, context)
|
||||
for start in starting_details:
|
||||
start_l.append((0, 0, start))
|
||||
for end in ending_details:
|
||||
end_l.append((0, 0, end))
|
||||
res['start'] = start_l
|
||||
res['end'] = end_l
|
||||
return res
|
||||
|
||||
def _get_statement(self, cr, uid, ids, context=None):
|
||||
def _get_statement_from_line(self, cr, uid, ids, context=None):
|
||||
result = {}
|
||||
for line in self.pool.get('account.bank.statement.line').browse(cr, uid, ids, context=context):
|
||||
result[line.statement_id.id] = True
|
||||
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_real - obj.balance_end
|
||||
|
||||
return result
|
||||
|
||||
def _compute_last_closing_balance(self, cr, uid, ids, fieldnames, args, context=None):
|
||||
result = dict.fromkeys(ids, 0.0)
|
||||
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
if obj.state == 'draft':
|
||||
self.search(cr, uid,
|
||||
[('journal_id', '=', journal_id),('state', '=', 'confirm')],
|
||||
order='create_date desc',
|
||||
limit=1,
|
||||
context=context
|
||||
)
|
||||
|
||||
if not statement_ids:
|
||||
return result
|
||||
|
||||
st = self.browse(cr, uid, statement_ids[0], context=context)
|
||||
result[obj.id] = st.balance_end_real
|
||||
|
||||
return result
|
||||
|
||||
def onchange_journal_id(self, cr, uid, ids, journal_id, context=None):
|
||||
result = super(account_cash_statement, self).onchange_journal_id(cr, uid, ids, journal_id)
|
||||
|
||||
if not journal_id:
|
||||
return result
|
||||
|
||||
statement_ids = self.search(cr, uid,
|
||||
[('journal_id', '=', journal_id),('state', '=', 'confirm')],
|
||||
order='create_date desc',
|
||||
limit=1,
|
||||
context=context
|
||||
)
|
||||
|
||||
if not statement_ids:
|
||||
return result
|
||||
|
||||
st = self.browse(cr, uid, statement_ids[0], context=context)
|
||||
result.setdefault('value', {}).update({'last_closing_balance' : st.balance_end_real})
|
||||
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Cash Transaction", help="Total cash transactions",
|
||||
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Cash Transactions",
|
||||
store = {
|
||||
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids'], 10),
|
||||
'account.bank.statement.line': (_get_statement, ['amount'], 10),
|
||||
'account.bank.statement': (lambda self, cr, uid, ids, context=None: ids, ['line_ids','move_line_ids'], 10),
|
||||
'account.bank.statement.line': (_get_statement_from_line, ['amount'], 10),
|
||||
}),
|
||||
'closing_date': fields.datetime("Closed On"),
|
||||
'balance_end_cash': fields.function(_balance_end_cash, store=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'),
|
||||
'details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='CashBox Lines'),
|
||||
'opening_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Opening Cashbox Lines'),
|
||||
'closing_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Closing Cashbox Lines'),
|
||||
'user_id': fields.many2one('res.users', 'Responsible', required=False),
|
||||
'difference' : fields.function(_compute_difference, method=True, string="Difference", type="float"),
|
||||
'last_closing_balance' : fields.function(_compute_last_closing_balance, method=True, string='Last Closing Balance', 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 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',[]):
|
||||
if line and len(line)==3 and line[2]:
|
||||
amount_total+= line[2]['pieces'] * line[2]['number']
|
||||
vals.update(balance_start= amount_total)
|
||||
return super(account_cash_statement, self).create(cr, uid, vals, context=context)
|
||||
journal = False
|
||||
if vals.get('journal_id'):
|
||||
journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context)
|
||||
if journal and (journal.type == 'cash') and not vals.get('details_ids'):
|
||||
vals['details_ids'] = []
|
||||
for value in journal.cashbox_line_ids:
|
||||
nested_values = {
|
||||
'number_closing' : 0,
|
||||
'number_opening' : 0,
|
||||
'pieces' : value.pieces
|
||||
}
|
||||
vals['details_ids'].append([0, False, nested_values])
|
||||
|
||||
res_id = super(account_cash_statement, self).create(cr, uid, vals, context=context)
|
||||
self._update_balances(cr, uid, [res_id], context)
|
||||
return res_id
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
"""
|
||||
|
@ -233,34 +220,9 @@ class account_cash_statement(osv.osv):
|
|||
@return: True on success, False otherwise
|
||||
"""
|
||||
|
||||
super(account_cash_statement, self).write(cr, uid, ids, vals, context=context)
|
||||
res = self._get_starting_balance(cr, uid, ids)
|
||||
for rs in res:
|
||||
super(account_cash_statement, self).write(cr, uid, [rs], res.get(rs))
|
||||
return True
|
||||
|
||||
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
|
||||
""" Changes balance start and starting details if journal_id changes"
|
||||
@param statement_id: Changed statement_id
|
||||
@param journal_id: Changed journal_id
|
||||
@return: Dictionary of changed values
|
||||
"""
|
||||
res = {}
|
||||
balance_start = 0.0
|
||||
if not journal_id:
|
||||
res.update({
|
||||
'balance_start': balance_start
|
||||
})
|
||||
return res
|
||||
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
|
||||
if statement.balance_end != statement.balance_end_cash:
|
||||
return False
|
||||
return True
|
||||
res = super(account_cash_statement, self).write(cr, uid, ids, vals, context=context)
|
||||
self._update_balances(cr, uid, ids, context)
|
||||
return res
|
||||
|
||||
def _user_allow(self, cr, uid, statement_id, context=None):
|
||||
return True
|
||||
|
@ -276,7 +238,7 @@ class account_cash_statement(osv.osv):
|
|||
for statement in statement_pool.browse(cr, uid, ids, context=context):
|
||||
vals = {}
|
||||
if not self._user_allow(cr, uid, statement.id, context=context):
|
||||
raise osv.except_osv(_('Error !'), (_('User %s does not have rights to access %s journal !') % (statement.user_id.name, statement.journal_id.name)))
|
||||
raise osv.except_osv(_('Error !'), (_('You do not have rights to open this %s journal !') % (statement.journal_id.name, )))
|
||||
|
||||
if statement.name and statement.name == '/':
|
||||
c = {'fiscalyear_id': statement.period_id.fiscalyear_id.id}
|
||||
|
@ -294,13 +256,6 @@ class account_cash_statement(osv.osv):
|
|||
self.write(cr, uid, [statement.id], vals, context=context)
|
||||
return True
|
||||
|
||||
def balance_check(self, cr, uid, cash_id, journal_type='bank', context=None):
|
||||
if journal_type == 'bank':
|
||||
return super(account_cash_statement, self).balance_check(cr, uid, cash_id, journal_type, context)
|
||||
if not self._equal_balance(cr, uid, cash_id, context):
|
||||
raise osv.except_osv(_('Error !'), _('The closing balance should be the same than the computed balance!'))
|
||||
return True
|
||||
|
||||
def statement_close(self, cr, uid, ids, journal_type='bank', context=None):
|
||||
if journal_type == 'bank':
|
||||
return super(account_cash_statement, self).statement_close(cr, uid, ids, journal_type, context)
|
||||
|
@ -317,16 +272,67 @@ 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)
|
||||
return self.write(cr, uid, ids, {'closing_date': time.strftime("%Y-%m-%d %H:%M:%S")}, context=context)
|
||||
absl_proxy = self.pool.get('account.bank.statement.line')
|
||||
|
||||
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})
|
||||
return True
|
||||
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)
|
||||
|
||||
account_cash_statement()
|
||||
|
||||
class account_journal(osv.osv):
|
||||
_inherit = 'account.journal'
|
||||
|
||||
def _default_cashbox_line_ids(self, cr, uid, context=None):
|
||||
# Return a list of coins in Euros.
|
||||
result = [
|
||||
dict(pieces=value) for value in [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500]
|
||||
]
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'cashbox_line_ids' : fields.one2many('account.journal.cashbox.line', 'journal_id', 'CashBox'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'cashbox_line_ids' : _default_cashbox_line_ids,
|
||||
}
|
||||
|
||||
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:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from operator import itemgetter
|
||||
|
@ -985,37 +986,32 @@ class account_move_line(osv.osv):
|
|||
if context.get('view_mode', False):
|
||||
return result
|
||||
fld = []
|
||||
fields = {}
|
||||
flds = []
|
||||
title = _("Accounting Entries") #self.view_header_get(cr, uid, view_id, view_type, context)
|
||||
title = _("Accounting Entries") # self.view_header_get(cr, uid, view_id, view_type, context)
|
||||
|
||||
ids = journal_pool.search(cr, uid, [])
|
||||
ids = journal_pool.search(cr, uid, [], context=context)
|
||||
journals = journal_pool.browse(cr, uid, ids, context=context)
|
||||
all_journal = [None]
|
||||
common_fields = {}
|
||||
total = len(journals)
|
||||
for journal in journals:
|
||||
all_journal.append(journal.id)
|
||||
for field in journal.view_id.columns_id:
|
||||
# sometimes, it's possible that a defined column is not loaded (the module containing
|
||||
# sometimes, it's possible that a defined column is not loaded (the module containing
|
||||
# this field is not loaded) when we make an update.
|
||||
if field.name not in self._columns:
|
||||
if field.field not in self._columns:
|
||||
continue
|
||||
|
||||
if not field.field in fields:
|
||||
fields[field.field] = [journal.id]
|
||||
if not field.field in flds:
|
||||
fld.append((field.field, field.sequence))
|
||||
flds.append(field.field)
|
||||
common_fields[field.field] = 1
|
||||
else:
|
||||
fields.get(field.field).append(journal.id)
|
||||
common_fields[field.field] = common_fields[field.field] + 1
|
||||
fld.append(('period_id', 3))
|
||||
fld.append(('journal_id', 10))
|
||||
flds.append('period_id')
|
||||
flds.append('journal_id')
|
||||
fields['period_id'] = all_journal
|
||||
fields['journal_id'] = all_journal
|
||||
|
||||
default_columns = {
|
||||
'period_id': 3,
|
||||
'journal_id': 10,
|
||||
'state': sys.maxint,
|
||||
}
|
||||
for d in default_columns:
|
||||
if d not in flds:
|
||||
fld.append((d, default_columns[d]))
|
||||
flds.append(d)
|
||||
|
||||
fld = sorted(fld, key=itemgetter(1))
|
||||
widths = {
|
||||
'statement_id': 50,
|
||||
|
@ -1029,10 +1025,7 @@ class account_move_line(osv.osv):
|
|||
colors="red:state=='draft';black:state=='valid'")
|
||||
fields_get = self.fields_get(cr, uid, flds, context)
|
||||
for field, _seq in fld:
|
||||
if common_fields.get(field) == total:
|
||||
fields.get(field).append(None)
|
||||
# if field=='state':
|
||||
# state = 'colors="red:state==\'draft\'"'
|
||||
# TODO add string to element
|
||||
f = etree.SubElement(document, 'field', name=field)
|
||||
|
||||
if field == 'debit':
|
||||
|
|
|
@ -169,41 +169,37 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Account" version="7.0">
|
||||
<label for="name" class="oe_edit_only" string="Account Name and Code:"/>
|
||||
<label for="code" class="oe_edit_only" string="Account Code and Name"/>
|
||||
<h1>
|
||||
<field name="name"/> -
|
||||
<field name="code"/>
|
||||
<field name="code" class="oe_inline" placeholder="Account code" style="width: 6em"/> -
|
||||
<field name="name" class="oe_inline" placeholder="Account name"/>
|
||||
</h1>
|
||||
<label for="company_id"/>
|
||||
<h2>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</h2>
|
||||
<group>
|
||||
<group>
|
||||
<field name="parent_id"/>
|
||||
<field name="type"/>
|
||||
<field name="user_type"/>
|
||||
<field name="active"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="debit" invisible="context.get('config_invisible', True)" attrs="{'readonly':[('type','=','view')]}"/>
|
||||
<field name="credit" invisible="context.get('config_invisible', True)" attrs="{'readonly':[('type','=','view')]}"/>
|
||||
<field name="balance" invisible="context.get('config_invisible', True)"/>
|
||||
<field name="debit" attrs="{'readonly':[('type','=','view')]}"/>
|
||||
<field name="credit" attrs="{'readonly':[('type','=','view')]}"/>
|
||||
<field name="balance"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="tax_ids" domain="[('parent_id','=',False)]" widget="many2many_tags"/>
|
||||
<field name="reconcile"/>
|
||||
<field name="child_consol_ids"
|
||||
attrs="{'readonly':[('type','!=','consolidation')]}"
|
||||
attrs="{'invisible':[('type','!=','consolidation')]}"
|
||||
widget="many2many_tags"/>
|
||||
</group>
|
||||
<group string="Currency">
|
||||
<group>
|
||||
<field name="currency_id"/>
|
||||
<field name="currency_mode" attrs="{'readonly': [('currency_id','=',False)]}"/>
|
||||
</group>
|
||||
<group string="Reconcile">
|
||||
<field name="reconcile"/>
|
||||
</group>
|
||||
</group>
|
||||
<label for="note"/>
|
||||
<field name="note"/>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -490,6 +486,7 @@
|
|||
<group>
|
||||
<field name="centralisation"/>
|
||||
<field name="entry_posted"/>
|
||||
<field name="with_last_closing_balance" />
|
||||
<field name="allow_date"/>
|
||||
<field name="group_invoice_lines"/>
|
||||
</group>
|
||||
|
@ -498,6 +495,29 @@
|
|||
<field name="account_control_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</group>
|
||||
<page string="Entry Controls">
|
||||
<separator colspan="4" string="Accounts Type Allowed (empty for no control)"/>
|
||||
<field colspan="4" name="type_control_ids" nolabel="1"/>
|
||||
<separator colspan="4" string="Accounts Allowed (empty for no control)"/>
|
||||
<field colspan="4" name="account_control_ids" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Cash">
|
||||
<group string="Profit & Loss Accounts">
|
||||
<field name="profit_account_id" />
|
||||
<field name="loss_account_id" />
|
||||
</group>
|
||||
|
||||
<group string="Internal Transfer Account">
|
||||
<field name="internal_account_id" />
|
||||
</group>
|
||||
|
||||
<separator string="Available Currencies" colspan="4" />
|
||||
<field name="cashbox_line_ids" nolabel="1" string="Unit Of Currency Definition" colspan="4">
|
||||
<tree string="CashBox Lines" editable="bottom">
|
||||
<field name="pieces" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
|
@ -600,15 +620,21 @@
|
|||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="date" on_change="onchange_date(date, company_id)"/>
|
||||
<field name="journal_id" domain="[('type', '=', 'bank')]" on_change="onchange_journal_id(journal_id)" widget="selection"/>
|
||||
<field name="period_id"/>
|
||||
<label for="date" string="Date / Period"/>
|
||||
<div>
|
||||
<field name="date" on_change="onchange_date(date, company_id)" class="oe_inline"/>
|
||||
<field name="period_id" class="oe_inline"/>
|
||||
</div>
|
||||
<field name="name"/>
|
||||
<field name='company_id' widget="selection" groups="base.group_multi_company" />
|
||||
</group><group>
|
||||
<field name="balance_start"/>
|
||||
<label for="balance_start"/>
|
||||
<div>
|
||||
<field name="balance_start" class="oe_inline"/>
|
||||
<field name="currency" class="oe_inline"/>
|
||||
</div>
|
||||
<field name="balance_end_real"/>
|
||||
<field name="currency" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
|
@ -894,47 +920,68 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Account Tax" version="7.0">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<field name="type_tax_use"/>
|
||||
<field name="price_include"/>
|
||||
<field name="active"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<group>
|
||||
</group>
|
||||
<field name="type_tax_use"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Tax Definition">
|
||||
<group col="4">
|
||||
<field name="type"/>
|
||||
<field name="amount" attrs="{'readonly':[('type','in',('none', 'code', 'balance'))]}"/>
|
||||
<separator colspan="4" string="Accounting Information"/>
|
||||
<group>
|
||||
<group string="Tax Computation">
|
||||
<label for="type"/>
|
||||
<div>
|
||||
<field name="type"/>
|
||||
<field name="amount" class="oe_inline"
|
||||
attrs="{'invisible':[('type','in',('none', 'code', 'balance'))]}"/>
|
||||
<label string="%%" attrs="{'invisible':[('type','<>','percent')]}"/>
|
||||
</div>
|
||||
<field name="python_compute" attrs="{'invisible':[('type','!=','code')],'required':[('type','=','code')]}"/>
|
||||
<field name="python_compute_inv" attrs="{'invisible':[('type','!=','code')],'required':[('type','=','code')]}"/>
|
||||
<field name="price_include"/>
|
||||
</group>
|
||||
<group string="Misc">
|
||||
<field name="sequence"/>
|
||||
<field name="include_base_amount"/>
|
||||
<field name="child_depend"/>
|
||||
</group>
|
||||
<group string="Invoices">
|
||||
<field name="account_collected_id" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="account_analytic_collected_id" domain="[('type','<>','view'), ('company_id', '=', company_id), ('parent_id', '<>', False)]" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="account_paid_id" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="account_analytic_paid_id" domain="[('type','<>','view'), ('company_id', '=', company_id), ('parent_id', '<>', False)]" groups="analytic.group_analytic_accounting"/>
|
||||
<separator colspan="4" string="Tax Declaration: Invoices"/>
|
||||
|
||||
<field name="base_code_id"/>
|
||||
<field name="base_sign"/>
|
||||
<field name="tax_code_id"/>
|
||||
<field name="tax_sign"/>
|
||||
<separator colspan="4" string="Tax Declaration: Credit Notes"/>
|
||||
|
||||
</group>
|
||||
<group string="Refunds">
|
||||
<field name="account_paid_id" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="account_analytic_paid_id" domain="[('type','<>','view'), ('company_id', '=', company_id), ('parent_id', '<>', False)]" groups="analytic.group_analytic_accounting"/>
|
||||
|
||||
<field name="ref_base_code_id"/>
|
||||
<field name="ref_base_sign"/>
|
||||
<field name="ref_tax_code_id"/>
|
||||
<field name="ref_tax_sign"/>
|
||||
<separator colspan="4" string="Children Definition"/>
|
||||
<field name="child_depend"/>
|
||||
<field name="sequence"/>
|
||||
<field name="include_base_amount"/>
|
||||
<field colspan="4" name="child_ids">
|
||||
</group>
|
||||
<group string="Children/Sub Taxes" colspan="2">
|
||||
<field name="child_depend" class="oe_inline"/>
|
||||
<field name="child_ids" nolabel="1" colspan="2">
|
||||
<tree string="Account Tax">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="price_include"/>
|
||||
<field name="description"/>
|
||||
</tree>
|
||||
</field>
|
||||
</field>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Special Computation">
|
||||
<group col="4">
|
||||
|
@ -943,10 +990,6 @@
|
|||
<field name="domain"/>
|
||||
<separator colspan="4" string="Applicable Code (if type=code)"/>
|
||||
<field colspan="4" name="python_applicable" nolabel="1" attrs="{'readonly':[('applicable_type','=','true')], 'required':[('applicable_type','=','code')]}"/>
|
||||
<separator colspan="2" string="Compute Code"/>
|
||||
<separator colspan="2" string="Reverse Compute Code"/>
|
||||
<field colspan="2" name="python_compute" nolabel="1" attrs="{'readonly':[('type','!=','code')],'required':[('type','=','code')]}"/>
|
||||
<field colspan="2" name="python_compute_inv" nolabel="1" attrs="{'readonly':[('type','!=','code')],'required':[('type','=','code')]}"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
|
@ -2528,7 +2571,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"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
@ -2587,31 +2630,24 @@ action = pool.get('res.config').next(cr, uid, [], context)
|
|||
</form>
|
||||
</field>
|
||||
</page>
|
||||
<page string="CashBox">
|
||||
<group>
|
||||
<field name="starting_details_ids" attrs="{'readonly':[('state','!=','draft')]}" nolabel="1">
|
||||
<tree string = "Opening Balance" editable="bottom">
|
||||
<page string="Cash Control">
|
||||
<group col="2" expand="1">
|
||||
<field name="opening_details_ids" nolabel="1" colspan="4" attrs="{'invisible' : [('state', '!=', 'draft')]}">
|
||||
<tree string="Opening Cashbox Lines" editable="bottom">
|
||||
<field name="pieces"/>
|
||||
<field name="number" on_change="on_change_sub(pieces,number, parent.balance_end)"/>
|
||||
<field name="subtotal" sum="Total"/>
|
||||
<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"/>
|
||||
</tree>
|
||||
<form string = "Opening Balance" version="7.0">
|
||||
<field name="pieces"/>
|
||||
<field name="number" on_change="on_change_sub(pieces,number, parent.balance_end)"/>
|
||||
<field name="subtotal"/>
|
||||
</form>
|
||||
</field>
|
||||
<field name="ending_details_ids" attrs="{'readonly':[('state','!=','open')]}" nolabel="1">
|
||||
<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"/>
|
||||
<field name="closing_details_ids" nolabel="1" colspan="4" attrs="{'invisible' : [('state', '=', 'draft')]}">
|
||||
<tree string="Closing Cashbox Lines" editable="bottom">
|
||||
<field name="pieces" readonly="1" />
|
||||
<field name="number_opening" string="Opening Unit Numbers" readonly="1" />
|
||||
<field name="subtotal_opening" string="Opening Subtotal" readonly="1" />
|
||||
|
||||
<field name="number_closing" string="Closing Unit Numbers" on_change="on_change_sub_closing(pieces, number_closing, parent.balance_end)"/>
|
||||
<field name="subtotal_closing" string="Closing Subtotal"/>
|
||||
</tree>
|
||||
<form string = "Closing Balance" version="7.0">
|
||||
<field name="pieces"/>
|
||||
<field name="number" on_change="on_change_sub(pieces,number, parent.balance_end)"/>
|
||||
<field name="subtotal"/>
|
||||
</form>
|
||||
</field>
|
||||
</group>
|
||||
</page>
|
||||
|
@ -2619,18 +2655,15 @@ action = pool.get('res.config').next(cr, uid, [], context)
|
|||
<field name="move_line_ids" string="Journal Entries"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<group col="3">
|
||||
<group string="Dates">
|
||||
<field name="date" attrs="{'readonly':[('state','!=','draft')]}" on_change="onchange_date(date, company_id)"/>
|
||||
<field name="closing_date" readonly="1"/>
|
||||
</group>
|
||||
<group string="Opening Balance">
|
||||
<field name="balance_start" readonly="1" string="Opening Balance"/>
|
||||
<field name="total_entry_encoding"/>
|
||||
<group col="6" colspan="4">
|
||||
<group col="2" colspan="2">
|
||||
<separator string="Opening Balance" colspan="4"/>
|
||||
<field name="balance_start" readonly="1" string="Opening Cash Control"/>
|
||||
<field name="last_closing_balance" readonly="1" string="Last Closing Balance" />
|
||||
<field name="total_entry_encoding" />
|
||||
</group>
|
||||
<group string="Closing Balance">
|
||||
<field name="balance_end"/>
|
||||
<field name="balance_end_cash"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
|
|
@ -22,11 +22,11 @@
|
|||
<field name="model">res.company</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="currency_id" position="after">
|
||||
<field name="property_reserve_and_surplus_account" colspan="2"/>
|
||||
<field name="tax_calculation_rounding_method"/>
|
||||
<field name="paypal_account" placeholder="sales@openerp.com"/>
|
||||
</field>
|
||||
<xpath expr="//group[@name='account_grp']" position="inside">
|
||||
<field name="property_reserve_and_surplus_account"/>
|
||||
<field name="tax_calculation_rounding_method"/>
|
||||
<field name="paypal_account" placeholder="sales@openerp.com"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
or
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
</header>
|
||||
|
||||
<field name="has_default_company" invisible="1" />
|
||||
<field name="has_chart_of_accounts" invisible="1"/>
|
||||
<field name="complete_tax_set" invisible="1"/>
|
||||
|
@ -34,7 +33,6 @@
|
|||
<field name="expects_chart_of_accounts"/>
|
||||
</group>
|
||||
|
||||
<div class="oe_form_button_save_dirty">
|
||||
<group string="Select a Chart of Accounts to Install"
|
||||
attrs="{'invisible': ['|', ('expects_chart_of_accounts','=',False), ('has_chart_of_accounts','=',True)]}">
|
||||
<group>
|
||||
|
@ -51,9 +49,7 @@
|
|||
<button string="Install More Chart Templates" icon="gtk-go-forward"
|
||||
name="%(open_account_charts_modules)d" type="action"/>
|
||||
</group>
|
||||
</div>
|
||||
|
||||
<div class="oe_form_button_save_dirty">
|
||||
<group string="No Fiscal Year Defined for This Company"
|
||||
attrs="{'invisible': ['|', ('expects_chart_of_accounts','=',False), ('has_fiscal_year','=',True)]}">
|
||||
<label for="date_start" string="Date Range"/>
|
||||
|
@ -63,78 +59,67 @@
|
|||
</div>
|
||||
<field name="period"/>
|
||||
</group>
|
||||
</div>
|
||||
|
||||
<group string="Accounting Configuration">
|
||||
<group>
|
||||
<group>
|
||||
<group name="account_config">
|
||||
<separator string="Accounting Configuration" colspan="2"/>
|
||||
<field name="default_sale_tax" domain="[('type_tax_use','=','sale'), ('company_id','=',company_id)]"
|
||||
attrs="{'invisible': [('has_chart_of_accounts','=',False)]}"/>
|
||||
<field name="module_account_accountant"/>
|
||||
<field name="currency_id"/>
|
||||
<field name="decimal_precision"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="default_purchase_tax" domain="[('type_tax_use','=','purchase'), ('company_id','=',company_id)]"
|
||||
attrs="{'invisible': [('has_chart_of_accounts','=',False)]}"/>
|
||||
<field name="tax_calculation_rounding_method"/>
|
||||
<field name="module_account_asset"/>
|
||||
<field name="module_account_budget"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<field name="sale_journal_id" invisible="1"/>
|
||||
<field name="sale_refund_journal_id" invisible="1"/>
|
||||
<field name="purchase_journal_id" invisible="1"/>
|
||||
<field name="purchase_refund_journal_id" invisible="1"/>
|
||||
<group>
|
||||
<group string="Customer Invoices">
|
||||
<separator string="Customer Invoices" colspan="2"/>
|
||||
<label for="sale_sequence_next"/>
|
||||
<group>
|
||||
<field name="sale_sequence_prefix" class="oe_inline" nolabel="1"
|
||||
help='If you put "%%(year)s" in the prefix, it will be replaced by the current year.'/>
|
||||
<field name="sale_sequence_next" class="oe_inline" nolabel="1" attrs="{'readonly': [('sale_journal_id','=',False)]}"/>
|
||||
<field name="sale_sequence_next" class="oe_inline" nolabel="1" attrs="{'readonly': [('sale_journal_id','=',False)]}"/>
|
||||
</group>
|
||||
<label for="sale_refund_sequence_next"/>
|
||||
<group>
|
||||
<field name="sale_refund_sequence_prefix" class="oe_inline" nolabel="1"
|
||||
<field name="sale_refund_sequence_prefix" class="oe_inline" nolabel="1"
|
||||
help='If you put "%%(year)s" in the prefix, it will be replaced by the current year.'/>
|
||||
<field name="sale_refund_sequence_next" class="oe_inline" nolabel="1" attrs="{'readonly': [('sale_refund_journal_id','=',False)]}"/>
|
||||
<field name="sale_refund_sequence_next" nolabel="1" class="oe_inline" attrs="{'readonly': [('sale_refund_journal_id','=',False)]}"/>
|
||||
</group>
|
||||
<field name="module_account_voucher"/>
|
||||
<field name="module_account_followup"/>
|
||||
<field name="group_proforma_invoices"/>
|
||||
<separator name="analytic_accounting" invisible="1" string="Analytic Accounting"/>
|
||||
</group>
|
||||
|
||||
<group string="Supplier Invoices">
|
||||
<group name="other_cofing">
|
||||
<separator string="Supplier Invoices" colspan="2"/>
|
||||
<label for="purchase_sequence_next"/>
|
||||
<group>
|
||||
<field name="purchase_sequence_prefix" class="oe_inline" nolabel="1"
|
||||
help='If you put "%%(year)s" in the prefix, it will be replaced by the current year.'/>
|
||||
<field name="purchase_sequence_next" class="oe_inline" nolabel="1" attrs="{'readonly': [('purchase_journal_id','=',False)]}"/>
|
||||
<field name="purchase_sequence_next" nolabel="1" class="oe_inline" attrs="{'readonly': [('purchase_journal_id','=',False)]}"/>
|
||||
</group>
|
||||
<label for="purchase_refund_sequence_next"/>
|
||||
<group>
|
||||
<field name="purchase_refund_sequence_prefix" class="oe_inline" nolabel="1"
|
||||
<field name="purchase_refund_sequence_prefix" class="oe_inline" nolabel="1"
|
||||
help='If you put "%%(year)s" in the prefix, it will be replaced by the current year.'/>
|
||||
<field name="purchase_refund_sequence_next" class="oe_inline" nolabel="1"
|
||||
attrs="{'readonly': [('purchase_refund_journal_id','=',False)]}"/>
|
||||
<field name="purchase_refund_sequence_next" class="oe_inline"
|
||||
attrs="{'readonly': [('purchase_refund_journal_id','=',False)]}" nolabel="1"/>
|
||||
</group>
|
||||
<field name="module_account_payment"/>
|
||||
</group>
|
||||
|
||||
<group string="Electronic Payments">
|
||||
<separator string="Electronic Payments" colspan="2"/>
|
||||
<field name="paypal_account" placeholder="sales@openerp.com"/>
|
||||
</group>
|
||||
|
||||
<group string="Bank & Cash">
|
||||
<separator string="Bank & Cash" colspan="2"/>
|
||||
<label for="id" string="Configure Bank Accounts"/>
|
||||
<button name="%(action_bank_tree)d" string="Configure Bank Accounts" icon="gtk-go-forward" type="action"/>
|
||||
<field name="company_footer"/>
|
||||
<field name="module_account_check_writing"/>
|
||||
</group>
|
||||
|
||||
<group name="analytic_accounting" invisible="1" string="Analytic Accounting"/>
|
||||
</group>
|
||||
<field name="sale_journal_id" invisible="1"/>
|
||||
<field name="sale_refund_journal_id" invisible="1"/>
|
||||
<field name="purchase_journal_id" invisible="1"/>
|
||||
<field name="purchase_refund_journal_id" invisible="1"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -44,4 +44,5 @@ class res_currency_account(osv.osv):
|
|||
|
||||
res_currency_account()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
- pieces: 500.0
|
||||
number: 2
|
||||
subtotal: 1000.0
|
||||
balance_end_cash: 1120.0
|
||||
|
||||
-
|
||||
I clicked on Close CashBox button to close the cashbox
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
||||
|
|
|
@ -102,22 +102,21 @@ class account_move_journal(osv.osv_memory):
|
|||
period = period_pool.browse(cr, uid, [period_id], ['name'])[0]['name']
|
||||
period_string = _("Period: %s") % tools.ustr(period)
|
||||
|
||||
separator_string = _("Open Journal Items !")
|
||||
separator_string = _("Open Journal Items")
|
||||
open_string = _("Open")
|
||||
view = """<?xml version="1.0" encoding="utf-8"?>
|
||||
<form string="Standard entries" version="7.0">
|
||||
<header>
|
||||
<button string="%s" name="action_open_window" default_focus="1" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</header>
|
||||
<group string="%s">
|
||||
<field name="target_move" />
|
||||
</group>
|
||||
<label width="300" string="%s"/>
|
||||
<newline/>
|
||||
<label width="300" string="%s"/>
|
||||
</form>""" % (open_string, separator_string, journal_string, period_string)
|
||||
%s: <label string="%s"/>
|
||||
%s: <label string="%s"/>
|
||||
<footer>
|
||||
<button string="%s" name="action_open_window" default_focus="1" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>""" % (separator_string, _('Journal'), journal_string, _('Period'), period_string,open_string)
|
||||
|
||||
view = etree.fromstring(view.encode('utf8'))
|
||||
xarch, xfields = self._view_look_dom_arch(cr, uid, view, view_id, context=context)
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env python
|
||||
from osv import osv, fields
|
||||
import decimal_precision as dp
|
||||
from tools.translate import _
|
||||
|
||||
class CashBox(osv.osv_memory):
|
||||
_register = False
|
||||
_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:
|
||||
raise osv.except_osv(_('Error !'),
|
||||
_("Please check that the field 'Journal' is set on the Bank Statement"))
|
||||
|
||||
if not record.journal_id.internal_account_id:
|
||||
raise osv.except_osv(_('Error !'),
|
||||
_("Please check that the field 'Internal Transfers Account' is set on the payment method '%s'.") % (record.journal_id.name,))
|
||||
|
||||
self._create_bank_statement_line(cr, uid, box, record, context=context)
|
||||
|
||||
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()
|
|
@ -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>
|
|
@ -41,9 +41,10 @@ class account_bank_statement(osv.osv):
|
|||
def button_confirm_bank(self, cr, uid, ids, context=None):
|
||||
super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context)
|
||||
for st in self.browse(cr, uid, ids, context=context):
|
||||
cr.execute("UPDATE account_bank_statement_line \
|
||||
SET state='confirm' WHERE id in %s ",
|
||||
(tuple([x.id for x in st.line_ids]),))
|
||||
if st.line_ids:
|
||||
cr.execute("UPDATE account_bank_statement_line \
|
||||
SET state='confirm' WHERE id in %s ",
|
||||
(tuple([x.id for x in st.line_ids]),))
|
||||
return True
|
||||
|
||||
def button_cancel(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -31,11 +31,9 @@
|
|||
<field name="priority">17</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<page string="Configuration" position="inside">
|
||||
<separator string="Default Check Layout" colspan="4"/>
|
||||
<xpath expr="//group[@name='account_grp']" position="inside">
|
||||
<field name="check_layout"/>
|
||||
<newline/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<field name="period_id" invisible="context.get('visible', True)"/>
|
||||
<field name="type" invisible="context.get('visible', True)"/>
|
||||
<field name="amount" sum="Total Amount"/>
|
||||
<field name="audit"/>
|
||||
<field name="audit" invisible="1"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
@ -272,8 +272,8 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="currency_id" position="after">
|
||||
<field name="income_currency_exchange_account_id" colspan="2"/>
|
||||
<field name="expense_currency_exchange_account_id" colspan="2"/>
|
||||
<field name="income_currency_exchange_account_id"/>
|
||||
<field name="expense_currency_exchange_account_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -149,26 +149,31 @@
|
|||
<button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft" invisible="context.get('line_type', False)"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
|
||||
</header>
|
||||
<sheet string="Bill Payment">
|
||||
<group col="6">
|
||||
<field name="partner_id" required="1" invisible="context.get('line_type', False)" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" context="{'invoice_currency':currency_id, 'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" string="Supplier"/>
|
||||
<field name="amount" invisible="context.get('line_type', False)" on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, payment_rate_currency_id, company_id, context)"/>
|
||||
<field name="journal_id"
|
||||
domain="[('type','in',['bank', 'cash'])]"
|
||||
invisible="context.get('line_type', False)"
|
||||
widget="selection"
|
||||
on_change="onchange_journal(journal_id, line_dr_ids, False, partner_id, date, amount, type, company_id, context)"
|
||||
string="Payment Method"/>
|
||||
<field name="date" invisible="context.get('line_type', False)" on_change="onchange_date(date, currency_id, payment_rate_currency_id, amount, company_id, context)"/>
|
||||
<field name="reference" invisible="context.get('line_type', False)" string="Payment Ref" placeholder="003/10"/>
|
||||
<field name="name" colspan="2" invisible="context.get('line_type', False)" placeholder="Invoice SAJ/0042"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
<field name="account_id"
|
||||
widget="selection"
|
||||
invisible="True"/>
|
||||
<field name="pre_line" invisible="1"/>
|
||||
<field name="type" invisible="True"/>
|
||||
<field name="currency_id" invisible="1" colspan="4"/>
|
||||
<sheet>
|
||||
<field name="account_id" invisible="True"/>
|
||||
<field name="pre_line" invisible="1"/>
|
||||
<field name="type" invisible="True"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" required="1" invisible="context.get('line_type', False)" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" context="{'invoice_currency':currency_id, 'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" string="Supplier"/>
|
||||
<label for="amount" string="Amount"/>
|
||||
<div>
|
||||
<field name="amount" invisible="context.get('line_type', False)" on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, payment_rate_currency_id, company_id, context)" class="oe_inline"/>
|
||||
<field name="currency_id" class="oe_inline"/>
|
||||
</div>
|
||||
<field name="journal_id"
|
||||
domain="[('type','in',['bank', 'cash'])]"
|
||||
invisible="context.get('line_type', False)"
|
||||
widget="selection"
|
||||
on_change="onchange_journal(journal_id, line_dr_ids, False, partner_id, date, amount, type, company_id, context)"
|
||||
string="Payment Method"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date" invisible="context.get('line_type', False)" on_change="onchange_date(date, currency_id, payment_rate_currency_id, amount, company_id, context)"/>
|
||||
<field name="reference" invisible="context.get('line_type', False)" string="Payment Ref" placeholder="003/10"/>
|
||||
<field name="name" colspan="2" invisible="context.get('line_type', False)" placeholder="Invoice SAJ/0042"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Payment Information">
|
||||
|
@ -311,10 +316,15 @@
|
|||
<group>
|
||||
<group>
|
||||
<field name="partner_id" domain="[('customer','=',True)]" required="1" invisible="context.get('line_type', False)" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Customer" context="{'search_default_customer': 1}"/>
|
||||
<field name="amount"
|
||||
invisible="context.get('line_type', False)"
|
||||
string="Paid Amount"
|
||||
on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, payment_rate_currency_id, company_id, context)"/>
|
||||
<label for="amount"
|
||||
string="Paid Amount"/>
|
||||
<div>
|
||||
<field name="amount" class="oe_inline"
|
||||
invisible="context.get('line_type', False)"
|
||||
on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, payment_rate_currency_id, company_id, context)"/>
|
||||
<field name="currency_id" class="oe_inline"/>
|
||||
</div>
|
||||
|
||||
<field name="journal_id"
|
||||
domain="[('type','in',['bank', 'cash'])]"
|
||||
invisible="context.get('line_type', False)"
|
||||
|
@ -323,7 +333,6 @@
|
|||
string="Payment Method"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="date" invisible="context.get('line_type', False)" on_change="onchange_date(date, currency_id, payment_rate_currency_id, amount, company_id, context)"/>
|
||||
<field name="reference" invisible="context.get('line_type', False)" string="Payment Ref" placeholder="003/10"/>
|
||||
<field name="name" colspan="2" invisible="context.get('line_type', False)" placeholder="Invoice SAJ/0042"/>
|
||||
|
|
|
@ -88,18 +88,18 @@
|
|||
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
|
||||
</header>
|
||||
<sheet string="Sales Receipt" >
|
||||
<h1><label for="number" string="Sales Receipt "/><field name="number" class="oe_inline"/></h1>
|
||||
<h1><label for="number" string="Sale Receipt"/> <field name="number" class="oe_inline" readonly="1"/></h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" domain="[('customer','=',True)]" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Customer" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": true}'/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="journal_id" domain="[('type','in',['sale','sale_refund'])]" widget="selection" on_change="onchange_journal(journal_id, line_cr_ids, tax_id, partner_id, date, amount, type, company_id, context)"/>
|
||||
<field name="date" on_change="onchange_date(date, currency_id, currency_id, amount, company_id, context)"/>
|
||||
<field name="name"/>
|
||||
<field name="paid" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
</group>
|
||||
<field name="type" invisible="True"/>
|
||||
</group>
|
||||
|
@ -118,16 +118,17 @@
|
|||
<group class="oe_subtotal_footer oe_right">
|
||||
<field name="tax_id"
|
||||
on_change="onchange_price(line_cr_ids, tax_id, partner_id)"
|
||||
widget="selection"
|
||||
widget="selection" nolabel="1"
|
||||
placeholder="select tax..."
|
||||
domain="[('type_tax_use','in',('sale','all')), ('parent_id', '=', False)]"/>
|
||||
<div>
|
||||
<label for="tax_amount"/>
|
||||
<field name="tax_amount" nolabel="1"/>
|
||||
<div class="oe_subtotal_footer_separator">
|
||||
<label for="amount"/>
|
||||
<button type="object" class="oe_link oe_edit_only"
|
||||
name="compute_tax" string="(update)"
|
||||
attrs="{'invisible': [('state','!=','draft')]}"/>
|
||||
</div>
|
||||
<field name="tax_amount" nolabel="1"/>
|
||||
<field name="amount" class="oe_subtotal_footer_separator" />
|
||||
<field name="amount" class="oe_subtotal_footer_separator" nolabel="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pay_now" on_change="onchange_payment(pay_now, journal_id, partner_id)" required="1"/>
|
||||
|
@ -228,37 +229,30 @@
|
|||
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
|
||||
</header>
|
||||
<sheet string="Supplier Voucher">
|
||||
<div class="oe_title">
|
||||
<label for="number" class="oe_edit_only"/>
|
||||
<h1><field name="number" readonly="0" /></h1>
|
||||
</div>
|
||||
<h1><label for="number" string="Purchase Receipt"/> <field name="number" class="oe_inline" readonly="1"/></h1>
|
||||
|
||||
<field name="pay_now" invisible="1"/>
|
||||
<field name="account_id" domain="[('type','=','other')]" invisible="True"/>
|
||||
<field name="type" invisible="True"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" domain="[('supplier','=',True)]" required="1" string="Supplier" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" />
|
||||
<field name="date" string="Bill Date" on_change="onchange_date(date, currency_id, currency_id, amount, company_id, context)"/>
|
||||
<field name="date_due"/>
|
||||
<field name="partner_id" domain="[('supplier','=',True)]" string="Supplier" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" />
|
||||
<field name="name" colspan="2"/>
|
||||
|
||||
<field name="reference"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date" string="Bill Date" on_change="onchange_date(date, currency_id, currency_id, amount, company_id, context)"/>
|
||||
<field name="date_due"/>
|
||||
<field name="paid" invisible="1"/>
|
||||
<field name="currency_id"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="journal_id"
|
||||
domain="[('type','in',['purchase','purchase_refund'])]"
|
||||
widget="selection"
|
||||
on_change="onchange_journal(journal_id, line_dr_ids, tax_id, partner_id, date, amount, type, company_id, context)"/>
|
||||
<field name="reference"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<group col="6">
|
||||
<field name="account_id" domain="[('type','=','other')]" invisible="True"/>
|
||||
<field name="type" invisible="True"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<notebook>
|
||||
<page string="Bill Information">
|
||||
<field name="line_dr_ids" on_change="onchange_price(line_dr_ids, tax_id, partner_id)" context="{'journal_id':journal_id,'partner_id':partner_id}">
|
||||
<tree string="Expense Lines" editable="bottom">
|
||||
|
@ -269,10 +263,8 @@
|
|||
</tree>
|
||||
</field>
|
||||
<group>
|
||||
<group>
|
||||
<field name="narration" placeholder="Internal Notes" nolabel="1" />
|
||||
</group>
|
||||
<group class="oe_subtotal_footer">
|
||||
<field name="narration" placeholder="Internal Notes" nolabel="1"/>
|
||||
<group class="oe_subtotal_footer oe_right">
|
||||
<!--
|
||||
<div>
|
||||
<label for="tax_id" />
|
||||
|
@ -284,13 +276,20 @@
|
|||
-->
|
||||
<field name="tax_id"
|
||||
on_change="onchange_price(line_dr_ids, tax_id, partner_id)"
|
||||
widget="selection"
|
||||
widget="selection" nolabel="1"
|
||||
placeholder="select tax..."
|
||||
|
||||
domain="[('type_tax_use','in',('purchase','all')), ('parent_id', '=', False)]"
|
||||
/>
|
||||
<field name="tax_amount" />
|
||||
<field name="amount" string="Total" class="oe_subtotal_footer_separator"/>
|
||||
</group>
|
||||
|
||||
<field name="tax_amount" nolabel="1"/>
|
||||
<div class="oe_subtotal_footer_separator">
|
||||
<label for="amount"/>
|
||||
<button type="object" class="oe_link oe_edit_only"
|
||||
name="compute_tax" string="(update)"
|
||||
attrs="{'invisible': [('state','!=','draft')]}"/>
|
||||
</div>
|
||||
<field name="amount" class="oe_subtotal_footer_separator" nolabel="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Journal Items" attrs="{'invisible': [('state','!=','posted')]}">
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
<field name="arch" type="xml">
|
||||
<notebook colspan="4" position="inside">
|
||||
<page string="OpenID">
|
||||
<field name="openid_url"/>
|
||||
<field name="openid_email"/>
|
||||
<group>
|
||||
<field name="openid_url"/>
|
||||
<field name="openid_email"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
|
|
|
@ -12,9 +12,12 @@
|
|||
or
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
</header>
|
||||
<group string="Company Settings">
|
||||
<group>
|
||||
<group>
|
||||
<group string="Company Settings">
|
||||
<field name="module_multi_company"/>
|
||||
<separator string="External Accesses" colspan="2"/>
|
||||
<field name="module_share"/>
|
||||
<field name="module_portal"/>
|
||||
</group>
|
||||
<group>
|
||||
<div>
|
||||
|
@ -22,16 +25,12 @@
|
|||
address for the header and footer, overdue payments texts, etc.
|
||||
</div>
|
||||
<button type="object" name="open_company" string="Configure Your Company Data" icon="gtk-execute"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="External Accesses">
|
||||
<field name="module_share"/>
|
||||
<field name="module_portal"/>
|
||||
</group>
|
||||
<group string="Others">
|
||||
<label for="id" string="Outgoing Mail Servers"/>
|
||||
<button type="action" name="%(base.action_ir_mail_server_list)d"
|
||||
<separator string="Others" colspan="2"/>
|
||||
<label for="id" string="Outgoing Mail Servers"/>
|
||||
<button type="action" name="%(base.action_ir_mail_server_list)d"
|
||||
string="Configure" icon="gtk-execute"/>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -58,13 +57,16 @@
|
|||
or
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
</header>
|
||||
<field name="module_crm" invisible="1"/>
|
||||
<group name="config_sale"/>
|
||||
<group name="config_fetchmail" string="Emails" attrs="{'invisible': [('module_crm','=',False)]}">
|
||||
<field name="module_plugin_thunderbird"/>
|
||||
<field name="module_plugin_outlook"/>
|
||||
</group>
|
||||
<group name="config_crm"/>
|
||||
<group>
|
||||
<group name="config_sale">
|
||||
<field name="module_crm" invisible="1"/>
|
||||
<separator string="Emails" colspan="2" attrs="{'invisible': [('module_crm','=',False)]}"/>
|
||||
<field name="module_plugin_thunderbird" attrs="{'invisible': [('module_crm','=',False)]}"/>
|
||||
<field name="module_plugin_outlook" attrs="{'invisible': [('module_crm','=',False)]}"/>
|
||||
</group>
|
||||
<group name="config_other">
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -140,9 +140,10 @@
|
|||
name="%(act_crm_opportunity_crm_phonecall_new)d"
|
||||
string="Phone Calls" />
|
||||
</div>
|
||||
|
||||
<label for="name" class="oe_edit_only" string="Lead Description"/>
|
||||
<h1><field name="name" placeholder="Describe the lead..."/></h1>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" string="Lead Description"/>
|
||||
<h1><field name="name" placeholder="Describe the lead..."/></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="user_id" />
|
||||
|
|
|
@ -8,29 +8,25 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base_setup.view_sale_config_settings"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="config_fetchmail" version="7.0" position="inside">
|
||||
<separator string="Emails" version="7.0" position="after">
|
||||
<label for="fetchmail_lead"/>
|
||||
<div>
|
||||
<field name="fetchmail_lead"/>
|
||||
<button name="configure_fetchmail_lead" type="object" string="Configure" icon="gtk-go-forward"
|
||||
attrs="{'invisible': [('fetchmail_lead','=',False)]}"/>
|
||||
</div>
|
||||
</separator>
|
||||
<group name="config_other" version="7.0" position="inside">
|
||||
<separator string="Import and Synchronize Data from an Other Application" colspan="2"/>
|
||||
<field name="module_import_sugarcrm"/>
|
||||
<field name="module_crm_caldav"/>
|
||||
<field name="module_import_google"/>
|
||||
<separator string="Customer Form" colspan="2"/>
|
||||
<field name="module_google_map"/>
|
||||
</group>
|
||||
|
||||
<group name="config_crm" position="after">
|
||||
<group string="Import and Synchronize Data from an Other Application">
|
||||
<field name="module_import_sugarcrm"/>
|
||||
<field name="module_crm_caldav"/>
|
||||
<field name="module_import_google"/>
|
||||
</group>
|
||||
|
||||
<group string="Documents and Wiki">
|
||||
<group name="config_sale" position="inside">
|
||||
<separator string="Documents and Wiki" colspan="2"/>
|
||||
<field name="module_wiki_sale_faq"/>
|
||||
</group>
|
||||
|
||||
<group string="Customer Form">
|
||||
<field name="module_google_map"/>
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
<field name="inherit_id" ref="base_setup.view_sale_config_settings"/>
|
||||
<field name="priority" eval="20"/> <!-- to put fetchmail_lead before fetchmail_claim -->
|
||||
<field name="arch" type="xml">
|
||||
<group name="config_fetchmail" version="7.0" position="inside">
|
||||
<separator string="Emails" version="7.0" position="after">
|
||||
<label for="fetchmail_claim"/>
|
||||
<div>
|
||||
<field name="fetchmail_claim"/>
|
||||
<button type="object" name="configure_fetchmail_claim" string="Configure" icon="gtk-go-forward"
|
||||
attrs="{'invisible': [('fetchmail_claim','=',False)]}"/>
|
||||
</div>
|
||||
</group>
|
||||
</separator>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -368,7 +368,7 @@
|
|||
<field name="priority" eval="1"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="subflow_id" position="after">
|
||||
<field name="directory_id" domain="[('ressource_type_id','=',model_id),('ressource_parent_type_id','=',False)]"/>
|
||||
<field name="directory_id" string="Document Directory" domain="[('ressource_type_id','=',model_id),('ressource_parent_type_id','=',False)]"/>
|
||||
<newline/>
|
||||
</field>
|
||||
</field>
|
||||
|
|
|
@ -17,20 +17,13 @@
|
|||
<notebook>
|
||||
<page string="Email Details">
|
||||
<group>
|
||||
<group string="Addresses">
|
||||
<field name="email_from" required="1"/>
|
||||
<field name="email_to" required="1"/>
|
||||
<field name="email_cc"/>
|
||||
<field name="email_bcc"/>
|
||||
<field name="reply_to"/>
|
||||
</group>
|
||||
<group string="Options">
|
||||
<field name="lang"/>
|
||||
<field name="user_signature"/>
|
||||
</group>
|
||||
<group string="Email Content">
|
||||
<field name="subject" required="1"/>
|
||||
<notebook colspan="2">
|
||||
<notebook colspan="4">
|
||||
<page string="Body (Text)">
|
||||
<field name="body_text" colspan="4" width="250" height="250" nolabel="1"/>
|
||||
</page>
|
||||
|
@ -39,22 +32,21 @@
|
|||
<label string="Note: This is Raw HTML." colspan="4"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</group>
|
||||
<field name="user_signature"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Dynamic Values Builder">
|
||||
<field name="model_object_field"
|
||||
domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]"
|
||||
on_change="onchange_sub_model_object_value_field(model_object_field)"
|
||||
colspan="4"/>
|
||||
<field name="sub_object" readonly="1" colspan="4"/>
|
||||
<field name="sub_model_object_field"
|
||||
domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]"
|
||||
colspan="4"
|
||||
attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}"
|
||||
on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
|
||||
<field name="null_value" colspan="4"
|
||||
on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)" />
|
||||
<field name="copyvalue" colspan="4"/>
|
||||
<group>
|
||||
<field name="model_object_field"
|
||||
domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]"
|
||||
on_change="onchange_sub_model_object_value_field(model_object_field)"/>
|
||||
<field name="sub_object" readonly="1"/>
|
||||
<field name="sub_model_object_field"
|
||||
domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]"
|
||||
attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}"
|
||||
on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
|
||||
<field name="null_value" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)"/>
|
||||
<field name="copyvalue"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
<button name="%(wizard_email_template_preview)d" string="Preview Template"
|
||||
|
@ -82,15 +74,18 @@
|
|||
<field name="track_campaign_item"/>
|
||||
<field name="message_id"/>
|
||||
<field name="auto_delete"/>
|
||||
<field name="lang"/>
|
||||
</group>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Attachments" colspan="2"/>
|
||||
<notebook colspan="2">
|
||||
<page string="Attach Report">
|
||||
<field name="report_template" colspan="4"
|
||||
domain="[('model','=',model)]"/>
|
||||
<field name="report_name" colspan="4" />
|
||||
<group>
|
||||
<field name="report_template" colspan="4"
|
||||
domain="[('model','=',model)]"/>
|
||||
<field name="report_name" colspan="4" />
|
||||
</group>
|
||||
</page>
|
||||
<page string="Attach existing files">
|
||||
<field name="attachment_ids" colspan="4" nolabel="1" height="350"/>
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Synchronization">
|
||||
<separator string="Google Account" colspan="4"/>
|
||||
<field name="gmail_user"/>
|
||||
<field name="gmail_password" password="True"/>
|
||||
<group string="Google Account" colspan="4">
|
||||
<field name="gmail_user"/>
|
||||
<field name="gmail_password" password="True"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
|
|
|
@ -250,13 +250,13 @@ class hr_employee(osv.osv):
|
|||
work_email = self.pool.get('res.users').browse(cr, uid, user_id, context=context).user_email
|
||||
return {'value': {'work_email' : work_email}}
|
||||
|
||||
def _get_photo(self, cr, uid, context=None):
|
||||
def _default_get_photo(self, cr, uid, context=None):
|
||||
photo_path = addons.get_module_resource('hr','images','photo.png')
|
||||
return self._photo_resize(cr, uid, open(photo_path, 'rb').read().encode('base64'), context=context)
|
||||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'photo': _get_photo,
|
||||
'photo': _default_get_photo,
|
||||
'marital': 'single',
|
||||
'color': 0,
|
||||
}
|
||||
|
|
|
@ -21,9 +21,6 @@
|
|||
<form string="Employee" version="7.0">
|
||||
<sheet>
|
||||
<field name="photo" widget='image' class="oe_right" on_change="onchange_photo(photo)"/>
|
||||
<div class="oe_right oe_button_box" name="button_box">
|
||||
<!-- Put here related buttons -->
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1>
|
||||
|
@ -38,6 +35,9 @@
|
|||
<label for="category_ids" class="oe_edit_only"/>
|
||||
<h3><field name="category_ids" widget="many2many_tags"/></h3>
|
||||
</div>
|
||||
<div class="oe_right oe_button_box" name="button_box">
|
||||
<!-- Put here related buttons -->
|
||||
</div>
|
||||
<group colspan="4" col="4">
|
||||
<field name="work_email" widget="email" />
|
||||
<field name="work_phone"/>
|
||||
|
|
|
@ -20,13 +20,11 @@
|
|||
or
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
</header>
|
||||
<group string="Additional Features">
|
||||
<group>
|
||||
<group>
|
||||
<group string="Additional Features" name="left_column">
|
||||
<field name="module_hr_expense"/>
|
||||
<field name="module_hr_evaluation"/>
|
||||
<field name="module_hr_holidays"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="module_hr_recruitment"/>
|
||||
<field name="module_hr_contract"/>
|
||||
<label for="module_hr_payroll"/>
|
||||
|
@ -37,14 +35,11 @@
|
|||
attrs="{'invisible': [('module_hr_payroll','=',False)]}"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Timesheets">
|
||||
<group string="Timesheets" name="right_column">
|
||||
<field name="module_hr_attendance" on_change="onchange_hr_attendance(module_hr_attendance)"/>
|
||||
<field name="module_hr_timesheet" on_change="onchange_hr_timesheet(module_hr_timesheet)"/>
|
||||
<field name="module_hr_timesheet_sheet"/>
|
||||
</group>
|
||||
<group name="config_recruitment"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<field name="inherit_id" ref="hr.view_human_resources_configuration"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- put after the element <div><field name="module_hr_payroll" class="oe_inline"/> ...</div> -->
|
||||
<xpath expr="//field[@name='module_hr_payroll']/.." position="after">
|
||||
<xpath expr="//group[@name='left_column']" position="inside">
|
||||
<field name="module_hr_payroll_account"/>
|
||||
</xpath>
|
||||
</field>
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr.view_human_resources_configuration"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="config_recruitment" position="replace">
|
||||
<group name="config_recruitment" string="Recruitment">
|
||||
<field name="module_document_ftp"/>
|
||||
<label for="fetchmail_applicants"/>
|
||||
<div>
|
||||
<field name="fetchmail_applicants"/>
|
||||
<button name="configure_fetchmail_applicants" type="object" string="Configure" icon="gtk-go-forward"
|
||||
attrs="{'invisible': [('fetchmail_applicants','=',False)]}"/>
|
||||
</div>
|
||||
</group>
|
||||
<group name="right_column" position="inside">
|
||||
<separator string="Recruitment" colspan="2"/>
|
||||
<field name="module_document_ftp"/>
|
||||
<label for="fetchmail_applicants"/>
|
||||
<div>
|
||||
<field name="fetchmail_applicants"/>
|
||||
<button name="configure_fetchmail_applicants" type="object" string="Configure" icon="gtk-go-forward"
|
||||
attrs="{'invisible': [('fetchmail_applicants','=',False)]}"/>
|
||||
</div>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -200,12 +200,12 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<page string="Configuration" position="inside">
|
||||
<separator string="Timesheets" colspan="4"/>
|
||||
<field name="timesheet_range"/>
|
||||
<field name="timesheet_max_difference"/>
|
||||
<newline/>
|
||||
</page>
|
||||
<xpath expr="//group[@name='account_grp']" position="after">
|
||||
<group name="timesheets_grp" string="Timesheets">
|
||||
<field name="timesheet_range"/>
|
||||
<field name="timesheet_max_difference"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
<button string="Apply" type="object" name="execute" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
|
||||
</header>
|
||||
<group>
|
||||
<group string="Wiki">
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="rml_footer2" position="after">
|
||||
<newline/>
|
||||
<group string="BVR data" colspan="4">
|
||||
<field name="bvr_delta_horz"/>
|
||||
<field name="bvr_delta_vert"/>
|
||||
<field name="bvr_scan_line_vert"/>
|
||||
<field name="bvr_scan_line_horz"/>
|
||||
<field name="bvr_scan_line_font_size"/>
|
||||
<field name="bvr_scan_line_letter_spacing"/>
|
||||
<field name="bvr_background"/>
|
||||
<field name="bvr_only"/>
|
||||
<field name="invoice_only"/>
|
||||
</group>
|
||||
<newline/>
|
||||
</field>
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="BVR Data">
|
||||
<group colspan="4">
|
||||
<field name="bvr_delta_horz"/>
|
||||
<field name="bvr_delta_vert"/>
|
||||
<field name="bvr_scan_line_vert"/>
|
||||
<field name="bvr_scan_line_horz"/>
|
||||
<field name="bvr_scan_line_font_size"/>
|
||||
<field name="bvr_scan_line_letter_spacing"/>
|
||||
<field name="bvr_background"/>
|
||||
<field name="bvr_only"/>
|
||||
<field name="invoice_only"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</openerp>
|
||||
|
|
|
@ -11,15 +11,15 @@
|
|||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Paie">
|
||||
<xpath expr="//group[@name='account_grp']" position="after">
|
||||
<group string="Paie">
|
||||
<field name="plafond_secu"/>
|
||||
<field name="nombre_employes"/>
|
||||
<newline/>
|
||||
<field name="org_ss"/>
|
||||
<newline/>
|
||||
<field name="conv_coll"/>
|
||||
</page>
|
||||
</group>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
<field name="priority">22</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<page string="Configuration" position="inside">
|
||||
<group>
|
||||
<field name="manufacturing_lead"/>
|
||||
</group>
|
||||
</page>
|
||||
<xpath expr="//group[@name='logistics_grp']" position="inside">
|
||||
<field name="manufacturing_lead"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -12,22 +12,22 @@
|
|||
or
|
||||
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
|
||||
</header>
|
||||
<group string="Manufacturing Order">
|
||||
<field name="module_mrp_operations"/>
|
||||
<field name="module_stock_planning"/>
|
||||
<field name="module_mrp_subproduct"/>
|
||||
<field name="module_mrp_repair"/>
|
||||
</group>
|
||||
<group string="Logistics">
|
||||
<field name="module_mrp_jit"/>
|
||||
<field name="module_stock_no_autopicking"/>
|
||||
</group>
|
||||
<group string="Bill Of Material">
|
||||
<field name="group_mrp_routings"/>
|
||||
<field name="group_mrp_properties"/>
|
||||
</group>
|
||||
<group string="Products">
|
||||
<field name="module_product_manufacturer"/>
|
||||
<group>
|
||||
<group string="Manufacturing Order">
|
||||
<field name="module_mrp_operations"/>
|
||||
<field name="module_stock_planning"/>
|
||||
<field name="module_mrp_subproduct"/>
|
||||
<field name="module_mrp_repair"/>
|
||||
<separator string="Logistics" colspan="2"/>
|
||||
<field name="module_mrp_jit"/>
|
||||
<field name="module_stock_no_autopicking"/>
|
||||
</group>
|
||||
<group string="Products">
|
||||
<field name="module_product_manufacturer"/>
|
||||
<separator string="Bill Of Material" colspan="2"/>
|
||||
<field name="group_mrp_routings"/>
|
||||
<field name="group_mrp_properties"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -26,17 +26,18 @@
|
|||
<field name="priority" eval="8"/>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Multi Company">
|
||||
<group col="6" colspan="4">
|
||||
<field name="name" colspan="6"/>
|
||||
<separator string="Matching" colspan="6"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="object_id"/>
|
||||
<field name="field_id" domain="[('model_id','=',object_id)]"/>
|
||||
<separator string="Condition" colspan="6"/>
|
||||
<field name="expression" colspan="4"/>
|
||||
<field name="sequence"/>
|
||||
<separator string="Returning" colspan="6"/>
|
||||
<field name="company_dest_id"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="company_dest_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="object_id"/>
|
||||
<field name="field_id" domain="[('model_id','=',object_id)]"/>
|
||||
<field name="expression"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -71,7 +72,7 @@
|
|||
parent="base.menu_custom"
|
||||
sequence="50"/>
|
||||
|
||||
<menuitem id="menu_action_inventory_form"
|
||||
<menuitem id="base.menu_action_inventory_form"
|
||||
action="action_inventory_form"
|
||||
parent="menu_custom_multicompany"/>
|
||||
</data>
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@string='Configuration']" position="inside">
|
||||
<separator string="Pad" colspan="4"/>
|
||||
<field name="pad_url_template"/>
|
||||
<xpath expr="//group[@name='account_grp']" position="after">
|
||||
<group string="Pads">
|
||||
<field name="pad_url_template"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -21,8 +21,11 @@
|
|||
|
||||
import point_of_sale
|
||||
import account_bank_statement
|
||||
import res_users
|
||||
import wizard
|
||||
import report
|
||||
|
||||
import controllers
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -51,22 +51,23 @@ 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',
|
||||
'wizard/pos_session_opening.xml',
|
||||
'point_of_sale_report.xml',
|
||||
'point_of_sale_view.xml',
|
||||
'point_of_sale_data.xml',
|
||||
'report/pos_order_report_view.xml',
|
||||
'report/report_cash_register_view.xml',
|
||||
'point_of_sale_sequence.xml',
|
||||
'point_of_sale_workflow.xml',
|
||||
'account_statement_view.xml',
|
||||
'account_statement_report.xml',
|
||||
'res_users_view.xml',
|
||||
],
|
||||
'demo_xml': [
|
||||
'point_of_sale_demo.xml',
|
||||
|
@ -80,10 +81,24 @@ Main features :
|
|||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'certificate' : '001156338024966477869',
|
||||
# Web client
|
||||
'js': ['static/lib/backbone/backbone-0.5.3.js', 'static/src/js/pos.js'],
|
||||
'css': ['static/src/css/pos.css'],
|
||||
'js': [
|
||||
'static/lib/backbone/backbone-0.9.2.js',
|
||||
'static/lib/mousewheel/jquery.mousewheel-3.0.6.js',
|
||||
'static/src/js/pos_models.js',
|
||||
'static/src/js/pos_basewidget.js',
|
||||
'static/src/js/pos_keyboard_widget.js',
|
||||
'static/src/js/pos_scrollbar_widget.js',
|
||||
'static/src/js/pos_widgets.js',
|
||||
'static/src/js/pos_devices.js',
|
||||
'static/src/js/pos_screens.js',
|
||||
'static/src/js/pos_main.js'
|
||||
],
|
||||
'css': [
|
||||
'static/src/css/pos.css',
|
||||
'static/src/css/keyboard.css'
|
||||
],
|
||||
'qweb': ['static/src/xml/pos.xml'],
|
||||
'auto_install': True,
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -25,53 +25,27 @@ 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"),
|
||||
|
||||
'amount_authorized_diff' : fields.float('Amount Authorized Difference'),
|
||||
'self_checkout_payment_method' : fields.boolean('Self Checkout Payment Method'),
|
||||
}
|
||||
_defaults = {
|
||||
'check_dtls': False,
|
||||
'auto_cash': True,
|
||||
'opening_control' : True,
|
||||
'closing_control' : True,
|
||||
'self_checkout_payment_method' : False,
|
||||
}
|
||||
|
||||
account_journal()
|
||||
|
||||
class account_cash_statement(osv.osv):
|
||||
_inherit = 'account.bank.statement'
|
||||
|
||||
def _equal_balance(self, cr, uid, cash_id, context=None):
|
||||
statement = self.browse(cr, uid, cash_id, context=context)
|
||||
if not statement.journal_id.check_dtls:
|
||||
return True
|
||||
if statement.journal_id.check_dtls and (statement.balance_end != statement.balance_end_cash):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def _get_cash_open_box_lines(self, cr, uid, context=None):
|
||||
res = super(account_cash_statement,self)._get_cash_open_box_lines(cr, uid, context)
|
||||
curr = [0.01, 0.02, 0.05, 0.10, 0.20, 0.50]
|
||||
for rs in curr:
|
||||
dct = {
|
||||
'pieces': rs,
|
||||
'number': 0
|
||||
}
|
||||
res.append(dct)
|
||||
res.sort()
|
||||
return res
|
||||
|
||||
def _get_default_cash_close_box_lines(self, cr, uid, context=None):
|
||||
res = super(account_cash_statement,self)._get_default_cash_close_box_lines(cr, uid, context=context)
|
||||
curr = [0.01, 0.02, 0.05, 0.10, 0.20, 0.50]
|
||||
for rs in curr:
|
||||
dct = {
|
||||
'pieces': rs,
|
||||
'number': 0
|
||||
}
|
||||
res.append(dct)
|
||||
res.sort()
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'pos_session_id' : fields.many2one('pos.session'),
|
||||
}
|
||||
account_cash_statement()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<page string="Point of Sale">
|
||||
<group col="6" colspan="4">
|
||||
<separator colspan="6" string="Extended Configuration"/>
|
||||
<group col="4" colspan="4">
|
||||
<field name="journal_user"/>
|
||||
<field name="auto_cash"/>
|
||||
<field name="check_dtls"/>
|
||||
<field name="opening_control"/>
|
||||
<field name="closing_control"/>
|
||||
<field name="amount_authorized_diff"/>
|
||||
<field name="self_checkout_payment_method" />
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
@ -133,6 +134,7 @@
|
|||
<field name="act_window_id" ref="action_new_bank_statement_all_tree"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
<menuitem name="Cash Register Management" parent="point_of_sale.menu_point_root"
|
||||
id="menu_point_open_config" sequence="10"/>
|
||||
<menuitem
|
||||
|
@ -160,6 +162,7 @@
|
|||
id="menu_all_menu_all_register"
|
||||
sequence="4"
|
||||
/>
|
||||
-->
|
||||
|
||||
|
||||
</data>
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
# -*- 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)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def scan_item_success(self, request):
|
||||
"""
|
||||
A product has been scanned with success
|
||||
"""
|
||||
print 'scan_item_success'
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def scan_item_error_unrecognized(self, request):
|
||||
"""
|
||||
A product has been scanned without success
|
||||
"""
|
||||
print 'scan_item_error_unrecognized'
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def help_needed(self, request):
|
||||
"""
|
||||
The user wants an help (ex: light is on)
|
||||
"""
|
||||
print "help_needed"
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def help_canceled(self, request):
|
||||
"""
|
||||
The user stops the help request
|
||||
"""
|
||||
print "help_canceled"
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def weighting_start(self, request):
|
||||
print "weighting_start"
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def weighting_read_kg(self, request):
|
||||
print "weighting_read_kg"
|
||||
return 0.0
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def weighting_end(self, request):
|
||||
print "weighting_end"
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def payment_request(self, request, price, method, info):
|
||||
"""
|
||||
The PoS will activate the method payment
|
||||
"""
|
||||
print "payment_request: price:"+str(price)+" method:"+str(method)+" info:"+str(info)
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def is_payment_accepted(self, request):
|
||||
print "is_payment_accepted"
|
||||
return 'waiting_for_payment'
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def payment_canceled(self, request):
|
||||
print "payment_canceled"
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def transaction_start(self, request):
|
||||
print 'transaction_start'
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def transaction_end(self, request):
|
||||
print 'transaction_end'
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def cashier_mode_activated(self, request):
|
||||
print 'cashier_mode_activated'
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def cashier_mode_deactivated(self, request):
|
||||
print 'cashier_mode_deactivated'
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def open_cashbox(self, request):
|
||||
print 'open_cashbox'
|
||||
return
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def print_receipt(self, request, receipt):
|
||||
print 'print_receipt' + str(receipt)
|
||||
return
|
||||
|
|
@ -0,0 +1,525 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<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="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="barcode_test_sheet.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.86706515"
|
||||
inkscape:cx="381.55817"
|
||||
inkscape:cy="505.31292"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1176"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g4158"
|
||||
transform="matrix(0.92675002,0,0,0.92675002,27.597551,38.360312)">
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text2985"
|
||||
y="72.12545"
|
||||
x="140.86679"
|
||||
style="font-size:46.51613998px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium"
|
||||
y="72.12545"
|
||||
x="140.86679"
|
||||
id="tspan2987"
|
||||
sodipodi:role="line">BARCODE TEST SHEET</tspan></text>
|
||||
<g
|
||||
transform="translate(0,-5.3405762e-5)"
|
||||
id="g3347">
|
||||
<image
|
||||
y="124.14642"
|
||||
x="388.17426"
|
||||
id="image3083"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACYCAIAAAB/IAJdAAAAA3NCSVQICAjb4U/gAAADqUlEQVR4 nO3a226jMABFUYjy/7/MPCChDBfHARM4zVpP1dQY4u66JEw/DEO3S9/3XdeNh79+vRwz2hr5OmZr 5JH5t0YuX0X51W0dW3PNNa9xOWf5au8wsrxu9Ud95HHkYPg+yRJGsoSRLGEkSxjJEkayhJEsYSRL GMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJ EkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJG soSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKE kSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEs YSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEk SxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxh+mEY dh7Z913XjYe/fv3LrMlS8zWxyxJGsjuNGwbf91z911Z/1GY/18oJ689+cOTb7LZmPtJr/ZrcfOTu 1SucseaQlV221f6xnKdm5vqznzHy1Nn6vq9fk5SRrYzzry7RzHyXbd7r9HszXVP9b3bN/EdGlq/k 0y250uu0W2tSv3oXjvxo9d4ahmE6b/mP58ou2/BNbuUr3Hf2M0aOzthRVn8M5QurX71rR87sXr1h GGa/z6tT/Zds2y12+TpfP+nYOqp+/rYjZ4esXvzk0zkLlmtSv3rXjlx1/F3QMtzZgMfse1d9jvi1 t1zND2HScPUK2+2j+cl2uEmvl/Bh2Zat+4TH64gLruvzs599C3vSOqz+Yf1LvZ60estwn93ehdt9 ez5zk1vYJmrW5C9lWqNVJ5OnW4IjR31kudFWvqe5v/NWb/lE47n6jbOvo3xZhbOfMfLL7n97fRNb j9/WH9j+mgtTtsUW5hzNN6PVMx2/iMLO93ba798tfPp6d398tjyqfqFu+I9vv7XD1uY6Ofd/ci0/ o/5ZhR/2lvrVu3ZkK7PPX7ee2px1YzA9Mn77S/Nrlj/+1UdNlat37ciGCncCMyfuslsP/e7mazey y22j8Pi3fvWuHdlq9cYZap6H/wMqFm5yx9XfMwAAAABJRU5ErkJggg== "
|
||||
height="107.96206"
|
||||
width="163.36363" />
|
||||
<rect
|
||||
style="fill:none;stroke:#c3c3c3;stroke-width:1.07903957;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3086"
|
||||
width="417.54495"
|
||||
height="126.4052"
|
||||
x="141.08452"
|
||||
y="114.51707"
|
||||
rx="2.0839903"
|
||||
ry="2.0839903" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:27.53050041px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="201.46712"
|
||||
y="147.73848"
|
||||
id="text3856"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3858"
|
||||
x="201.46712"
|
||||
y="147.73848"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">CASHIER</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3860"
|
||||
y="182.10147"
|
||||
x="154.5717"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium"
|
||||
y="182.10147"
|
||||
x="154.5717"
|
||||
id="tspan3862"
|
||||
sodipodi:role="line">Prefix: 40</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="200.85837"
|
||||
id="text3149"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3151"
|
||||
x="154.5717"
|
||||
y="200.85837"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">ID: 4447190000</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,0.97855377)"
|
||||
id="g3335">
|
||||
<g
|
||||
id="g3173"
|
||||
transform="translate(0,-3.2620699)">
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3153"
|
||||
y="341.12738"
|
||||
x="154.5717"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium"
|
||||
y="341.12738"
|
||||
x="154.5717"
|
||||
id="tspan3155"
|
||||
sodipodi:role="line">Prefix: 42</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="359.88428"
|
||||
id="text3157"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3159"
|
||||
x="154.5717"
|
||||
y="359.88428"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">ID: 1182180000</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g3954"
|
||||
transform="translate(0,-18.756902)">
|
||||
<rect
|
||||
style="fill:none;stroke:#c3c3c3;stroke-width:1.07903957;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3876"
|
||||
width="417.54495"
|
||||
height="126.4052"
|
||||
x="141.08452"
|
||||
y="284.96024"
|
||||
rx="2.0839903"
|
||||
ry="2.0839903" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:27.53050041px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="209.6223"
|
||||
y="318.18164"
|
||||
id="text3878"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3880"
|
||||
x="209.6223"
|
||||
y="318.18164"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">CLIENT</tspan></text>
|
||||
<image
|
||||
width="162.31204"
|
||||
height="107.26709"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACYCAIAAAB/IAJdAAAAA3NCSVQICAjb4U/gAAADyUlEQVR4 nO3a3Y6qShSFUTC+/yvXuSAxbCgQsPiZp8e46mgJq/ETxe6+lNId0vd913XDw8c/z+8d3zIYP2p8 y9LKLbcvbXN8y5Zt/jLn0jHZcnzm29z+m961cmn+vY/a5fXLg+F6kiWMZAkjWcJIljCSJYxkCSNZ wkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJI ljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYw kiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIl jGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxk CSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkj WcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nC 9KWUg4/s+67rhoePf/7LHJO55sfEWZYwj0t2eCG2XXmGe/f+l72rt7Z6U5s8r1832LbX+ZqlAc6b 85qpbln59SDs7afvN31MrZxlm5w/+r6fb6d644H9Huu1euOpcx6eqnrj0n7vXdnKsP31Iz+YnmWb TzZ+3Wx/wqoOrJzvfeml3HDO36ear1wa/saV62fovafYUspnv+tv8pWzbMPPA5NNjS8bL1Dd+9gt c36dqnrX+pNy78qJw8etlDJ53VY39U+ybZ+kjb9nGWm1cpfmc/5o6RwzfyHdu3LX8NvNw50seE3u a/J8XPC8bjH5bavXPdfP+XWqXG0TGm92fJTezXf2BJ8PRtsvzy/wzKkea3Je/yT6mqw41e0vjI27 vnjO/0evJx20+eeEd3f0vWnXx/OlC52TVA/f8P6yPsCPc64fk8NTRTt8GbfkffYZ5eJYu9ULiJU+ zp7z2FQpzqtocj4tpbyrdzSZY7zNJz8fKXP+NfNYhx/qf7BtuL+HR5Ay55OdcYpdOY+8Ss1n6Y9z pHTwqDmXvgGdl3HvypNMvtKa7/GU/+S695uB7Qf9yjkPpDD/hn/JvStbmcdaPSxnfTDoVn/PK783 +GXZBdcTS/utfoO7dPV218qGtl9RPO7/ZZuovkBv/5vcrqmqK5c2e+PKVu9Uwxa2PEf/AXnknj+O sxSLAAAAAElFTkSuQmCC "
|
||||
id="image3951"
|
||||
x="388.17426"
|
||||
y="294.58957" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,0.3261795)"
|
||||
id="g3322">
|
||||
<rect
|
||||
style="fill:none;stroke:#c3c3c3;stroke-width:1.07903957;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3964"
|
||||
width="417.54495"
|
||||
height="126.4052"
|
||||
x="141.08452"
|
||||
y="419.52063"
|
||||
rx="2.0839903"
|
||||
ry="2.0839903" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:27.53050041px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="209.6223"
|
||||
y="452.74203"
|
||||
id="text3966"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3968"
|
||||
x="209.6223"
|
||||
y="452.74203"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">WEIGHT</tspan></text>
|
||||
<image
|
||||
width="162.12962"
|
||||
height="107.14654"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACYCAIAAAB/IAJdAAAAA3NCSVQICAjb4U/gAAAERElEQVR4 nO3a0ZKaQBRFUbX8/182D1QZInRzadDxTNZ6mjgNNrhBYHJ9PB6XIdfr9XK5TIvPf57/drJ8/ayR rVdaG9Wfc+Vd+vPc+3N/hv3XK68st2i5Xa09XNnS+sjKthfdjiwMnydZwkiWMJIljGQJI1nCSJYw kiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIl jGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxk CSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkj WcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nC SJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiW MJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCS Jcz18XgMLnm9Xi6XafH5z/8z+2Tp9H3iLEuYDyU7HV7njuT/dH/+9NLKid9o5/Zan+fYFnW+vFrT 27uv+hPb3AnLt1su0prSO/beWeVcr6XL1Ns0dLnNqy+OzeOskfV5Dm9RZ8BZe2N1YgfXWXlx11u/ Y2TftFTlM7rP/zFv/B378eDIp+I8V89enUO5MpMjXz7P9S/nP59V/3zWOiX317k6/9aw5TqPj9z0 eDyea+vfpd1Wt/ny7y3eN6jP88jX9wdu8Jfzn2wuWD84W1cOm8Navz1rZN/LfmidcW/H36nz9pUP oz7yUs6uuLa5dx+cB5/vvOmRWeuAb52ex0bunVL/W/Se8uDw+Dw3r1MHTnVjs5qvpP6m9QuG7/lu HNa5Trg3F/oVKrfSR05ge5dt3awMH5DPj7b+0KA/n+/xcrZ+7qhmsm/6JjpdfZ6dMZuLd+5yBuxa ydgHsbxsnS4N407Gy3BXkm3d6KyuqzLyTSrzXH5Cex+Cdt5ifoabBlT2SSWmutZGtVb4+UxP7+Sf v34979EGbl8+aWye9RuIuoMnv039Ge66AVruqy//lCcvzw3+XhjsvSH4Ke+YZ+dR/DfvijFBW9S6 071fylcCP644z19T2wc25GsvZzvnpnvrF1/rxHl2rvZWL3lbTxuK77V6ifmZaPpH+8vlZmeeYyPH ptqa8C3lnPTjj5OW6xz7dlr9Q93YrFoP7Vfz6s+kOM+DI/uWl63r095c0VnP8A8+M9/cF8XHN8Xn WfUT6nCvm2uo7Lf6lu6af32eu7aoo36X8jv/i/fqAXrwBrm1zr0rKa6heJzXt3TXE4P6PI/vk/lS lc/oD6RX6TSeNJuDAAAAAElFTkSuQmCC "
|
||||
id="image4065"
|
||||
x="387.35876"
|
||||
y="429.14993" />
|
||||
<g
|
||||
transform="translate(0,140.26901)"
|
||||
id="g3179">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="341.12738"
|
||||
id="text3181"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3183"
|
||||
x="154.5717"
|
||||
y="341.12738"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">Prefix: 21</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3185"
|
||||
y="359.88428"
|
||||
x="154.5717"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium"
|
||||
y="359.88428"
|
||||
x="154.5717"
|
||||
id="tspan3187"
|
||||
sodipodi:role="line">ID: 12345</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="379.4567"
|
||||
id="text3189"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3191"
|
||||
x="154.5717"
|
||||
y="379.4567"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">Value: 67.89Kg</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,-1.9572678)"
|
||||
id="g3308">
|
||||
<rect
|
||||
ry="2.0839903"
|
||||
rx="2.0839903"
|
||||
y="574.46893"
|
||||
x="141.08452"
|
||||
height="126.4052"
|
||||
width="417.54495"
|
||||
id="rect4081"
|
||||
style="fill:none;stroke:#c3c3c3;stroke-width:1.07903957;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<g
|
||||
id="g3296">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:27.53050041px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="195.7585"
|
||||
y="607.69037"
|
||||
id="text4083"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4085"
|
||||
x="195.7585"
|
||||
y="607.69037"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">DISCOUNT</tspan></text>
|
||||
<image
|
||||
y="584.09827"
|
||||
x="385.72772"
|
||||
id="image4202"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACYCAIAAAB/IAJdAAAAA3NCSVQICAjb4U/gAAADsElEQVR4 nO3aXXOiMACGUej4//8ye+EMZYHECBF96zlXHTd8iE8jYTtO0zQcMo7jMAz3zUs/b8ffLUcuXymN bHn92ZHtR3l2ZOnnpfazOvauS3toP3rLyPr5tGx1wM+ZjeF6kiWMZAkjWcJIljCSJYxkCSNZwkiW MJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCS JYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWM ZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJ I1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZ wkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJI ljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCjNM0 HdxyHIdhuG++/PmbuSZb3a+JWZYwH5fs/RfxL42kr9vuq6/4UmvZZ0qFZ3pdbVu5II0jSyezO777 0XdP4Fg549h0m7ozy75i/mjZZ0qFHXst7W0cx92RjZufPPrJkc+e1XKT3fe4sp5lr+81pb/zV2be wzyXzJ9TaXZZvl45gZbJqf3oZ0ZWBtdN0zTvrf6FvDPLvmKRa+E8W16K+nf36l+Xi+7XHf3kyIeD 6/tZpb/7Zv+bZd9yS9A4kQSN3FWaOe6zy3ZOumYhsT36s+fZ3eo3c3vE32TfteRi5cDlal8qvcKq qi4TX+U+4bb7ahd6fZfLrvwcVq+HBts9bMO9rUb0pdeOtiFWVj/v1fFz34Z7G46+yfrt+SdcuOu1 L1meUl+Qbc/h2Jr98IltHyMsD939mvy4Jfhk86p5tZquu+bKVxZqQ785a/Xc4PfGoPJA+OTfzfTd 5/dYfU5vPJN3Ka0p9//Dlvcq3Ql8j8pv7K3yNPvMM+Hu+0xXeq5ZuSwPr1Vp2931e+PRD5xnXw8f 2H3cX3L9ecuPpMu902on9Rn64dHbR5buWQ/Hvb1t3d2JG4PrlJ5itvzJ1e74px6Lth/9qfOsn2q7 9nt3s+ylSuvrMzts32f3kaWjH3hT901atv0Hm+wpnHOLKX0AAAAASUVORK5CYII= "
|
||||
height="108.34499"
|
||||
width="163.94308"
|
||||
inkscape:transform-center-x="-24.4145"
|
||||
inkscape:transform-center-y="6.3942733" />
|
||||
<g
|
||||
transform="translate(0,296.03285)"
|
||||
id="g3210">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="341.12738"
|
||||
id="text3212"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3214"
|
||||
x="154.5717"
|
||||
y="341.12738"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">Prefix: 44</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3216"
|
||||
y="359.88428"
|
||||
x="154.5717"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium"
|
||||
y="359.88428"
|
||||
x="154.5717"
|
||||
id="tspan3218"
|
||||
sodipodi:role="line">ID: 11111</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="379.4567"
|
||||
id="text3220"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3222"
|
||||
x="154.5717"
|
||||
y="379.4567"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">Value: 25%</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,-0.97866058)"
|
||||
id="g3283">
|
||||
<rect
|
||||
style="fill:none;stroke:#c3c3c3;stroke-width:1.07903957;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect4115"
|
||||
width="417.54495"
|
||||
height="126.4052"
|
||||
x="141.08452"
|
||||
y="726.15521"
|
||||
rx="2.0839903"
|
||||
ry="2.0839903" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:27.53050041px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="212.88437"
|
||||
y="759.37659"
|
||||
id="text4117"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4119"
|
||||
x="212.88437"
|
||||
y="759.37659"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">PRICE</tspan></text>
|
||||
<image
|
||||
width="163.36363"
|
||||
height="107.96206"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACYCAIAAAB/IAJdAAAAA3NCSVQICAjb4U/gAAAD70lEQVR4 nO3Z3XKbOhiGUezJ/d8yPfBsbwaB+Phz/aZrHaWukDB+goE8xnEcDnk8HsMwvDaf/tz+7/SVl3bR drbEkWvHZG3O/gytyvxrq6yt265emWfvyMq7K3qe2Rg+T7KEkSxhJEsYyRJGsoSRLGEkSxjJEkay hJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSR LGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxh JEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRL GMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJ EkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJG soSRLGEkSxjJEkayhJEsYSRLGMkSRrKEkSxhJEsYyRJGsoSRLGEkSxjJEkayhJEsYSRLmMc4jge3 fDyGYXhtPv35X+aYtC4/Js6yhJHsX/M65bDXz/un2RG85ButPufvG9lX6fXYWp0v37VFK4M/c0wq 2z4XV118Ze/yi3PWX6zP+W0jN21uVT9Q9Zl37Wr9nV57TCrv8We6xrvx9/bnz7XTGTp70w5bWz1l ZGvvZzmbdnO5yvyVXa33cGE54zi+Z+vfpT2n2yz+fED7Tqb/nB7ZxZ3rfE99/8jzdn19HxhTVO/h qnLGcZydERYPxXOt6DavA3twctv6aeP7Rw7/fSSzD6YzrDLn21U3c/UebiqnDXc24Ge4gYeRd9i8 Tt31pf/ytZ9U5zrhlmTPq/+Opow8pp2/jaze69r83xnu7Gz93tWPPpdtD9Dil8hiBykj79O5Wths bnp3cezC429prxOOn2V3XXSv3ZC1AzZ988gLb2HbSRbPiPXL6MUXL3w0VFn6klVuP8u+7/vWfrPb 19NH3qR+A7R3zm82e24wjuON17KzlfqD68cuZeTHrP3hY/jKva1bu1O8K9nNK4Hi5r9mZN0vqO28 zvnu53VBs/aHjZMH7uQ17uLzuS8f+UmL63YuedeeNszmLPZwUzmbj+Gei0NPnjzqO9056KEjr9JO fv4ksvbEY/Pd9d/pVeW0l63LO7b4+Oa9zeG1+wMWT2Cbq6eMrOj31zmAxS+uk/t/x294X/3O5/+z +oV/F9mVbLvJxh6HjOyrnDKPfSK7fhk6c94xsq/4rO0Pc0/7XuEpWE8AAAAASUVORK5CYII= "
|
||||
id="image4264"
|
||||
x="386.54324"
|
||||
y="734.96906" />
|
||||
<g
|
||||
transform="translate(0,442.82599)"
|
||||
id="g3224">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="341.12738"
|
||||
id="text3226"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3228"
|
||||
x="154.5717"
|
||||
y="341.12738"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">Prefix: 02</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3230"
|
||||
y="359.88428"
|
||||
x="154.5717"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium"
|
||||
y="359.88428"
|
||||
x="154.5717"
|
||||
id="tspan3232"
|
||||
sodipodi:role="line">ID: 99999</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="379.4567"
|
||||
id="text3234"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3236"
|
||||
x="154.5717"
|
||||
y="379.4567"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">Value: 134.50€</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3269">
|
||||
<g
|
||||
id="g3061"
|
||||
transform="translate(0,284.6156)">
|
||||
<g
|
||||
id="g3063"
|
||||
transform="translate(0,154.94832)">
|
||||
<rect
|
||||
ry="2.0839903"
|
||||
rx="2.0839903"
|
||||
y="438.27753"
|
||||
x="141.08452"
|
||||
height="126.4052"
|
||||
width="417.54495"
|
||||
id="rect3065"
|
||||
style="fill:none;stroke:#c3c3c3;stroke-width:1.07903957;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3067"
|
||||
y="471.49893"
|
||||
x="216.61778"
|
||||
style="font-size:27.53050041px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium"
|
||||
y="471.49893"
|
||||
x="216.61778"
|
||||
sodipodi:role="line"
|
||||
id="tspan3083">UNIT</tspan></text>
|
||||
<g
|
||||
transform="translate(0,156.57936)"
|
||||
id="g3071" />
|
||||
</g>
|
||||
</g>
|
||||
<image
|
||||
y="887.47076"
|
||||
x="386.54324"
|
||||
id="image3146"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACYCAIAAAB/IAJdAAAAA3NCSVQICAjb4U/gAAADz0lEQVR4
|
||||
nO3Z0ZKaMACGUdnx/V+ZXjBjGWKyEQjyt+fcdIsBY/ZTgZ3meX7sMk3T4/FYdq/9XI5frB9db18/
|
||||
Wh6nfJZyr/Yz9s+t/Yp65tw/22+N3Pe6asevhdQ/stPPkZ3hepIljGQJI1nCSJYwkiWMZAkjWcJI
|
||||
ljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYw
|
||||
kiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIl
|
||||
jGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxk
|
||||
CSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkj
|
||||
WcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nC
|
||||
SJYwkiWMZAkjWcJIljCSJYxkCSNZwkiWMJIljGQJI1nCSJYwkiWMZAkjWcJIljCSJYxkCSNZwkzz
|
||||
PO/cc5oej8ey+/rn/5k1KZ2+Jj5lCSNZwjyXf5ZP7NKJ32v9XwrtkZupNg743ZH3nNWgV3p8WZaD
|
||||
9Oz4Uz7fCP1P0Rg5TVP5aG38d0fWfHFW/av36TofX5bXLm+PtvF8/TTuQuGUXl/W83y9zs3kX8d5
|
||||
bb9yZM0dZtWzev0jy2f/9bA18zy/jtb+mr3oXLZ/9u3zgc2j7cOuH71+5K1m1b96B9d5+e+isUvt
|
||||
OJv0336EDU/23I/Y0vruyfo45ZJdM7LmnrM6MnLQXbwy3M2AZ+2xU6Zy1iUXN7eO55RfYuM84Vnb
|
||||
53hD1/R6wbXjP+z4d2Dt2ut4uJvP9ddhf9Zn0LvPQtrPesrIt19heu3Uv3r71nlEPOsjr2fyrF0t
|
||||
/nrd1z7lH3cKe+dMj1+cjTbi91Jefi1XTsv209ekevl1w1OC8k084m39r+pfvY/WefT6b+4bzPNc
|
||||
PZc95clqGzevs3/k2y30O/FUbbTa/YCByV7jzucJ9zf6FuRujVsQb/56sdnnrHfbwbOF2nwag7+1
|
||||
ccfrGr2xf/XOWudye6dfb7b+vB13eq/HvZ1J+61f3ve+cuStZtW/emet845yytPW95NZ37PdOLfX
|
||||
49dkH83zst/cR6v0xVn1r96gdW7r/2PE33tYI/76Vc7p+G2ED15b9ysaMfKes9q3emetc1vjjura
|
||||
Hwkp3Xa7HcbMAAAAAElFTkSuQmCC
|
||||
"
|
||||
height="108.34499"
|
||||
width="163.94308" />
|
||||
<g
|
||||
id="g3255"
|
||||
transform="translate(0,598.58983)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:17.41555405px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="154.5717"
|
||||
y="351.81107"
|
||||
id="text3261"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3263"
|
||||
x="154.5717"
|
||||
y="351.81107"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Medium">ID: 5449000000996</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0,-1,1,0,261.82237,1622.2884)"
|
||||
id="g4150">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
|
||||
x="618.97778"
|
||||
y="320.0275"
|
||||
id="text3357"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3359"
|
||||
x="618.97778"
|
||||
y="320.0275">This is a test sheet intended to help you test the codebar aquisition in OpenERP's Point of Sale module. </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="618.97778"
|
||||
y="330.0275"
|
||||
id="tspan3363">The codes provided in this list are randomly chosen and are encoded in the EAN13 format. Their codes</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="618.97778"
|
||||
y="340.0275"
|
||||
id="tspan3367">and prefixes are not intended to match any specified standard. </tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3369"
|
||||
y="349.54001"
|
||||
x="618.99207"
|
||||
style="font-size:6.53564215px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#b3b3b3;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan3375"
|
||||
y="349.54001"
|
||||
x="618.99207"
|
||||
sodipodi:role="line"
|
||||
style="fill:#b3b3b3;fill-opacity:1">This document is licensed by OpenERP S.A. under the Creative Commons CC BY 3.0 license htttp://www.creativecommons.org</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 31 KiB |
|
@ -18,6 +18,10 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import pdb
|
||||
import io
|
||||
import openerp
|
||||
import addons
|
||||
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
@ -33,18 +37,395 @@ import decimal_precision as dp
|
|||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class pos_config_journal(osv.osv):
|
||||
""" Point of Sale journal configuration"""
|
||||
_name = 'pos.config.journal'
|
||||
_description = "Journal Configuration"
|
||||
class pos_config(osv.osv):
|
||||
_name = 'pos.config'
|
||||
|
||||
POS_CONFIG_STATE = [
|
||||
('active', 'Active'),
|
||||
('inactive', 'Inactive'),
|
||||
('deprecated', 'Deprecated')
|
||||
]
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Description', size=64),
|
||||
'code': fields.char('Code', size=64),
|
||||
'journal_id': fields.many2one('account.journal', "Journal")
|
||||
'name' : fields.char('Point of Sale Name', size=32, select=1,
|
||||
required=True, help="An internal identification of the point of sale"),
|
||||
'journal_ids' : fields.many2many('account.journal', 'pos_config_journal_rel',
|
||||
'pos_config_id', 'journal_id', 'Available Payment Methods',
|
||||
domain="[('journal_user', '=', True )]",),
|
||||
'shop_id' : fields.many2one('sale.shop', 'Shop',
|
||||
required=True),
|
||||
'journal_id' : fields.many2one('account.journal', 'Sale Journal',
|
||||
required=True, domain=[('type', '=', 'sale')],
|
||||
help="Accounting journal used to post sales entries."),
|
||||
'iface_self_checkout' : fields.boolean('Self Checkout Mode',
|
||||
help="Check this if this point of sale should open by default in a self checkout mode. If unchecked, OpenERP uses the normal cashier mode by default."),
|
||||
'iface_websql' : fields.boolean('WebSQL (Faster but Chrome Only)',
|
||||
help="If have more than 200 products, it's highly suggested to use WebSQL "\
|
||||
"to store the data in the browser, instead of localStore mechanism. "\
|
||||
"It's more efficient but works on the Chrome browser only."
|
||||
),
|
||||
'iface_led' : fields.boolean('Help Notification'),
|
||||
'iface_cashdrawer' : fields.boolean('Cashdrawer Interface'),
|
||||
'iface_payment_terminal' : fields.boolean('Payment Terminal Interface'),
|
||||
'iface_electronic_scale' : fields.boolean('Electronic Scale Interface'),
|
||||
'iface_barscan' : fields.boolean('BarScan Interface'),
|
||||
'iface_vkeyboard' : fields.boolean('Virtual KeyBoard Interface'),
|
||||
'iface_print_via_proxy' : fields.boolean('Print via Proxy'),
|
||||
|
||||
'state' : fields.selection(POS_CONFIG_STATE, 'State', required=True, readonly=True),
|
||||
'sequence_id' : fields.many2one('ir.sequence', 'Order IDs Sequence', readonly=True,
|
||||
help="This sequence is automatically created by OpenERP but you can change it "\
|
||||
"to customize the reference numbers of your orders."),
|
||||
'session_ids': fields.one2many('pos.session', 'config_id', 'Sessions'),
|
||||
'group_by' : fields.boolean('Group By', help="Check this if you want to group the Journal Items by Product while closing a Session"),
|
||||
}
|
||||
|
||||
pos_config_journal()
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
result = []
|
||||
states = {
|
||||
'opening_control': _('Opening Control'),
|
||||
'opened': _('In Progress'),
|
||||
'closing_control': _('Closing Control'),
|
||||
'closed': _('Closed & Posted'),
|
||||
}
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
if (not record.session_ids) or (record.session_ids[0].state=='closed'):
|
||||
result.append((record.id, record.name+' ('+_('not used')+')'))
|
||||
continue
|
||||
session = record.session_ids[0]
|
||||
result.append((record.id, record.name + ' ('+session.user_id.name+', '+states[session.state]+')'))
|
||||
return result
|
||||
|
||||
|
||||
def _default_payment_journal(self, cr, uid, context=None):
|
||||
res = self.pool.get('account.journal').search(cr, uid, [('type', 'in', ('bank','cash'))], limit=2)
|
||||
return res or []
|
||||
|
||||
def _default_sale_journal(self, cr, uid, context=None):
|
||||
res = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale')], limit=1)
|
||||
return res and res[0] or False
|
||||
|
||||
def _default_shop(self, cr, uid, context=None):
|
||||
res = self.pool.get('sale.shop').search(cr, uid, [])
|
||||
return res and res[0] or False
|
||||
|
||||
_defaults = {
|
||||
'state' : POS_CONFIG_STATE[0][0],
|
||||
'shop_id': _default_shop,
|
||||
'journal_id': _default_sale_journal,
|
||||
'journal_ids': _default_payment_journal,
|
||||
'group_by' : True,
|
||||
}
|
||||
|
||||
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')
|
||||
sequence_values = dict(
|
||||
name='PoS %s' % values['name'],
|
||||
padding=5,
|
||||
prefix="%s/" % values['name'],
|
||||
)
|
||||
sequence_id = proxy.create(cr, uid, sequence_values, context=context)
|
||||
values['sequence_id'] = sequence_id
|
||||
return super(pos_config, self).create(cr, uid, values, context=context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
if obj.sequence_id:
|
||||
obj.sequence_id.unlink()
|
||||
return super(pos_config, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
pos_config()
|
||||
|
||||
class pos_session(osv.osv):
|
||||
_name = 'pos.session'
|
||||
_order = 'id desc'
|
||||
|
||||
POS_SESSION_STATE = [
|
||||
('opening_control', 'Opening Control'), # Signal open
|
||||
('opened', 'In Progress'), # Signal closing
|
||||
('closing_control', 'Closing Control'), # Signal close
|
||||
('closed', 'Closed & Posted'),
|
||||
]
|
||||
|
||||
def _compute_cash_register_id(self, cr, uid, ids, fieldnames, args, context=None):
|
||||
result = dict.fromkeys(ids, False)
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
for st in record.statement_ids:
|
||||
if st.journal_id.type == 'cash':
|
||||
result[record.id] = st.id
|
||||
break
|
||||
return result
|
||||
|
||||
def _compute_controls(self, cr, uid, ids, fieldnames, args, context=None):
|
||||
result = {}
|
||||
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
has_opening_control = False
|
||||
has_closing_control = False
|
||||
|
||||
for journal in record.config_id.journal_ids:
|
||||
if journal.opening_control == True:
|
||||
has_opening_control = True
|
||||
if journal.closing_control == True:
|
||||
has_closing_control = True
|
||||
|
||||
if has_opening_control and has_closing_control:
|
||||
break
|
||||
|
||||
values = {
|
||||
'has_opening_control': has_opening_control,
|
||||
'has_closing_control': has_closing_control,
|
||||
}
|
||||
result[record.id] = values
|
||||
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'config_id' : fields.many2one('pos.config', 'Point of Sale',
|
||||
help="The physical point of sale you will use.",
|
||||
required=True,
|
||||
select=1,
|
||||
domain="[('state', '=', 'active')]",
|
||||
# readonly=True,
|
||||
# states={'draft' : [('readonly', False)]}
|
||||
),
|
||||
|
||||
'name' : fields.char('Session ID', size=32,
|
||||
required=True,
|
||||
# readonly=True,
|
||||
# states={'draft' : [('readonly', False)]}
|
||||
),
|
||||
'user_id' : fields.many2one('res.users', 'Responsible',
|
||||
required=True,
|
||||
select=1,
|
||||
# readonly=True,
|
||||
# states={'draft' : [('readonly', False)]}
|
||||
),
|
||||
'start_at' : fields.datetime('Opening Date'),
|
||||
'stop_at' : fields.datetime('Closing Date'),
|
||||
|
||||
'state' : fields.selection(POS_SESSION_STATE, 'State',
|
||||
required=True, readonly=True,
|
||||
select=1),
|
||||
|
||||
'cash_register_id' : fields.function(_compute_cash_register_id, method=True,
|
||||
type='many2one', relation='account.bank.statement',
|
||||
string='Cash Register', store=True),
|
||||
|
||||
'opening_details_ids' : fields.related('cash_register_id', 'opening_details_ids',
|
||||
type='one2many', relation='account.cashbox.line',
|
||||
string='Opening Cash Control'),
|
||||
'details_ids' : fields.related('cash_register_id', 'details_ids',
|
||||
type='one2many', relation='account.cashbox.line',
|
||||
string='Cash Control'),
|
||||
|
||||
'cash_register_balance_end_real' : fields.related('cash_register_id', 'balance_end_real',
|
||||
type='float',
|
||||
digits_compute=dp.get_precision('Account'),
|
||||
string="Ending Balance",
|
||||
help="Computed using the cash control lines",
|
||||
readonly=True),
|
||||
'cash_register_balance_start' : fields.related('cash_register_id', 'balance_start',
|
||||
type='float',
|
||||
digits_compute=dp.get_precision('Account'),
|
||||
string="Starting Balance",
|
||||
help="Computed using the cash control at the opening.",
|
||||
readonly=True),
|
||||
'cash_register_total_entry_encoding' : fields.related('cash_register_id', 'total_entry_encoding',
|
||||
string='Total Cash Transaction',
|
||||
readonly=True),
|
||||
'cash_register_balance_end' : fields.related('cash_register_id', 'balance_end',
|
||||
type='float',
|
||||
digits_compute=dp.get_precision('Account'),
|
||||
string="Computed Balance",
|
||||
help="Computed with the initial cash control and the sum of all payments.",
|
||||
readonly=True),
|
||||
'cash_register_difference' : fields.related('cash_register_id', 'difference',
|
||||
type='float',
|
||||
string='Difference',
|
||||
help="Difference between the counted cash control at the closing and the computed balance.",
|
||||
readonly=True),
|
||||
|
||||
'journal_ids' : fields.related('config_id', 'journal_ids',
|
||||
type='many2many',
|
||||
readonly=True,
|
||||
relation='account.journal',
|
||||
string='Available Payment Methods'),
|
||||
'order_ids' : fields.one2many('pos.order', 'session_id', 'Orders'),
|
||||
|
||||
'statement_ids' : fields.one2many('account.bank.statement', 'pos_session_id', 'Bank Statement', readonly=True),
|
||||
'has_opening_control' : fields.function(_compute_controls, string='Has Opening Control', multi='control', type='boolean'),
|
||||
'has_closing_control' : fields.function(_compute_controls, string='Has Closing Control', multi='control', type='boolean'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'name' : '/',
|
||||
'user_id' : lambda obj, cr, uid, context: uid,
|
||||
'state' : 'opening_control',
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('uniq_name', 'unique(name)', "The name of this POS Session must be unique !"),
|
||||
]
|
||||
|
||||
def _check_unicity(self, cr, uid, ids, context=None):
|
||||
for session in self.browse(cr, uid, ids, context=None):
|
||||
# open if there is no session in 'opening_control', 'opened', 'closing_control' for one user
|
||||
domain = [
|
||||
('state', '!=', 'closed'),
|
||||
('user_id', '=', uid)
|
||||
]
|
||||
count = self.search_count(cr, uid, domain, context=context)
|
||||
if count>1:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _check_pos_config(self, cr, uid, ids, context=None):
|
||||
for session in self.browse(cr, uid, ids, context=None):
|
||||
domain = [
|
||||
('state', '!=', 'closed'),
|
||||
('config_id', '=', session.config_id.id)
|
||||
]
|
||||
count = self.search_count(cr, uid, domain, context=context)
|
||||
if count>1:
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_unicity, "You can not create two active sessions with the same responsible!", ['user_id', 'state']),
|
||||
(_check_pos_config, "You can not create two active sessions related to the same point of sale!", ['config_id']),
|
||||
]
|
||||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
config_id = values.get('config_id', False) or False
|
||||
|
||||
pos_config = None
|
||||
if config_id:
|
||||
pos_config = self.pool.get('pos.config').browse(cr, uid, config_id, context=context)
|
||||
|
||||
bank_statement_ids = []
|
||||
for journal in pos_config.journal_ids:
|
||||
bank_values = {
|
||||
'journal_id' : journal.id,
|
||||
'user_id' : uid,
|
||||
}
|
||||
statement_id = self.pool.get('account.bank.statement').create(cr, uid, bank_values, context=context)
|
||||
bank_statement_ids.append(statement_id)
|
||||
|
||||
values.update({
|
||||
'name' : pos_config.sequence_id._next(),
|
||||
'statement_ids' : [(6, 0, bank_statement_ids)]
|
||||
})
|
||||
|
||||
return super(pos_session, self).create(cr, uid, values, context=context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
for statement in obj.statement_ids:
|
||||
statement.unlink(context=context)
|
||||
return True
|
||||
|
||||
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)
|
||||
for st in record.statement_ids:
|
||||
st.button_open(context=context)
|
||||
return True
|
||||
|
||||
def wkf_action_opening_control(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state' : 'opening_control'}, context=context)
|
||||
|
||||
def wkf_action_closing_control(self, cr, uid, ids, context=None):
|
||||
for session in self.browse(cr, uid, ids, context=context):
|
||||
for statement in session.statement_ids:
|
||||
if not statement.journal_id.closing_control:
|
||||
if statement.balance_end<>statement.balance_end_real:
|
||||
self.pool.get('account.bank.statement').write(cr, uid,
|
||||
[statement.id], {'balance_end_real': statement.balance_end})
|
||||
return self.write(cr, uid, ids, {'state' : 'closing_control', 'stop_at' : time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
|
||||
|
||||
def wkf_action_close(self, cr, uid, ids, context=None):
|
||||
# Close CashBox
|
||||
bsl = self.pool.get('account.bank.statement.line')
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
for st in record.statement_ids:
|
||||
if abs(st.difference) > st.journal_id.amount_authorized_diff:
|
||||
# The pos manager can close statements with maximums.
|
||||
if not self.pool.get('ir.model.access').check_groups(cr, uid, "point_of_sale.group_pos_manager"):
|
||||
raise osv.except_osv( _('Error !'),
|
||||
_("Your ending balance is too different from the theorical cash closing (%.2f), the maximum allowed is: %.2f. You can contact your manager to force it.") % (st.difference, st.journal_id.amount_authorized_diff))
|
||||
if st.difference:
|
||||
if st.difference > 0.0:
|
||||
name= _('Point of Sale Profit')
|
||||
account_id = st.journal_id.profit_account_id.id
|
||||
else:
|
||||
account_id = st.journal_id.loss_account_id.id
|
||||
name= _('Point of Sale Loss')
|
||||
if not account_id:
|
||||
raise osv.except_osv( _('Error !'),
|
||||
_("Please set your profit and loss accounts on your payment method '%s'.") % (st.journal_id.name,))
|
||||
bsl.create(cr, uid, {
|
||||
'statement_id': st.id,
|
||||
'amount': st.difference,
|
||||
'ref': record.name,
|
||||
'name': name,
|
||||
'account_id': account_id
|
||||
}, context=context)
|
||||
|
||||
getattr(st, 'button_confirm_%s' % st.journal_id.type)(context=context)
|
||||
self._confirm_orders(cr, uid, ids, context=context)
|
||||
return self.write(cr, uid, ids, {'state' : 'closed'}, context=context)
|
||||
|
||||
def _confirm_orders(self, cr, uid, ids, context=None):
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
|
||||
for session in self.browse(cr, uid, ids, context=context):
|
||||
order_ids = [order.id for order in session.order_ids if order.state == 'paid']
|
||||
|
||||
move_id = self.pool.get('account.move').create(cr, uid, {'ref' : session.name, 'journal_id' : session.config_id.journal_id.id, }, context=context)
|
||||
|
||||
self.pool.get('pos.order')._create_account_move_line(cr, uid, order_ids, session, move_id, context=context)
|
||||
|
||||
for order in session.order_ids:
|
||||
if order.state != 'paid':
|
||||
raise osv.except_osv(
|
||||
_('Error !'),
|
||||
_("You can not confirm all orders of this session, because they have not the 'paid' status"))
|
||||
else:
|
||||
wf_service.trg_validate(uid, 'pos.order', order.id, 'done', cr)
|
||||
|
||||
return True
|
||||
|
||||
def open_frontend_cb(self, cr, uid, ids, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
if not ids:
|
||||
return {}
|
||||
|
||||
context.update({'session_id' : ids[0]})
|
||||
return {
|
||||
'type' : 'ir.actions.client',
|
||||
'name' : 'Start Point Of Sale',
|
||||
'tag' : 'pos.ui',
|
||||
'context' : context,
|
||||
}
|
||||
|
||||
pos_session()
|
||||
|
||||
class pos_order(osv.osv):
|
||||
_name = "pos.order"
|
||||
|
@ -53,25 +434,30 @@ class pos_order(osv.osv):
|
|||
|
||||
def create_from_ui(self, cr, uid, orders, context=None):
|
||||
#_logger.info("orders: %r", orders)
|
||||
list = []
|
||||
for order in orders:
|
||||
order_ids = []
|
||||
for tmp_order in orders:
|
||||
order = tmp_order['data']
|
||||
# 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')
|
||||
# get statements out of order because they will be generated with add_payment to ensure
|
||||
# the module behavior is the same when using the front-end or the back-end
|
||||
statement_ids = order.pop('statement_ids')
|
||||
statement_ids = order.get('statement_ids', [])
|
||||
order_id = self.create(cr, uid, order, context)
|
||||
list.append(order_id)
|
||||
order_ids.append(order_id)
|
||||
# call add_payment; refer to wizard/pos_payment for data structure
|
||||
# add_payment launches the 'paid' signal to advance the workflow to the 'paid' state
|
||||
|
||||
data = {
|
||||
'journal': statement_ids[0][2]['journal_id'],
|
||||
'amount': order['amount_paid'],
|
||||
'payment_name': order['name'],
|
||||
'payment_date': statement_ids[0][2]['name'],
|
||||
}
|
||||
order_obj.add_payment(cr, uid, order_id, data, context=context)
|
||||
return list
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr)
|
||||
wf_service.trg_write(uid, 'pos.order', order_id, cr)
|
||||
|
||||
#self.add_payment(cr, uid, order_id, data, context=context)
|
||||
return order_ids
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
for rec in self.browse(cr, uid, ids, context=context):
|
||||
|
@ -107,14 +493,6 @@ class pos_order(osv.osv):
|
|||
res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1)
|
||||
return res
|
||||
|
||||
def _default_sale_journal(self, cr, uid, context=None):
|
||||
res = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale')], limit=1)
|
||||
return res and res[0] or False
|
||||
|
||||
def _default_shop(self, cr, uid, context=None):
|
||||
res = self.pool.get('sale.shop').search(cr, uid, [])
|
||||
return res and res[0] or False
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
if not default:
|
||||
default = {}
|
||||
|
@ -131,13 +509,11 @@ 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),
|
||||
'date_order': fields.datetime('Date Ordered', readonly=True, select=True),
|
||||
'user_id': fields.many2one('res.users', 'Connected Salesman', help="Person who uses the the cash register. It could be a reliever, a student or an interim employee."),
|
||||
'shop_id': fields.related('session_id', 'config_id', 'shop_id', relation='sale.shop', type='many2one', string='Shop', store=True, readonly=True),
|
||||
'date_order': fields.datetime('Order Date', readonly=True, select=True),
|
||||
'user_id': fields.many2one('res.users', 'Salesman', help="Person who uses the the cash register. It could be a reliever, a student or an interim employee."),
|
||||
'amount_tax': fields.function(_amount_all, string='Taxes', digits_compute=dp.get_precision('Point Of Sale'), multi='all'),
|
||||
'amount_total': fields.function(_amount_all, string='Total', multi='all'),
|
||||
'amount_paid': fields.function(_amount_all, string='Paid', states={'draft': [('readonly', False)]}, readonly=True, digits_compute=dp.get_precision('Point Of Sale'), multi='all'),
|
||||
|
@ -147,6 +523,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'),
|
||||
|
@ -159,9 +542,15 @@ class pos_order(osv.osv):
|
|||
'picking_id': fields.many2one('stock.picking', 'Picking', readonly=True),
|
||||
'note': fields.text('Internal Notes'),
|
||||
'nb_print': fields.integer('Number of Print', readonly=True),
|
||||
'sale_journal': fields.many2one('account.journal', 'Journal', required=True, states={'draft': [('readonly', False)]}, readonly=True),
|
||||
|
||||
'sale_journal': fields.related('session_id', 'config_id', 'journal_id', relation='account.journal', type='many2one', string='Sale Journal', store=True, readonly=True),
|
||||
}
|
||||
|
||||
def _default_session(self, cr, uid, context=None):
|
||||
so = self.pool.get('pos.session')
|
||||
session_ids = so.search(cr, uid, [('state','=', 'opened'), ('user_id','=',uid)], context=context)
|
||||
return session_ids and session_ids[0] or False
|
||||
|
||||
def _default_pricelist(self, cr, uid, context=None):
|
||||
res = self.pool.get('sale.shop').search(cr, uid, [], context=context)
|
||||
if res:
|
||||
|
@ -172,15 +561,18 @@ 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,
|
||||
'session_id': _default_session,
|
||||
'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
|
||||
'sale_journal': _default_sale_journal,
|
||||
'shop_id': _default_shop,
|
||||
'pricelist_id': _default_pricelist,
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -244,18 +636,6 @@ class pos_order(osv.osv):
|
|||
picking_obj.force_assign(cr, uid, [picking_id], context)
|
||||
return True
|
||||
|
||||
def set_to_draft(self, cr, uid, ids, *args):
|
||||
if not len(ids):
|
||||
return False
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
if order.state<>'cancel':
|
||||
raise osv.except_osv(_('Error!'), _('In order to set to draft a sale, it must be cancelled.'))
|
||||
self.write(cr, uid, ids, {'state': 'draft'})
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
for i in ids:
|
||||
wf_service.trg_create(uid, 'pos.order', i, cr)
|
||||
return True
|
||||
|
||||
def cancel_order(self, cr, uid, ids, context=None):
|
||||
""" Changes order state to cancel
|
||||
@return: True
|
||||
|
@ -270,6 +650,8 @@ class pos_order(osv.osv):
|
|||
|
||||
def add_payment(self, cr, uid, order_id, data, context=None):
|
||||
"""Create a new payment for the order"""
|
||||
if not context:
|
||||
context = {}
|
||||
statement_obj = self.pool.get('account.bank.statement')
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
prod_obj = self.pool.get('product.product')
|
||||
|
@ -277,11 +659,10 @@ class pos_order(osv.osv):
|
|||
curr_c = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
|
||||
curr_company = curr_c.id
|
||||
order = self.browse(cr, uid, order_id, context=context)
|
||||
ids_new = []
|
||||
args = {
|
||||
'amount': data['amount'],
|
||||
}
|
||||
if 'payment_date' in data.keys():
|
||||
if 'payment_date' in data:
|
||||
args['date'] = data['payment_date']
|
||||
args['name'] = order.name
|
||||
if data.get('payment_name', False):
|
||||
|
@ -298,22 +679,31 @@ class pos_order(osv.osv):
|
|||
msg = _('There is no receivable account defined to make payment for the partner: "%s" (id:%d)') % (order.partner_id.name, order.partner_id.id,)
|
||||
raise osv.except_osv(_('Configuration Error !'), msg)
|
||||
|
||||
statement_id = statement_obj.search(cr,uid, [
|
||||
('journal_id', '=', int(data['journal'])),
|
||||
('company_id', '=', curr_company),
|
||||
('user_id', '=', uid),
|
||||
('state', '=', 'open')], context=context)
|
||||
if len(statement_id) == 0:
|
||||
context.pop('pos_session_id', False)
|
||||
|
||||
try:
|
||||
journal_id = long(data['journal'])
|
||||
except Exception:
|
||||
journal_id = False
|
||||
|
||||
statement_id = False
|
||||
for statement in order.session_id.statement_ids:
|
||||
if statement.journal_id.id == journal_id:
|
||||
statement_id = statement.id
|
||||
break
|
||||
|
||||
if not statement_id:
|
||||
raise osv.except_osv(_('Error !'), _('You have to open at least one cashbox'))
|
||||
if statement_id:
|
||||
statement_id = statement_id[0]
|
||||
args['statement_id'] = statement_id
|
||||
args['pos_statement_id'] = order_id
|
||||
args['journal_id'] = int(data['journal'])
|
||||
args['type'] = 'customer'
|
||||
args['ref'] = order.name
|
||||
|
||||
args.update({
|
||||
'statement_id' : statement_id,
|
||||
'pos_statement_id' : order_id,
|
||||
'journal_id' : journal_id,
|
||||
'type' : 'customer',
|
||||
'ref' : order.name,
|
||||
})
|
||||
|
||||
statement_line_obj.create(cr, uid, args, context=context)
|
||||
ids_new.append(statement_id)
|
||||
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr)
|
||||
|
@ -432,49 +822,120 @@ class pos_order(osv.osv):
|
|||
}
|
||||
|
||||
def create_account_move(self, cr, uid, ids, context=None):
|
||||
return self._create_account_move_line(cr, uid, ids, None, None, context=context)
|
||||
|
||||
def _create_account_move_line(self, cr, uid, ids, session=None, move_id=None, context=None):
|
||||
# Tricky, via the workflow, we only have one id in the ids variable
|
||||
"""Create a account move line of order grouped by products or not."""
|
||||
account_move_obj = self.pool.get('account.move')
|
||||
account_move_line_obj = self.pool.get('account.move.line')
|
||||
account_period_obj = self.pool.get('account.period')
|
||||
period = account_period_obj.find(cr, uid, context=context)[0]
|
||||
account_tax_obj = self.pool.get('account.tax')
|
||||
res_obj=self.pool.get('res.users')
|
||||
property_obj=self.pool.get('ir.property')
|
||||
user_proxy = self.pool.get('res.users')
|
||||
property_obj = self.pool.get('ir.property')
|
||||
|
||||
period = account_period_obj.find(cr, uid, context=context)[0]
|
||||
|
||||
#session_ids = set(order.session_id for order in self.browse(cr, uid, ids, context=context))
|
||||
|
||||
if session and not all(session.id == order.session_id.id for order in self.browse(cr, uid, ids, context=context)):
|
||||
raise osv.except_osv(_('Error!'), _('The selected orders do not have the same session !'))
|
||||
|
||||
current_company = user_proxy.browse(cr, uid, uid, context=context).company_id
|
||||
|
||||
grouped_data = {}
|
||||
have_to_group_by = session and session.config_id.group_by or False
|
||||
|
||||
def compute_tax(amount, tax, line):
|
||||
if amount > 0:
|
||||
tax_code_id = tax['base_code_id']
|
||||
tax_amount = line.price_subtotal * tax['base_sign']
|
||||
else:
|
||||
tax_code_id = tax['ref_base_code_id']
|
||||
tax_amount = line.price_subtotal * tax['ref_base_sign']
|
||||
|
||||
return (tax_code_id, tax_amount,)
|
||||
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
if order.state<>'paid': continue
|
||||
if order.account_move:
|
||||
continue
|
||||
if order.state != 'paid':
|
||||
continue
|
||||
|
||||
user_company = user_proxy.browse(cr, order.user_id.id, order.user_id.id).company_id
|
||||
|
||||
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
|
||||
comp_id = comp_id and comp_id.id or False
|
||||
to_reconcile = []
|
||||
group_tax = {}
|
||||
account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context).id
|
||||
|
||||
order_account = order.partner_id and order.partner_id.property_account_receivable and order.partner_id.property_account_receivable.id or account_def or curr_c.account_receivable.id
|
||||
order_account = order.partner_id and \
|
||||
order.partner_id.property_account_receivable and \
|
||||
order.partner_id.property_account_receivable.id or account_def or current_company.account_receivable.id
|
||||
|
||||
# Create an entry for the sale
|
||||
move_id = account_move_obj.create(cr, uid, {
|
||||
'journal_id': order.sale_journal.id,
|
||||
}, context=context)
|
||||
if move_id is None:
|
||||
# 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)
|
||||
|
||||
def insert_data(data_type, values):
|
||||
# if have_to_group_by:
|
||||
|
||||
sale_journal_id = order.sale_journal.id
|
||||
|
||||
# 'quantity': line.qty,
|
||||
# 'product_id': line.product_id.id,
|
||||
values.update({
|
||||
'date': order.date_order[:10],
|
||||
'ref': order.name,
|
||||
'journal_id' : sale_journal_id,
|
||||
'period_id' : period,
|
||||
'move_id' : move_id,
|
||||
'company_id': user_company and user_company.id or False,
|
||||
})
|
||||
|
||||
if data_type == 'product':
|
||||
key = ('product', values['product_id'],)
|
||||
elif data_type == 'tax':
|
||||
key = ('tax', values['tax_code_id'],)
|
||||
elif data_type == 'counter_part':
|
||||
key = ('counter_part', values['partner_id'], values['account_id'])
|
||||
else:
|
||||
return
|
||||
|
||||
grouped_data.setdefault(key, [])
|
||||
|
||||
# if not have_to_group_by or (not grouped_data[key]):
|
||||
# grouped_data[key].append(values)
|
||||
# else:
|
||||
# pass
|
||||
|
||||
if have_to_group_by:
|
||||
if not grouped_data[key]:
|
||||
grouped_data[key].append(values)
|
||||
else:
|
||||
current_value = grouped_data[key][0]
|
||||
current_value['quantity'] = current_value.get('quantity', 0.0) + values.get('quantity', 0.0)
|
||||
current_value['credit'] = current_value.get('credit', 0.0) + values.get('credit', 0.0)
|
||||
current_value['debit'] = current_value.get('debit', 0.0) + values.get('debit', 0.0)
|
||||
current_value['tax_amount'] = current_value.get('tax_amount', 0.0) + values.get('tax_amount', 0.0)
|
||||
else:
|
||||
grouped_data[key].append(values)
|
||||
|
||||
# Create an move for each order line
|
||||
|
||||
for line in order.lines:
|
||||
tax_amount = 0
|
||||
taxes = [t for t in line.product_id.taxes_id]
|
||||
computed = account_tax_obj.compute_all(cr, uid, taxes, line.price_unit * (100.0-line.discount) / 100.0, line.qty)
|
||||
computed_taxes = computed['taxes']
|
||||
computed_taxes = account_tax_obj.compute_all(cr, uid, taxes, line.price_unit * (100.0-line.discount) / 100.0, line.qty)['taxes']
|
||||
|
||||
for tax in computed_taxes:
|
||||
tax_amount += round(tax['amount'], 2)
|
||||
group_key = (tax['tax_code_id'],
|
||||
tax['base_code_id'],
|
||||
tax['account_collected_id'])
|
||||
group_key = (tax['tax_code_id'], tax['base_code_id'], tax['account_collected_id'], tax['id'])
|
||||
|
||||
group_tax.setdefault(group_key, 0)
|
||||
group_tax[group_key] += round(tax['amount'], 2)
|
||||
|
||||
if group_key in group_tax:
|
||||
group_tax[group_key] += round(tax['amount'], 2)
|
||||
else:
|
||||
group_tax[group_key] = round(tax['amount'], 2)
|
||||
amount = line.price_subtotal
|
||||
|
||||
# Search for the income account
|
||||
|
@ -492,110 +953,80 @@ class pos_order(osv.osv):
|
|||
tax_amount = 0
|
||||
while computed_taxes:
|
||||
tax = computed_taxes.pop(0)
|
||||
if amount > 0:
|
||||
tax_code_id = tax['base_code_id']
|
||||
tax_amount = line.price_subtotal * tax['base_sign']
|
||||
else:
|
||||
tax_code_id = tax['ref_base_code_id']
|
||||
tax_amount = line.price_subtotal * tax['ref_base_sign']
|
||||
tax_code_id, tax_amount = compute_tax(amount, tax, line)
|
||||
|
||||
# If there is one we stop
|
||||
if tax_code_id:
|
||||
break
|
||||
|
||||
|
||||
# Create a move for the line
|
||||
account_move_line_obj.create(cr, uid, {
|
||||
'name': line.name,
|
||||
'date': order.date_order[:10],
|
||||
'ref': order.name,
|
||||
insert_data('product', {
|
||||
'name': line.product_id.name,
|
||||
'quantity': line.qty,
|
||||
'product_id': line.product_id.id,
|
||||
'move_id': move_id,
|
||||
'account_id': income_account,
|
||||
'company_id': comp_id,
|
||||
'credit': ((amount>0) and amount) or 0.0,
|
||||
'debit': ((amount<0) and -amount) or 0.0,
|
||||
'journal_id': order.sale_journal.id,
|
||||
'period_id': period,
|
||||
'tax_code_id': tax_code_id,
|
||||
'tax_amount': tax_amount,
|
||||
'partner_id': order.partner_id and order.partner_id.id or False
|
||||
}, context=context)
|
||||
})
|
||||
|
||||
# For each remaining tax with a code, whe create a move line
|
||||
for tax in computed_taxes:
|
||||
if amount > 0:
|
||||
tax_code_id = tax['base_code_id']
|
||||
tax_amount = line.price_subtotal * tax['base_sign']
|
||||
else:
|
||||
tax_code_id = tax['ref_base_code_id']
|
||||
tax_amount = line.price_subtotal * tax['ref_base_sign']
|
||||
tax_code_id, tax_amount = compute_tax(amount, tax, line)
|
||||
if not tax_code_id:
|
||||
continue
|
||||
|
||||
account_move_line_obj.create(cr, uid, {
|
||||
'name': "Tax" + line.name,
|
||||
'date': order.date_order[:10],
|
||||
'ref': order.name,
|
||||
insert_data('tax', {
|
||||
'name': _('Tax'),
|
||||
'product_id':line.product_id.id,
|
||||
'quantity': line.qty,
|
||||
'move_id': move_id,
|
||||
'account_id': income_account,
|
||||
'company_id': comp_id,
|
||||
'credit': 0.0,
|
||||
'debit': 0.0,
|
||||
'journal_id': order.sale_journal.id,
|
||||
'period_id': period,
|
||||
'tax_code_id': tax_code_id,
|
||||
'tax_amount': tax_amount,
|
||||
}, context=context)
|
||||
|
||||
})
|
||||
|
||||
# Create a move for each tax group
|
||||
(tax_code_pos, base_code_pos, account_pos)= (0, 1, 2)
|
||||
for key, amount in group_tax.items():
|
||||
account_move_line_obj.create(cr, uid, {
|
||||
'name': 'Tax',
|
||||
'date': order.date_order[:10],
|
||||
'ref': order.name,
|
||||
'move_id': move_id,
|
||||
'company_id': comp_id,
|
||||
(tax_code_pos, base_code_pos, account_pos, tax_id)= (0, 1, 2, 3)
|
||||
|
||||
for key, tax_amount in group_tax.items():
|
||||
tax = self.pool.get('account.tax').browse(cr, uid, key[tax_id], context=context)
|
||||
insert_data('tax', {
|
||||
'name': _('Tax') + ' ' + tax.name,
|
||||
'quantity': line.qty,
|
||||
'product_id': line.product_id.id,
|
||||
'account_id': key[account_pos],
|
||||
'credit': ((amount>0) and amount) or 0.0,
|
||||
'debit': ((amount<0) and -amount) or 0.0,
|
||||
'journal_id': order.sale_journal.id,
|
||||
'period_id': period,
|
||||
'credit': ((tax_amount>0) and tax_amount) or 0.0,
|
||||
'debit': ((tax_amount<0) and -tax_amount) or 0.0,
|
||||
'tax_code_id': key[tax_code_pos],
|
||||
'tax_amount': amount,
|
||||
}, context=context)
|
||||
'tax_amount': tax_amount,
|
||||
})
|
||||
|
||||
# counterpart
|
||||
to_reconcile.append(account_move_line_obj.create(cr, uid, {
|
||||
'name': order.name,
|
||||
'date': order.date_order[:10],
|
||||
'ref': order.name,
|
||||
'move_id': move_id,
|
||||
'company_id': comp_id,
|
||||
insert_data('counter_part', {
|
||||
'name': _("Trade Receivables"), #order.name,
|
||||
'account_id': order_account,
|
||||
'credit': ((order.amount_total < 0) and -order.amount_total)\
|
||||
or 0.0,
|
||||
'debit': ((order.amount_total > 0) and order.amount_total)\
|
||||
or 0.0,
|
||||
'journal_id': order.sale_journal.id,
|
||||
'period_id': period,
|
||||
'credit': ((order.amount_total < 0) and -order.amount_total) or 0.0,
|
||||
'debit': ((order.amount_total > 0) and order.amount_total) or 0.0,
|
||||
'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)
|
||||
})
|
||||
|
||||
order.write({'state':'done', 'account_move': move_id})
|
||||
|
||||
for group_key, group_data in grouped_data.iteritems():
|
||||
for value in group_data:
|
||||
account_move_line_obj.create(cr, uid, value, context=context)
|
||||
|
||||
return True
|
||||
|
||||
def action_payment(self, cr, uid, ids, context=None):
|
||||
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
|
||||
|
||||
|
@ -711,7 +1142,7 @@ pos_order_line()
|
|||
|
||||
class pos_category(osv.osv):
|
||||
_name = 'pos.category'
|
||||
_description = "PoS Category"
|
||||
_description = "Point of Sale Category"
|
||||
_order = "sequence, name"
|
||||
def _check_recursion(self, cr, uid, ids, context=None):
|
||||
level = 100
|
||||
|
@ -743,13 +1174,43 @@ class pos_category(osv.osv):
|
|||
res = self.name_get(cr, uid, ids, context=context)
|
||||
return dict(res)
|
||||
|
||||
def _get_small_image(self, cr, uid, ids, prop, unknow_none, context=None):
|
||||
result = {}
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
if not obj.category_image:
|
||||
result[obj.id] = False
|
||||
continue
|
||||
|
||||
image_stream = io.BytesIO(obj.category_image.decode('base64'))
|
||||
img = Image.open(image_stream)
|
||||
img.thumbnail((120, 100), Image.ANTIALIAS)
|
||||
img_stream = StringIO.StringIO()
|
||||
img.save(img_stream, "JPEG")
|
||||
result[obj.id] = img_stream.getvalue().encode('base64')
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True, translate=True),
|
||||
'complete_name': fields.function(_name_get_fnc, type="char", string='Name'),
|
||||
'parent_id': fields.many2one('pos.category','Parent Category', select=True),
|
||||
'child_id': fields.one2many('pos.category', 'parent_id', string='Children Categories'),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of product categories."),
|
||||
'category_image': fields.binary('Image'),
|
||||
'category_image_small': fields.function(_get_small_image, string='Small Image', type="binary",
|
||||
store = {
|
||||
'pos.category': (lambda self, cr, uid, ids, c={}: ids, ['category_image'], 10),
|
||||
}),
|
||||
}
|
||||
|
||||
def _get_default_image(self, cr, uid, context=None):
|
||||
image_path = openerp.modules.get_module_resource('point_of_sale', 'images', 'default_category_photo.png')
|
||||
return open(image_path, 'rb').read().encode('base64')
|
||||
|
||||
|
||||
_defaults = {
|
||||
'category_image': _get_default_image,
|
||||
}
|
||||
|
||||
pos_category()
|
||||
|
||||
import io, StringIO
|
||||
|
@ -772,15 +1233,20 @@ class product_product(osv.osv):
|
|||
return result
|
||||
|
||||
_columns = {
|
||||
'income_pdt': fields.boolean('PoS Cash Input', help="This is a product you can use to put cash into a statement for the point of sale backend."),
|
||||
'expense_pdt': fields.boolean('PoS Cash Output', help="This is a product you can use to take cash from a statement for the point of sale backend, exemple: money lost, transfer to bank, etc."),
|
||||
'pos_categ_id': fields.many2one('pos.category','PoS Category',
|
||||
'income_pdt': fields.boolean('Point of Sale Cash In', help="This is a product you can use to put cash into a statement for the point of sale backend."),
|
||||
'expense_pdt': fields.boolean('Point of Sale Cash Out', help="This is a product you can use to take cash from a statement for the point of sale backend, exemple: money lost, transfer to bank, etc."),
|
||||
'pos_categ_id': fields.many2one('pos.category','Point of Sale Category',
|
||||
help="If you want to sell this product through the point of sale, select the category it belongs to."),
|
||||
'product_image_small': fields.function(_get_small_image, string='Small Image', type="binary",
|
||||
store = {
|
||||
'product.product': (lambda self, cr, uid, ids, c={}: ids, ['product_image'], 10),
|
||||
})
|
||||
}),
|
||||
'to_weight' : fields.boolean('To Weight', help="This category contains products that should be weighted, mainly used for the self-checkout interface"),
|
||||
}
|
||||
_defaults = {
|
||||
'to_weight' : False,
|
||||
}
|
||||
|
||||
product_product()
|
||||
|
||||
|
||||
|
|
|
@ -3,15 +3,9 @@
|
|||
<data>
|
||||
|
||||
|
||||
<menuitem
|
||||
id="stock.next_id_61"
|
||||
name="Reporting"
|
||||
parent="stock.menu_stock_root" groups="base.group_user"/>
|
||||
|
||||
<menuitem action="stock.action_picking_tree" id="stock.menu_action_picking_tree"
|
||||
parent="stock.menu_stock_root" sequence="19" groups="res_groups_posuser0"/>
|
||||
<menuitem parent="stock.next_id_61" action="stock.action_stock_line_date"
|
||||
id="stock.menu_report_stock_line_date" groups="base.group_user"/>
|
||||
<record model="pos.config" id="pos_config_main">
|
||||
<field name="name">Main PoS</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -76,5 +76,11 @@
|
|||
rml="point_of_sale/report/pos_payment_report_user.rml"
|
||||
/>
|
||||
|
||||
<report id="report_user_label"
|
||||
model="res.users"
|
||||
name="point_of_sale.user.label"
|
||||
string="User Labels"
|
||||
xml="point_of_sale/report/user_label.xml"
|
||||
xsl="point_of_sale/report/user_label.xsl"/>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -16,28 +16,27 @@
|
|||
<field name="model">pos.order</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="PoS Orders" version="7.0">
|
||||
<header>
|
||||
<button name="%(action_pos_payment)d" string="Payment" type="action" states="draft" class="oe_highlight"/>
|
||||
<button name="%(action_report_pos_receipt)d" string="Reprint" type="action" states="paid,done,invoiced"/>
|
||||
<button name="action_invoice" string="Invoice" icon="gtk-apply" type="object" states="paid" attrs="{'readonly': [('partner_id','=',False)]}" class="oe_highlight"/>
|
||||
<button name="done" string="Post Entries" icon="gtk-apply" type="workflow" states="paid" class="oe_highlight"/>
|
||||
<button name="refund" string="Return Products" type="object"
|
||||
attrs="{'invisible':[('state','=','draft')]}"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,paid,done" statusbar_colors='{"cancel":"red"}'/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_customer':1}" attrs="{'readonly': [('state','=','invoiced')]}"/>
|
||||
</group><group>
|
||||
<field name="name"/>
|
||||
<field name="date_order"/>
|
||||
</group>
|
||||
<form string="Point of Sale Orders" version="7.0">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="%(action_pos_payment)d" string="Payment" icon="gtk-apply" type="action" states="draft" context="{'pos_session_id' : session_id}"/>
|
||||
<button name="action_invoice" string="Invoice" icon="gtk-apply" type="object" states="paid" attrs="{'readonly': [('partner_id','=',False)]}"/>
|
||||
<button name="refund" string="Return Products" type="object" icon="gtk-ok"
|
||||
attrs="{'invisible':[('state','=','draft')]}"/>
|
||||
<button name="%(action_report_pos_receipt)d" string="Reprint" icon="gtk-print" type="action" states="paid,done,invoiced"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,paid,done" statusbar_colors='{"cancel":"red"}'/>
|
||||
</div>
|
||||
</div>
|
||||
<sheet>
|
||||
<group col="4" colspan="4">
|
||||
<field name="name"/>
|
||||
<field name="date_order"/>
|
||||
<field name="session_id" required="1" />
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_customer':1}" attrs="{'readonly': [('state','=','invoiced')]}"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Sale Order">
|
||||
<field name="lines">
|
||||
<notebook colspan="4">
|
||||
<page string="Products">
|
||||
<field name="lines" colspan="4" nolabel="1">
|
||||
<tree string="Order lines" editable="bottom">
|
||||
<field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,qty,parent.partner_id)"/>
|
||||
<field name="qty" on_change="onchange_qty(product_id, discount, qty, price_unit, context)"/>
|
||||
|
@ -64,8 +63,8 @@
|
|||
<button name="button_dummy" string="Update" icon="gtk-execute" states="draft" />
|
||||
</group>
|
||||
</page>
|
||||
<page string="Payment">
|
||||
<field name="statement_ids">
|
||||
<page string="Payments">
|
||||
<field name="statement_ids" colspan="4" nolabel="1">
|
||||
<tree editable="bottom" string="Statement lines">
|
||||
<field name="journal_id"/>
|
||||
<field name="statement_id" />
|
||||
|
@ -107,7 +106,7 @@
|
|||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="action_pos_pos_form">
|
||||
<field name="name">PoS Orders</field>
|
||||
<field name="name">Orders</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">pos.order</field>
|
||||
<field name="view_type">form</field>
|
||||
|
@ -622,6 +621,7 @@
|
|||
<group name="status" position="after">
|
||||
<group name="pos" string="Point of Sale">
|
||||
<field name="pos_categ_id"/>
|
||||
<field name="to_weight" />
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
|
@ -634,11 +634,13 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="product.product_normal_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_id" position="after">
|
||||
<separator string="Point of Sale" colspan="2"/>
|
||||
<field name="income_pdt"/>
|
||||
<field name="expense_pdt"/>
|
||||
</field>
|
||||
<group name="misc" position="after">
|
||||
<group name="pos" colspan="2" col="2">
|
||||
<separator string="Point of Sale" colspan="2"/>
|
||||
<field name="income_pdt"/>
|
||||
<field name="expense_pdt"/>
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
@ -648,13 +650,16 @@
|
|||
<field name="model">pos.category</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="PoS Categories" version="7.0">
|
||||
<form string="Product PoS Categories" version="7.0">
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
<field name="category_image" widget='image' class="oe_avatar oe_right"/>
|
||||
<div class="oe_left">
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
</div>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -665,14 +670,14 @@
|
|||
<field name="type">tree</field>
|
||||
<field name="field_parent" eval="False"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="PoS Categories">
|
||||
<tree string="Product PoS Categories">
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="complete_name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="pos_category_action" model="ir.actions.act_window">
|
||||
<field name="name">PoS Categories</field>
|
||||
<field name="name">Product Categories</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">pos.category</field>
|
||||
<field name="view_type">form</field>
|
||||
|
@ -685,52 +690,12 @@
|
|||
<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>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context" eval="{'default_journal_user': 1, 'default_view_id': ref('account.account_journal_bank_view'), 'default_type': 'cash'}"/>
|
||||
<field name="context" eval="{'default_journal_user': 1, 'default_type': 'cash'}"/>
|
||||
<field name="domain">[('journal_user','=', 1)]</field>
|
||||
<field name="help">Payment methods are defined by accounting journals having the field Payment Method checked.</field>
|
||||
</record>
|
||||
|
@ -766,16 +731,6 @@
|
|||
<menuitem name="Point of Sale" parent="base.menu_reporting" id="menu_point_rep" sequence="50" groups="group_pos_manager"/>
|
||||
<!-- Invoice -->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_pos_sale_all">
|
||||
<field name="name">All Sales Orders</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">pos.order</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[]</field>
|
||||
</record>
|
||||
<menuitem parent="menu_point_rep" id="menu_point_ofsale_all" action="action_pos_sale_all" sequence="1"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_pos_invoice">
|
||||
<field name="name">Invoices</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
|
@ -785,14 +740,12 @@
|
|||
<field name="domain">[('origin','like','POS')]</field>
|
||||
</record>
|
||||
|
||||
<menuitem name="Reporting" id="menu_point_of_sale_reporting" parent="menu_point_root" sequence="20" />
|
||||
|
||||
<menuitem icon="STOCK_PRINT" action="action_report_pos_details"
|
||||
id="menu_pos_details" parent="menu_point_of_sale_reporting" sequence="6" />
|
||||
id="menu_pos_details" parent="menu_point_rep" sequence="6" />
|
||||
|
||||
<record model="ir.actions.client" id="action_pos_pos">
|
||||
<field name="name">Start Point of Sale</field>
|
||||
<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">
|
||||
|
@ -805,5 +758,301 @@
|
|||
<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="Point of Sale Configuration" version="7.0">
|
||||
<header>
|
||||
<button string="Set to Active" name="set_active" type="object" states="inactive,deprecated"/>
|
||||
<button string="Set to Inactive" name="set_inactive" type="object" states="active" />
|
||||
<button string="Set to Deprecated" name="set_deprecate" type="object" states="active,inactive" />
|
||||
<div class="oe_right">
|
||||
<field name="state" widget="statusbar" statusbar_visible="active,inactive,deprecated" statusbar_colors='{"deprecated" : "red"}' nolabel="1"/>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="shop_id" widget="selection" />
|
||||
<field name="journal_id" widget="selection" />
|
||||
<field name="sequence_id" readonly="1"/>
|
||||
<field name="group_by" />
|
||||
</group>
|
||||
<separator string="Available Payment Methods" colspan="4"/>
|
||||
<field name="journal_ids" colspan="4" nolabel="1">
|
||||
<tree string="Journals">
|
||||
<field name="code" />
|
||||
<field name="name" />
|
||||
<field name="type" />
|
||||
<field name="opening_control" />
|
||||
<field name="closing_control" />
|
||||
</tree>
|
||||
</field>
|
||||
<group string="Material Interfaces" >
|
||||
<group>
|
||||
<field name="iface_self_checkout" />
|
||||
<field name="iface_websql" />
|
||||
<field name="iface_led" />
|
||||
<field name="iface_cashdrawer" />
|
||||
<field name="iface_payment_terminal" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="iface_electronic_scale" />
|
||||
<field name="iface_barscan" />
|
||||
<field name="iface_vkeyboard" />
|
||||
<field name="iface_print_via_proxy" />
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
</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="Point of Sale Configuration" colors="grey:state == 'inactive'">
|
||||
<field name="name" />
|
||||
<field name="shop_id" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_pos_config_search">
|
||||
<field name="name">pos.config.search.view</field>
|
||||
<field name="model">pos.config</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Point of Sale Config">
|
||||
<filter string="Active" domain="[('state', '=', 'active')]" />
|
||||
<filter string="Inactive" domain="[('state', '=', 'inactive')]" />
|
||||
<separator orientation="vertical"/>
|
||||
<field name="name" />
|
||||
<field name="shop_id" />
|
||||
|
||||
</search>
|
||||
</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>
|
||||
<field name="search_view_id" ref="view_pos_config_search" />
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
parent="menu_point_config_product"
|
||||
action="action_pos_config_pos"
|
||||
id="menu_pos_config_pos"
|
||||
groups="group_pos_manager"/>
|
||||
|
||||
<act_window
|
||||
id="act_pos_session_orders"
|
||||
name="Orders"
|
||||
src_model="pos.session"
|
||||
res_model="pos.order"
|
||||
context="{'search_default_session_id': active_id, 'default_session_id' : active_id }" />
|
||||
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="view_pos_session_form">
|
||||
<field name="name">pos.session.form.view</field>
|
||||
<field name="model">pos.session</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Point of Sale Session" version="7.0">
|
||||
<header>
|
||||
<button name="open" type="workflow" string="Validate & Open Session" states="opening_control" />
|
||||
<button name="cashbox_control" type="workflow" string="End of Session" states="opened" />
|
||||
<button name="close" type="workflow" string="Validate & Close" states="closing_control,opened" />
|
||||
|
||||
<div class="oe_right">
|
||||
<field name="state" widget="statusbar" statusbar_visible="opening_control,opened,closing_control,closed" nolabel="1"/>
|
||||
</div>
|
||||
</header>
|
||||
<sheet>
|
||||
|
||||
<group>
|
||||
<field name="config_id"/>
|
||||
<field name="has_opening_control" invisible="1" />
|
||||
<field name="has_closing_control" invisible="1" />
|
||||
<group>
|
||||
<button name="%(action_pos_box_in)d" string="Put Money In" type="action" states="opened"/>
|
||||
<button name="%(action_pos_box_out)d" string="Take Money Out" type="action" states="opened"/>
|
||||
<button name="open_frontend_cb" type="object" string="Open Point Of Sale" states="opened" />
|
||||
</group>
|
||||
<newline/>
|
||||
<field name="user_id" />
|
||||
<field name="name" />
|
||||
<newline/>
|
||||
<field name="start_at" attrs="{'insivible' : [('state', '=', 'opening_control')]}"/>
|
||||
<field name="stop_at" attrs="{'insivible' : [('state', '=', 'opening_control')]}"/>
|
||||
<separator string="Cash Control" colspan="4"/>
|
||||
<field name="cash_register_id" invisible="1" />
|
||||
<field name="opening_details_ids" colspan="4" nolabel="1" attrs="{'invisible' : [('state', 'not in', ('opening_control',))]}">
|
||||
<tree string="Opening Cashbox Lines" editable="bottom">
|
||||
<field name="pieces" readonly="1" />
|
||||
<field name="number_opening" string="Opening Unit Numbers" on_change="on_change_sub_opening(pieces, number_opening, parent.balance_end)" />
|
||||
<field name="subtotal_opening" string="Opening Subtotal" sum="Total"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
<field name="details_ids" colspan="4" nolabel="1" attrs="{'invisible': [('state', '=', 'opening_control')]}">
|
||||
<tree string="Cashbox Lines" editable="bottom">
|
||||
<field name="pieces" readonly="1" />
|
||||
<field name="number_opening" readonly="1"/>
|
||||
<field name="subtotal_opening"/>
|
||||
<field name="number_closing"/>
|
||||
<field name="subtotal_closing"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
|
||||
<group col="4" colspan="4">
|
||||
<group col="2" colspan="2">
|
||||
<separator string="Cash Balance" colspan="2"/>
|
||||
<field name="cash_register_balance_start" readonly="1" string="Opening Cash Control"/>
|
||||
<field name="cash_register_total_entry_encoding" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="+ Transactions"/>
|
||||
<field name="cash_register_balance_end" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="= Theorical Cash Closing"/>
|
||||
</group>
|
||||
<group col="2" colspan="2" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
|
||||
<separator string="Cash Closing Balance" colspan="2"/>
|
||||
<field name="cash_register_balance_end_real"/>
|
||||
<field name="cash_register_difference" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<separator string="Summary by Payment Methods" colspan="4" attrs="{'invisible' : [('state', '=', 'opening_control')]}"/>
|
||||
<field name="statement_ids" colspan="4" nolabel="1" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
|
||||
<tree string="Statements">
|
||||
<field name="name" />
|
||||
<field name="journal_id" />
|
||||
<field name="balance_start" />
|
||||
<field name="total_entry_encoding" />
|
||||
<field name="balance_end_real" />
|
||||
<field name="difference" />
|
||||
<field name="currency" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<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="Point of Sale 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="Point of Sale Session">
|
||||
<filter string="Open" domain="[('state', '=', 'opened')]" />
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Today" domain="[('start_at', '>=', time.strftime('%%Y-%%m-%%d 00:00:00'))]" />
|
||||
<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="Point of Sales" domain="[]" context="{'group_by': 'user_id'}" />
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_pos_session">
|
||||
<field name="name">All Sessions</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">pos.session</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_pos_session_search" />
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
parent="menu_point_rep"
|
||||
action="action_pos_session"
|
||||
id="menu_pos_session"
|
||||
sequence="0"
|
||||
groups="group_pos_manager"/>
|
||||
|
||||
<menuitem
|
||||
parent="menu_point_of_sale"
|
||||
action="action_pos_session"
|
||||
id="menu_pos_session_all"
|
||||
sequence="0"
|
||||
groups="group_pos_manager"/>
|
||||
|
||||
<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"/>
|
||||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
<field name="date_order"/>
|
||||
<field name="session_id"/>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By..." groups="base.group_extended">
|
||||
<filter string="Customer" icon="terp-personal" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Salesman" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Session" icon="terp-personal" domain="[]" context="{'group_by':'session_id'}"/>
|
||||
<separator string="" orientation="vertical"/>
|
||||
<filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
|
||||
<separator string="" orientation="vertical"/>
|
||||
<filter string="Order Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_order'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_pos_session_opening" parent="menu_point_of_sale" id="menu_pos_session_opening" sequence="0" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -76,4 +76,92 @@
|
|||
|
||||
|
||||
</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_start">
|
||||
<field name="wkf_id" ref="wkf_pos_session" />
|
||||
<field name="flow_start">True</field>
|
||||
<field name="name">start</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_opening_control">
|
||||
<field name="wkf_id" ref="wkf_pos_session"/>
|
||||
<field name="name">opening_control</field>
|
||||
<field name="action">wkf_action_opening_control()</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_open">
|
||||
<field name="wkf_id" ref="wkf_pos_session"/>
|
||||
<field name="name">opened</field>
|
||||
<field name="action">wkf_action_open()</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_closing_control">
|
||||
<field name="wkf_id" ref="wkf_pos_session"/>
|
||||
<field name="name">closing_control</field>
|
||||
<field name="action">wkf_action_closing_control()</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_close">
|
||||
<field name="wkf_id" ref="wkf_pos_session"/>
|
||||
<field name="flow_stop">True</field>
|
||||
<field name="name">closed</field>
|
||||
<field name="action">wkf_action_close()</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
|
||||
<!-- Transitions -->
|
||||
<record model="workflow.transition" id="trans_start_to_opening_control">
|
||||
<field name="act_from" ref="act_start" />
|
||||
<field name="act_to" ref="act_opening_control" />
|
||||
<field name="signal" eval="False" /> <!-- >start_to_opening_control</field> -->
|
||||
<field name="condition">has_opening_control == True</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="trans_start_to_open">
|
||||
<field name="act_from" ref="act_start" />
|
||||
<field name="act_to" ref="act_open" />
|
||||
<field name="signal" eval="False" />
|
||||
<field name="condition">has_opening_control == False</field>
|
||||
</record>
|
||||
<!-- state:opening_control -> signal:open -> state:opened -> signal:cashbox_control -> state:closing_control -> signal:close -> state:close -->
|
||||
|
||||
<record model="workflow.transition" id="trans_opening_control_to_open">
|
||||
<field name="act_from" ref="act_opening_control" />
|
||||
<field name="act_to" ref="act_open" />
|
||||
<field name="signal">open</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="trans_open_to_closing_control">
|
||||
<field name="act_from" ref="act_open" />
|
||||
<field name="act_to" ref="act_closing_control" />
|
||||
<field name="signal">cashbox_control</field>
|
||||
<field name="condition">has_closing_control == True</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="trans_open_to_close">
|
||||
<field name="act_from" ref="act_open" />
|
||||
<field name="act_to" ref="act_close" />
|
||||
<field name="signal">close</field>
|
||||
<field name="condition">has_closing_control == False</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="trans_closing_control_to_close">
|
||||
<field name="act_from" ref="act_closing_control" />
|
||||
<field name="act_to" ref="act_close" />
|
||||
<field name="signal">close</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -33,6 +33,5 @@ import pos_sales_user_today
|
|||
import pos_payment_report_user
|
||||
import pos_report
|
||||
import pos_order_report
|
||||
import report_cash_register
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -69,13 +69,6 @@ class pos_details_summary(report_sxw.rml_parse):
|
|||
0.0 )
|
||||
|
||||
def _get_payments(self, objects):
|
||||
# gift_journal_id = None
|
||||
# if ignore_gift:
|
||||
# config_journal_ids = self.pool.get("pos.config.journal").search(self.cr, self.uid, [('code', '=', 'GIFT')])
|
||||
# if len(config_journal_ids):
|
||||
# config_journal = self.pool.get("pos.config.journal").browse(self.cr, self.uid, config_journal_ids, {})[0]
|
||||
# gift_journal_id = config_journal.journal_id.id
|
||||
|
||||
result = {}
|
||||
for obj in objects:
|
||||
for statement in obj.statement_ids:
|
||||
|
@ -136,4 +129,4 @@ report_sxw.report_sxw('report.pos.details_summary',
|
|||
parser=pos_details_summary,
|
||||
header='internal')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -35,7 +35,14 @@
|
|||
<field name="arch" type="xml">
|
||||
<search string="Point of Sale Analysis">
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<filter icon="terp-go-year" string="Year" name="year"
|
||||
domain="[('year','=',time.strftime('%%Y'))]"
|
||||
help="POS ordered created during current year"/>
|
||||
<filter icon="terp-go-today"
|
||||
string="Today"
|
||||
name="today"
|
||||
domain="[('date','=', time.strftime('%%Y-%%m-%%d'))]"
|
||||
help="POS ordered created by today"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter icon="terp-dolar"
|
||||
string="Invoiced"
|
||||
|
@ -43,6 +50,10 @@
|
|||
<filter icon="terp-dolar"
|
||||
string="Not Invoiced"
|
||||
domain="[('state','=',('paid'))]"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="date"/>
|
||||
<field name="user_id" widget="selection" />
|
||||
<filter icon="terp-personal"
|
||||
string="My Sales"
|
||||
help="My Sales"
|
||||
|
@ -67,12 +78,12 @@
|
|||
</record>
|
||||
|
||||
<record id="action_report_pos_order_all" model="ir.actions.act_window">
|
||||
<field name="name">Point of Sale Analysis</field>
|
||||
<field name="name">Orders Analysis</field>
|
||||
<field name="res_model">report.pos.order</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="search_view_id" ref="view_report_pos_order_search"/>
|
||||
<field name="context">{'search_default_year':1,'search_default_This Month':1,'search_default_today':1,'search_default_User':1,'group_by_no_leaf':1,'group_by':[]}</field>
|
||||
<field name="context">{'search_default_year':1,'search_default_today':1,'group_by_no_leaf':1,'group_by':['product_id']}</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_report_pos_order_all" id="menu_report_pos_order_all" parent="menu_point_rep" sequence="3"/>
|
||||
|
|
|
@ -39,16 +39,13 @@ class pos_user_product(report_sxw.rml_parse):
|
|||
data={}
|
||||
for o in object :
|
||||
sql1=""" SELECT distinct(o.id) from account_bank_statement s, account_bank_statement_line l,pos_order o,pos_order_line i where i.order_id=o.id and o.state in ('paid','invoiced') and l.statement_id=s.id and l.pos_statement_id=o.id and s.id=%d"""%(o.id)
|
||||
print sql1
|
||||
self.cr.execute(sql1)
|
||||
data = self.cr.dictfetchall()
|
||||
print "DATA",data
|
||||
a_l=[]
|
||||
for r in data:
|
||||
if r['id']:
|
||||
a_l.append(r['id'])
|
||||
a = ','.join(map(str,a_l))
|
||||
print a_l, a
|
||||
if len(a_l):
|
||||
sql2="""SELECT sum(qty) as qty,l.price_unit*sum(l.qty) as amt,t.name as name from product_product p, product_template t, pos_order_line l where order_id in (%s) and p.product_tmpl_id=t.id and l.product_id=p.id group by t.name, l.price_unit"""%(a)
|
||||
self.cr.execute(sql2)
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import tools
|
||||
from osv import fields,osv
|
||||
|
||||
class report_cash_register(osv.osv):
|
||||
_name = "report.cash.register"
|
||||
_description = "Point of Sale Cash Register Analysis"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'date': fields.date('Create Date', readonly=True),
|
||||
'year': fields.char('Year', size=4),
|
||||
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'),
|
||||
('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'),
|
||||
('10','October'), ('11','November'), ('12','December')], 'Month',readonly=True),
|
||||
'day': fields.char('Day', size=128, readonly=True),
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'state': fields.selection([('draft', 'Quotation'),('open','Open'),('confirm', 'Confirmed')],'Status'),
|
||||
'journal_id': fields.many2one('account.journal', 'Journal'),
|
||||
'balance_start': fields.float('Opening Balance'),
|
||||
'balance_end_real': fields.float('Closing Balance'),
|
||||
}
|
||||
_order = 'date desc'
|
||||
|
||||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'report_cash_register')
|
||||
cr.execute("""
|
||||
create or replace view report_cash_register as (
|
||||
select
|
||||
min(s.id) as id,
|
||||
to_date(to_char(s.create_date, 'dd-MM-YYYY'),'dd-MM-YYYY') as date,
|
||||
s.user_id as user_id,
|
||||
s.journal_id as journal_id,
|
||||
s.state as state,
|
||||
s.balance_start as balance_start,
|
||||
s.balance_end_real as balance_end_real,
|
||||
to_char(s.create_date, 'YYYY') as year,
|
||||
to_char(s.create_date, 'MM') as month,
|
||||
to_char(s.create_date, 'YYYY-MM-DD') as day
|
||||
from account_bank_statement as s
|
||||
group by
|
||||
s.user_id,s.journal_id, s.balance_start, s.balance_end_real,s.state,to_char(s.create_date, 'dd-MM-YYYY'),
|
||||
to_char(s.create_date, 'YYYY'),
|
||||
to_char(s.create_date, 'MM'),
|
||||
to_char(s.create_date, 'YYYY-MM-DD'))""")
|
||||
|
||||
report_cash_register()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,71 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_report_cash_register_tree" model="ir.ui.view">
|
||||
<field name="name">report.cash.register.tree</field>
|
||||
<field name="model">report.cash.register</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Point of Sale Cash Register Analysis">
|
||||
<field name="date" invisible="1"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="year" invisible="1"/>
|
||||
<field name="month" invisible="1"/>
|
||||
<field name="day" invisible="1"/>
|
||||
<field name="journal_id" invisible="1"/>
|
||||
<field name="balance_start" />
|
||||
<field name="balance_end_real" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_report_cash_register_search" model="ir.ui.view">
|
||||
<field name="name">report.cash.register.search</field>
|
||||
<field name="model">report.cash.register</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Point of Sale Cash Register Analysis">
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter icon="terp-document-new"
|
||||
string="Draft"
|
||||
domain="[('state','=',('draft'))]"/>
|
||||
<filter icon="terp-camera_test"
|
||||
string="Confirm"
|
||||
domain="[('state','=',('confirm'))]"/>
|
||||
<filter icon="terp-personal"
|
||||
string="My Sales"
|
||||
help="My Sales"
|
||||
domain="[('user_id','=',uid)]"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="user_id" widget="selection"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group expand="1" string="Group By...">
|
||||
<filter string="User" name="User" icon="terp-personal" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Journal" icon="terp-folder-orange" context="{'group_by':'journal_id'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="State" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Day" icon="terp-go-today" context="{'group_by':'day'}" help="Day from Creation date of cash register"/>
|
||||
<filter string="Month" icon="terp-go-month" context="{'group_by':'month'}" help="Month from Creation date of cash register"/>
|
||||
<filter string="Year" icon="terp-go-year" context="{'group_by':'year'}" help="Year from Creation date of cash register"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_cash_register_all" model="ir.actions.act_window">
|
||||
<field name="name">Register Analysis</field>
|
||||
<field name="res_model">report.cash.register</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_report_cash_register_search"/>
|
||||
<field name="context">{'search_default_year':1,'search_default_This Month':1,'search_default_today':1,'search_default_User':1,'group_by_no_leaf':1,'group_by':[]}</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_report_cash_register_all" id="menu_report_cash_register_all" parent="menu_point_rep" sequence="1"/>
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<lots>
|
||||
<lot-line type="fields" name="id">
|
||||
<username type="field" name="name"/>
|
||||
<ean13 type="field" name="ean13"/>
|
||||
</lot-line>
|
||||
</lots>
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsl:stylesheet
|
||||
version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format">
|
||||
<xsl:variable name="initial_bottom_pos">24.5</xsl:variable>
|
||||
<xsl:variable name="initial_left_pos">0.5</xsl:variable>
|
||||
<xsl:variable name="height_increment">4.8</xsl:variable>
|
||||
<xsl:variable name="width_increment">10</xsl:variable>
|
||||
<xsl:variable name="frame_height">3cm</xsl:variable>
|
||||
<xsl:variable name="frame_width">9.3cm</xsl:variable>
|
||||
<xsl:variable name="number_columns">2</xsl:variable>
|
||||
<xsl:variable name="max_frames">16</xsl:variable>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:apply-templates select="lots"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="lots">
|
||||
<document>
|
||||
<template leftMargin="2.0cm" rightMargin="2.0cm" topMargin="2.0cm" bottomMargin="2.0cm" title="Address list" author="Generated by Open ERP">
|
||||
<pageTemplate id="all">
|
||||
<pageGraphics/>
|
||||
<xsl:apply-templates select="lot-line" mode="frames"/>
|
||||
</pageTemplate>
|
||||
</template>
|
||||
<stylesheet>
|
||||
<paraStyle name="nospace" fontName="Courier" fontSize="10" spaceBefore="0" spaceAfter="0"/>
|
||||
<blockTableStyle id="mytable">
|
||||
<blockBackground colorName="lightred" start="0,0" stop="0,0"/>
|
||||
<blockBackground colorName="lightgrey" start="1,0" stop="-1,0"/>
|
||||
<blockAlignment value="CENTER"/>
|
||||
<blockValign value="MIDDLE"/>
|
||||
<blockFont name="Helvetica-BoldOblique" size="14" start="0,0" stop="-1,0"/>
|
||||
<blockFont name="Helvetica" size="8" start="0,1" stop="-1,1"/>
|
||||
<lineStyle kind="GRID" colorName="black" tickness="1"/>
|
||||
</blockTableStyle>
|
||||
</stylesheet>
|
||||
<story>
|
||||
<xsl:apply-templates select="lot-line" mode="story"/>
|
||||
</story>
|
||||
</document>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="lot-line" mode="frames">
|
||||
<xsl:if test="position() < $max_frames + 1">
|
||||
<frame>
|
||||
<xsl:attribute name="width">
|
||||
<xsl:value-of select="$frame_width"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="height">
|
||||
<xsl:value-of select="$frame_height"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="x1">
|
||||
<xsl:value-of select="$initial_left_pos + ((position()-1) mod $number_columns) * $width_increment"/>
|
||||
<xsl:text>cm</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="y1">
|
||||
<xsl:value-of select="$initial_bottom_pos - floor((position()-1) div $number_columns) * $height_increment"/>
|
||||
<xsl:text>cm</xsl:text>
|
||||
</xsl:attribute>
|
||||
</frame>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="lot-line" mode="story">
|
||||
<blockTable style="mytable" colWidths="2.8cm,5.4cm">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="nospace"></para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="nospace" t="1">
|
||||
<!--
|
||||
<xsl:value-of select="price"/> <xsl:value-of select="currency"/>
|
||||
-->
|
||||
</para>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<barCode><xsl:value-of select="ean13" /></barCode>
|
||||
</td>
|
||||
<td>
|
||||
<para style="nospace"><xsl:value-of select="username"/></para>
|
||||
</td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
<nextFrame/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python
|
||||
from osv import osv, fields
|
||||
import math
|
||||
|
||||
def is_pair(x):
|
||||
return not x%2
|
||||
# This code is a duplicate of product#check_ean function
|
||||
def check_ean(eancode):
|
||||
if not eancode:
|
||||
return True
|
||||
if len(eancode) <> 13:
|
||||
return False
|
||||
try:
|
||||
int(eancode)
|
||||
except:
|
||||
return False
|
||||
oddsum=0
|
||||
evensum=0
|
||||
total=0
|
||||
eanvalue=eancode
|
||||
reversevalue = eanvalue[::-1]
|
||||
finalean=reversevalue[1:]
|
||||
|
||||
for i in range(len(finalean)):
|
||||
if is_pair(i):
|
||||
oddsum += int(finalean[i])
|
||||
else:
|
||||
evensum += int(finalean[i])
|
||||
total=(oddsum * 3) + evensum
|
||||
|
||||
check = int(10 - math.ceil(total % 10.0)) %10
|
||||
|
||||
if check != int(eancode[-1]):
|
||||
return False
|
||||
return True
|
||||
|
||||
class res_users(osv.osv):
|
||||
_inherit = 'res.users'
|
||||
_columns = {
|
||||
'ean13' : fields.char('EAN13', size=13, help="BarCode"),
|
||||
'pos_config' : fields.many2one('pos.config', 'Default Point of Sale', domain=[('state', '=', 'active')]),
|
||||
}
|
||||
|
||||
def _check_ean(self, cr, uid, ids, context=None):
|
||||
return all(
|
||||
check_ean(user.ean13) == True
|
||||
for user in self.browse(cr, uid, ids, context=context)
|
||||
)
|
||||
|
||||
_constraints = [
|
||||
(_check_ean, "Error: Invalid ean code", ['ean13'],),
|
||||
]
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="res_users_form_preference_view" model="ir.ui.view">
|
||||
<field name="name">res.users.form.view</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base.view_users_form_simple_modif" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='preferences']" position="inside">
|
||||
<field name="pos_config" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="res_users_form_view" model="ir.ui.view">
|
||||
<field name="name">res.users.form.view</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base.view_users_form" />
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="inside">
|
||||
<page string="Point Of Sale">
|
||||
<field name="ean13" />
|
||||
<field name="pos_config" />
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,11 +1,9 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_pos_config_journal,pos.config.journal,model_pos_config_journal,group_pos_user,1,0,0,0
|
||||
access_pos_order,pos.order,model_pos_order,group_pos_user,1,1,1,1
|
||||
access_pos_order_line,pos.order.line,model_pos_order_line,group_pos_user,1,1,1,1
|
||||
access_pos_order_manager,pos.order manager,model_pos_order,group_pos_manager,1,0,0,0
|
||||
access_pos_order_line_manager,pos.order.line manager,model_pos_order_line,group_pos_manager,1,0,0,0
|
||||
access_report_transaction_pos,report.transaction.pos,model_report_transaction_pos,group_pos_manager,1,1,1,1
|
||||
access_pos_config_journal_manager,pos.config.journal.manager,model_pos_config_journal,group_pos_manager,1,1,1,1
|
||||
access_account_journal_pos_user,account.journal pos_user,account.model_account_journal,group_pos_user,1,0,0,0
|
||||
access_account_move_pos_user,account.move pos_user,account.model_account_move,group_pos_user,1,1,1,0
|
||||
access_account_account_pos_user,account.account pos_user,account.model_account_account,group_pos_user,1,0,0,0
|
||||
|
@ -32,6 +30,7 @@ access_account_period_pos_manager,account.period pos manager,account.model_accou
|
|||
access_account_fiscalyear_pos_user,account.fiscalyear user,account.model_account_fiscalyear,group_pos_user,1,1,1,0
|
||||
access_account_fiscalyear_pos_manager,account.fiscalyear manager,account.model_account_fiscalyear,group_pos_manager,1,0,0,0
|
||||
access_account_cashbox_line,account.cashbox.line,account.model_account_cashbox_line,group_pos_user,1,1,1,0
|
||||
access_account_journal_cashbox_line,account.cashbox.journal.line,account.model_account_journal_cashbox_line,group_pos_user,1,1,1,0
|
||||
access_account_cashbox_line_manager,account.cashbox.line manager,account.model_account_cashbox_line,group_pos_manager,1,1,1,1
|
||||
access_product_product,product.product,product.model_product_product,group_pos_user,1,0,0,0
|
||||
access_product_template_pos_user,product.template pos user,product.model_product_template,group_pos_user,1,0,0,0
|
||||
|
@ -49,7 +48,6 @@ access_account_analytic_line,account.analytic.line,analytic.model_account_analyt
|
|||
access_account_analytic_account,account.analytic.account,analytic.model_account_analytic_account,group_pos_user,1,1,1,0
|
||||
access_account_journal_column,account.journal.column,account.model_account_journal_column,group_pos_user,1,1,1,0
|
||||
access_account_journal_column_manager,account.journal.column manager,account.model_account_journal_column,group_pos_manager,1,0,0,0
|
||||
access_report_check_register,report.cash.register,model_report_cash_register,group_pos_manager,1,1,1,1
|
||||
access_ir_property_pos_manager,ir.property manager,base.model_ir_property,group_pos_manager,1,1,1,1
|
||||
access_account_bank_statement_line_manager,account.bank.statement.line manager,account.model_account_bank_statement_line,group_pos_manager,1,1,1,1
|
||||
access_account_invoice_manager,account.invoice manager,account.model_account_invoice,group_pos_manager,1,1,1,1
|
||||
|
@ -64,3 +62,5 @@ access_product_category_manager,product.category manager,product.model_product_c
|
|||
access_product_pricelist_manager,product.pricelist manager,product.model_product_pricelist,group_pos_manager,1,0,0,0
|
||||
access_product_category_pos_manager,pos.category manager,model_pos_category,group_pos_manager,1,1,1,"1"""
|
||||
access_product_category_pos_user,pos.category user,model_pos_category,group_pos_user,1,0,0,"0"""
|
||||
access_pos_session_user,pos.session user,model_pos_session,group_pos_user,1,1,1,0
|
||||
access_pos_config_user,pos.config user,model_pos_config,group_pos_user,1,1,1,0
|
||||
|
|
|
|
@ -0,0 +1,84 @@
|
|||
/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
|
||||
* Licensed under the MIT License (LICENSE.txt).
|
||||
*
|
||||
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
|
||||
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
|
||||
* Thanks to: Seamus Leahy for adding deltaX and deltaY
|
||||
*
|
||||
* Version: 3.0.6
|
||||
*
|
||||
* Requires: 1.2.2+
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
var types = ['DOMMouseScroll', 'mousewheel'];
|
||||
|
||||
if ($.event.fixHooks) {
|
||||
for ( var i=types.length; i; ) {
|
||||
$.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
|
||||
}
|
||||
}
|
||||
|
||||
$.event.special.mousewheel = {
|
||||
setup: function() {
|
||||
if ( this.addEventListener ) {
|
||||
for ( var i=types.length; i; ) {
|
||||
this.addEventListener( types[--i], handler, false );
|
||||
}
|
||||
} else {
|
||||
this.onmousewheel = handler;
|
||||
}
|
||||
},
|
||||
|
||||
teardown: function() {
|
||||
if ( this.removeEventListener ) {
|
||||
for ( var i=types.length; i; ) {
|
||||
this.removeEventListener( types[--i], handler, false );
|
||||
}
|
||||
} else {
|
||||
this.onmousewheel = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.extend({
|
||||
mousewheel: function(fn) {
|
||||
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
|
||||
},
|
||||
|
||||
unmousewheel: function(fn) {
|
||||
return this.unbind("mousewheel", fn);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function handler(event) {
|
||||
var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
|
||||
event = $.event.fix(orgEvent);
|
||||
event.type = "mousewheel";
|
||||
|
||||
// Old school scrollwheel delta
|
||||
if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
|
||||
if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
|
||||
|
||||
// New school multidimensional scroll (touchpads) deltas
|
||||
deltaY = delta;
|
||||
|
||||
// Gecko
|
||||
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
|
||||
deltaY = 0;
|
||||
deltaX = -1*delta;
|
||||
}
|
||||
|
||||
// Webkit
|
||||
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
|
||||
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
|
||||
|
||||
// Add event and delta to the front of the arguments
|
||||
args.unshift(event, delta, deltaX, deltaY);
|
||||
|
||||
return ($.event.dispatch || $.event.handle).apply(this, args);
|
||||
}
|
||||
|
||||
})(jQuery);
|
|
@ -0,0 +1,146 @@
|
|||
/* Onscreen Keyboard http://net.tutsplus.com/tutorials/javascript-ajax/creating-a-keyboard-with-css-and-jquery/ */
|
||||
|
||||
.point-of-sale .keyboard_frame{
|
||||
display: none;
|
||||
position:absolute;
|
||||
left: 0;
|
||||
bottom: 0px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-top: 15px;
|
||||
width: 100%;
|
||||
height: 0px; /* 235px, animated via jquery */
|
||||
background-color: #BBB;
|
||||
overflow:hidden;
|
||||
-webkit-box-shadow: 0px 0px 10px rgba(0,0,0, 0.3);
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
z-index:10000;
|
||||
|
||||
}
|
||||
.point-of-sale .keyboard_frame .close_button{
|
||||
height:40px;
|
||||
width:60px;
|
||||
text-align:center;
|
||||
background-color: #DDD;
|
||||
font-size: 12px;
|
||||
line-height:40px;
|
||||
border: 1px solid #CCC;
|
||||
-webkit-border-radius: 5px;
|
||||
-webkit-box-shadow: 0px 2px 5px rgba(0,0,0, 0.2);
|
||||
position:absolute;
|
||||
top:0;
|
||||
right:15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.point-of-sale .keyboard li {
|
||||
float: left;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
top:0;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
-webkit-box-shadow: 0px 2px 5px rgba(0,0,0, 0.2);
|
||||
-webkit-transition-property: top, background-color;
|
||||
-webkit-transition-duration: 0.2s;
|
||||
-webkit-transition-timing-function: linear;
|
||||
}
|
||||
.point-of-sale .keyboard li:hover {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: 0px;
|
||||
border-color: #ddd;
|
||||
background-color:#e5e5e5;
|
||||
cursor: pointer;
|
||||
-webkit-transition-property: top, background-color;
|
||||
-webkit-transition-duration: 0.1s;
|
||||
-webkit-transition-timing-function: ease-out;
|
||||
}
|
||||
.point-of-sale .uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.point-of-sale .on {
|
||||
display: none;
|
||||
}
|
||||
.point-of-sale .firstitem{
|
||||
clear: left;
|
||||
}
|
||||
.point-of-sale .keyboard .lastitem {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* ---- full sized keyboard ---- */
|
||||
|
||||
.point-of-sale .full_keyboard {
|
||||
list-style: none;
|
||||
font-size: 14px;
|
||||
width: 680px;
|
||||
height: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.point-of-sale .full_keyboard li{
|
||||
margin: 0 5px 5px 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
.point-of-sale .full_keyboard .tab, .point-of-sale .full_keyboard .delete {
|
||||
width: 70px;
|
||||
}
|
||||
.point-of-sale .full_keyboard .capslock {
|
||||
width: 80px;
|
||||
}
|
||||
.point-of-sale .full_keyboard .return {
|
||||
width: 77px;
|
||||
}
|
||||
.point-of-sale .full_keyboard .left-shift {
|
||||
width: 95px;
|
||||
}
|
||||
.point-of-sale .full_keyboard .right-shift {
|
||||
width: 109px;
|
||||
}
|
||||
.point-of-sale .full_keyboard .space {
|
||||
clear: left;
|
||||
width: 673px;
|
||||
}
|
||||
|
||||
/* ---- simplified keyboard ---- */
|
||||
|
||||
.point-of-sale .simple_keyboard {
|
||||
list-style: none;
|
||||
font-size: 16px;
|
||||
width: 545px;
|
||||
height: 220px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.point-of-sale .simple_keyboard li{
|
||||
margin: 0 5px 5px 0;
|
||||
width: 49px;
|
||||
height: 49px;
|
||||
line-height: 49px;
|
||||
}
|
||||
.point-of-sale .simple_keyboard .firstitem.row_asdf{
|
||||
margin-left:25px;
|
||||
}
|
||||
.point-of-sale .simple_keyboard .firstitem.row_zxcv{
|
||||
margin-left:55px;
|
||||
}
|
||||
.point-of-sale .simple_keyboard .delete{
|
||||
width: 103px;
|
||||
}
|
||||
.point-of-sale .simple_keyboard .return{
|
||||
width: 103px;
|
||||
}
|
||||
.point-of-sale .simple_keyboard .space{
|
||||
width:268px;
|
||||
}
|
||||
.point-of-sale .simple_keyboard .numlock{
|
||||
width:103px;
|
||||
}
|
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 97 B |
After Width: | Height: | Size: 751 B |
After Width: | Height: | Size: 830 B |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,502 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<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"
|
||||
sodipodi:docname="printer.svg"
|
||||
sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/devices"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:version="0.32"
|
||||
id="svg2994"
|
||||
height="48px"
|
||||
width="48px"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs3">
|
||||
<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="perspective79" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5060"
|
||||
id="radialGradient6719"
|
||||
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="radialGradient6717"
|
||||
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="linearGradient6715"
|
||||
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="linearGradient4762">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.12371134;"
|
||||
offset="0.0000000"
|
||||
id="stop4764" />
|
||||
<stop
|
||||
id="stop4768"
|
||||
offset="0.10344828"
|
||||
style="stop-color:#ffffff;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4766" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4741">
|
||||
<stop
|
||||
id="stop4743"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#dcdcda;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
id="stop4745"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#bab9b7;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4733">
|
||||
<stop
|
||||
id="stop4735"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#000000;stop-opacity:0.23711340;" />
|
||||
<stop
|
||||
id="stop4737"
|
||||
offset="1"
|
||||
style="stop-color:#000000;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4698">
|
||||
<stop
|
||||
id="stop4700"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#fffffd;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
style="stop-color:#bbbbb9;stop-opacity:1.0000000;"
|
||||
offset="0.50000000"
|
||||
id="stop4706" />
|
||||
<stop
|
||||
id="stop4702"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#000000;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4688">
|
||||
<stop
|
||||
id="stop4690"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#666666;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
id="stop4692"
|
||||
offset="1"
|
||||
style="stop-color:#000000;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4680"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop4682"
|
||||
offset="0"
|
||||
style="stop-color:#f7f6f5;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop4684"
|
||||
offset="1"
|
||||
style="stop-color:#f7f6f5;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4668">
|
||||
<stop
|
||||
id="stop4670"
|
||||
offset="0"
|
||||
style="stop-color:#8e8d87;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#cbc9c1;stop-opacity:1.0000000;"
|
||||
offset="0.27586207"
|
||||
id="stop4676" />
|
||||
<stop
|
||||
id="stop4672"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#8e8d87;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient259">
|
||||
<stop
|
||||
id="stop260"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#e0e0e0;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1.0000000;"
|
||||
offset="0.40546969"
|
||||
id="stop4886" />
|
||||
<stop
|
||||
style="stop-color:#cdcdcd;stop-opacity:1.0000000;"
|
||||
offset="0.53448278"
|
||||
id="stop4884" />
|
||||
<stop
|
||||
id="stop261"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#494949;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient15662">
|
||||
<stop
|
||||
id="stop15664"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#ffffff;stop-opacity:0.0000000;" />
|
||||
<stop
|
||||
id="stop15666"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#f8f8f8;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="2.1227016"
|
||||
fy="26.925594"
|
||||
fx="9.1295490"
|
||||
cy="26.925594"
|
||||
cx="9.1295490"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1433"
|
||||
xlink:href="#linearGradient4698"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="72.064316"
|
||||
x2="9.9128132"
|
||||
y1="57.227650"
|
||||
x1="9.8698082"
|
||||
gradientTransform="matrix(2.772086,0.000000,0.000000,0.360739,0.618718,2.883883)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1447"
|
||||
xlink:href="#linearGradient4733"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="54.136139"
|
||||
x2="10.338233"
|
||||
y1="64.652260"
|
||||
x1="10.338233"
|
||||
gradientTransform="matrix(2.369844,0.000000,0.000000,0.421969,0.000000,2.000000)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1451"
|
||||
xlink:href="#linearGradient4680"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="62.282467"
|
||||
x2="9.7052784"
|
||||
y1="70.724976"
|
||||
x1="9.7316532"
|
||||
gradientTransform="matrix(2.369844,0.000000,0.000000,0.421969,0.000000,2.000000)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1453"
|
||||
xlink:href="#linearGradient4688"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="19.337463"
|
||||
x2="20.717800"
|
||||
y1="25.140253"
|
||||
x1="20.771229"
|
||||
gradientTransform="matrix(1.198769,0,0,0.853565,-0.143086,2.034513)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1456"
|
||||
xlink:href="#linearGradient15662"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="25.247311"
|
||||
x2="24.789707"
|
||||
y1="3.6785457"
|
||||
x1="25.056711"
|
||||
gradientTransform="matrix(0.94571,0,0,1.076032,5.016683e-2,4.095404)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1459"
|
||||
xlink:href="#linearGradient259"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="58.831264"
|
||||
x2="15.487823"
|
||||
y1="32.539238"
|
||||
x1="15.387969"
|
||||
gradientTransform="matrix(1.492569,0,0,0.668741,8.188072e-2,2)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1464"
|
||||
xlink:href="#linearGradient4762"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="88.294930"
|
||||
x2="18.972126"
|
||||
y1="88.294930"
|
||||
x1="1.8456430"
|
||||
gradientTransform="matrix(2.291824,0,0,0.434269,8.855179e-2,2)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1468"
|
||||
xlink:href="#linearGradient4741"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
y2="88.294933"
|
||||
x2="18.972126"
|
||||
y1="88.294933"
|
||||
x1="1.8456431"
|
||||
gradientTransform="matrix(2.30272,0,0,0.437918,0,0.584034)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1471"
|
||||
xlink:href="#linearGradient4668"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
inkscape:window-y="160"
|
||||
inkscape:window-x="491"
|
||||
inkscape:window-height="688"
|
||||
inkscape:window-width="872"
|
||||
inkscape:guide-bbox="true"
|
||||
showguides="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
showgrid="false"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:cy="4.6034265"
|
||||
inkscape:cx="29.124539"
|
||||
inkscape:zoom="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="0.090196078"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
inkscape:showpageshadow="false" />
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Printer</dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
|
||||
<dc:source>http://jimmac.musichall.cz</dc:source>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>printer</rdf:li>
|
||||
<rdf:li>local</rdf:li>
|
||||
<rdf:li>laser</rdf:li>
|
||||
<rdf:li>bubblejet</rdf:li>
|
||||
<rdf:li>inkjet</rdf:li>
|
||||
<rdf:li>print</rdf:li>
|
||||
<rdf:li>output</rdf:li>
|
||||
<rdf:li>cups</rdf:li>
|
||||
<rdf:li>lpd</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</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>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1"
|
||||
id="layer1">
|
||||
<g
|
||||
transform="matrix(2.311016e-2,0,0,2.271533e-2,44.68502,39.36099)"
|
||||
id="g6707">
|
||||
<rect
|
||||
style="opacity:0.40206185;color:black;fill:url(#linearGradient6715);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect6709"
|
||||
width="1339.6335"
|
||||
height="478.35718"
|
||||
x="-1559.2523"
|
||||
y="-150.69685" />
|
||||
<path
|
||||
style="opacity:0.40206185;color:black;fill:url(#radialGradient6717);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z "
|
||||
id="path6711"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path6713"
|
||||
d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z "
|
||||
style="opacity:0.40206185;color:black;fill:url(#radialGradient6719);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
<rect
|
||||
ry="1.7115477"
|
||||
rx="1.7115483"
|
||||
y="36.004189"
|
||||
x="4.75"
|
||||
height="6.4915943"
|
||||
width="38.4375"
|
||||
id="rect4652"
|
||||
style="fill:url(#linearGradient1471);fill-opacity:1;stroke:#595959;stroke-width:0.99999982;stroke-miterlimit:4;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cssssssssssss"
|
||||
id="rect4609"
|
||||
d="M 7.1308961,21.5 L 40.870615,21.5 C 41.255661,21.5 41.747648,21.788155 42.051049,22.223919 C 42.354451,22.659684 43.787518,24.83394 44.109448,25.297964 C 44.431378,25.761987 44.502397,26.201852 44.502397,26.774049 L 44.502397,38.850951 C 44.502397,39.764524 43.770402,40.5 42.861152,40.5 L 5.1403596,40.5 C 4.2311094,40.5 3.4991138,39.764524 3.4991138,38.850951 L 3.4991138,26.774049 C 3.4991138,26.280031 3.6002798,25.571641 3.9455202,25.120718 C 4.3811666,24.551713 5.5498664,22.57277 5.8581276,22.153118 C 6.1663887,21.733467 6.7324461,21.5 7.1308961,21.5 z "
|
||||
style="color:#000000;fill:url(#linearGradient1468);fill-opacity:1;fill-rule:nonzero;stroke:#676767;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
|
||||
<path
|
||||
sodipodi:nodetypes="cssssssss"
|
||||
id="path4718"
|
||||
d="M 7.4246212,21.975532 C 6.9218931,21.975532 6.3048776,22.053784 6.0546019,22.46703 L 4.1542523,25.604816 C 3.8721285,26.070648 4.1881986,26.868141 5.0873106,26.868141 L 42.730786,26.868141 C 44.040732,26.868141 43.950533,25.858073 43.663844,25.428039 L 41.896077,22.776389 C 41.575544,22.295589 41.459199,21.975532 40.65864,21.975532 L 7.4246212,21.975532 z "
|
||||
style="fill:#fbfbfb;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000" />
|
||||
<path
|
||||
style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient1464);stroke-width:0.94696712;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 7.60536,22.445756 L 40.432673,22.445756 C 40.798351,22.445756 41.265592,22.718629 41.553733,23.131283 C 41.841873,23.543938 42.849964,25.160945 43.155701,25.60036 C 43.461437,26.039775 43.59127,26.456312 43.59127,26.998164 L 43.59127,38.279261 C 43.59127,39.144385 43.457547,39.528356 42.594031,39.528356 L 5.5322268,39.528356 C 4.6687108,39.528356 4.4726047,39.144385 4.4726047,38.279261 L 4.4726047,26.998164 C 4.4726047,26.530345 4.6934498,25.859523 5.0213249,25.432514 C 5.435059,24.893685 6.1038541,23.461633 6.3966101,23.064237 C 6.6893662,22.666841 7.2269515,22.445756 7.60536,22.445756 z "
|
||||
id="path4750"
|
||||
sodipodi:nodetypes="cssssssssssss" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
id="rect15391"
|
||||
d="M 11.672962,4.4999475 L 36.325116,4.4999475 C 36.975881,4.4999475 37.49978,5.0100777 37.49978,5.6437371 L 37.49978,24.348176 L 10.498298,24.348176 L 10.498298,5.6437371 C 10.498298,5.0100777 11.022197,4.4999475 11.672962,4.4999475 z "
|
||||
style="color:#000000;fill:url(#linearGradient1459);fill-opacity:1;fill-rule:nonzero;stroke:#898989;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient1456);stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
id="rect15660"
|
||||
width="25.000576"
|
||||
height="18.836374"
|
||||
x="11.498513"
|
||||
y="5.4992466"
|
||||
ry="0.17677675"
|
||||
rx="0.17677672" />
|
||||
<rect
|
||||
ry="1.7115483"
|
||||
rx="1.7115483"
|
||||
y="27.375000"
|
||||
x="6.8750000"
|
||||
height="5.1875000"
|
||||
width="33.750000"
|
||||
id="rect4678"
|
||||
style="fill:url(#linearGradient1451);fill-opacity:1.0000000;stroke:url(#linearGradient1453);stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
|
||||
<path
|
||||
transform="translate(0.000000,2.000000)"
|
||||
d="M 10.871767 27.626486 A 1.2816310 1.2816310 0 1 1 8.3085046,27.626486 A 1.2816310 1.2816310 0 1 1 10.871767 27.626486 z"
|
||||
sodipodi:ry="1.2816310"
|
||||
sodipodi:rx="1.2816310"
|
||||
sodipodi:cy="27.626486"
|
||||
sodipodi:cx="9.5901356"
|
||||
id="path4696"
|
||||
style="fill:url(#radialGradient1433);fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:nodetypes="csscssssc"
|
||||
id="path4731"
|
||||
d="M 11.743718,25.416053 L 37.306218,25.478553 C 37.993716,25.480234 38.294038,25.107558 38.243718,24.478553 L 38.118718,22.916053 L 39.984835,22.916053 C 40.797335,22.916053 40.975035,23.108616 41.172335,23.478553 L 41.672335,24.416053 C 42.199130,25.403793 43.483508,26.390165 42.170495,26.390165 C 37.667784,26.390165 13.993718,26.041053 11.743718,25.416053 z "
|
||||
style="fill:url(#linearGradient1447);fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;opacity:0.36571429" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 43.488808,26.5 L 4.5111805,26.5"
|
||||
id="path4760"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<g
|
||||
transform="translate(0.000000,2.000000)"
|
||||
style="opacity:0.43575415"
|
||||
id="g4849">
|
||||
<rect
|
||||
y="7.0000000"
|
||||
x="14.000000"
|
||||
height="1.0000000"
|
||||
width="19.000000"
|
||||
id="rect4833"
|
||||
style="color:#000000;fill:#000000;fill-opacity:0.29239765;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible" />
|
||||
<rect
|
||||
style="color:#000000;fill:#000000;fill-opacity:0.29239765;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect4835"
|
||||
width="19.000000"
|
||||
height="1.0000000"
|
||||
x="14.000000"
|
||||
y="9.0000000" />
|
||||
<rect
|
||||
y="11.000000"
|
||||
x="14.000000"
|
||||
height="1.0000000"
|
||||
width="19.000000"
|
||||
id="rect4837"
|
||||
style="color:#000000;fill:#000000;fill-opacity:0.29239765;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible" />
|
||||
<rect
|
||||
style="color:#000000;fill:#000000;fill-opacity:0.29239765;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect4839"
|
||||
width="11.000000"
|
||||
height="1.0000000"
|
||||
x="14.000000"
|
||||
y="13.000000" />
|
||||
<rect
|
||||
style="color:#000000;fill:#000000;fill-opacity:0.29239765;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
|
||||
id="rect4843"
|
||||
width="19.000000"
|
||||
height="1.0000000"
|
||||
x="14.000000"
|
||||
y="17.000000" />
|
||||
<rect
|
||||
y="19.000000"
|
||||
x="14.000000"
|
||||
height="1.0000000"
|
||||
width="19.000000"
|
||||
id="rect4845"
|
||||
style="color:#000000;fill:#000000;fill-opacity:0.29239765;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 22 KiB |
|
@ -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 |
|
@ -0,0 +1,201 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<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"
|
||||
version="1.1"
|
||||
width="48"
|
||||
height="48"
|
||||
id="svg11300">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
id="linearGradient1442">
|
||||
<stop
|
||||
id="stop1444"
|
||||
style="stop-color:#73d216;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop1446"
|
||||
style="stop-color:#4e9a06;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient8662">
|
||||
<stop
|
||||
id="stop8664"
|
||||
style="stop-color:#000000;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop8666"
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient8650">
|
||||
<stop
|
||||
id="stop8652"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop8654"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
cx="24.837126"
|
||||
cy="36.421127"
|
||||
r="15.644737"
|
||||
fx="24.837126"
|
||||
fy="36.421127"
|
||||
id="radialGradient1444"
|
||||
xlink:href="#linearGradient8662"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.536723,0,16.87306)" />
|
||||
<radialGradient
|
||||
cx="15.987216"
|
||||
cy="1.5350308"
|
||||
r="17.171415"
|
||||
fx="15.987216"
|
||||
fy="1.5350308"
|
||||
id="radialGradient3006"
|
||||
xlink:href="#linearGradient8650"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0,2.046729,1.55761,0,2.91297,-22.93354)" />
|
||||
<radialGradient
|
||||
cx="35.292667"
|
||||
cy="20.494493"
|
||||
r="16.9562"
|
||||
fx="35.292667"
|
||||
fy="20.494493"
|
||||
id="radialGradient3009"
|
||||
xlink:href="#linearGradient1442"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0,0.843022,-1.020168,0,46.422124,1.41307)" />
|
||||
<linearGradient
|
||||
x1="46.5"
|
||||
y1="27"
|
||||
x2="80.5"
|
||||
y2="27"
|
||||
id="linearGradient3785"
|
||||
xlink:href="#linearGradient1442"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="47.703129"
|
||||
y1="26.804157"
|
||||
x2="58.338215"
|
||||
y2="26.804157"
|
||||
id="linearGradient3807"
|
||||
xlink:href="#linearGradient8650"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="58.968754"
|
||||
y1="24.609373"
|
||||
x2="75.09375"
|
||||
y2="24.609373"
|
||||
id="linearGradient3817"
|
||||
xlink:href="#linearGradient8650"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="46.5"
|
||||
y1="27"
|
||||
x2="80.5"
|
||||
y2="27"
|
||||
id="linearGradient3825"
|
||||
xlink:href="#linearGradient1442"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="47.703129"
|
||||
y1="26.804157"
|
||||
x2="58.338215"
|
||||
y2="26.804157"
|
||||
id="linearGradient3827"
|
||||
xlink:href="#linearGradient8650"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="58.968754"
|
||||
y1="24.609373"
|
||||
x2="75.09375"
|
||||
y2="24.609373"
|
||||
id="linearGradient3829"
|
||||
xlink:href="#linearGradient8650"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:source>http://jimmac.musichall.cz</dc:source>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
|
||||
<dc:title></dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>go</rdf:li>
|
||||
<rdf:li>lower</rdf:li>
|
||||
<rdf:li>down</rdf:li>
|
||||
<rdf:li>arrow</rdf:li>
|
||||
<rdf:li>pointer</rdf:li>
|
||||
<rdf:li>></rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Andreas Nilsson</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>
|
||||
<g
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 40.481863,36.421127 a 15.644737,8.3968935 0 1 1 -31.2894745,0 15.644737,8.3968935 0 1 1 31.2894745,0 z"
|
||||
transform="matrix(0.90685456,0,0,0.595458,-2.8361621,15.68775)"
|
||||
id="path8660"
|
||||
style="opacity:0.20454544;color:#000000;fill:url(#radialGradient1444);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
|
||||
<g
|
||||
transform="translate(-40.03125,-3.65625)"
|
||||
id="g3819">
|
||||
<path
|
||||
d="M 52,23 47,28 59,40 80,19 75,14 59,30 z"
|
||||
id="path3002"
|
||||
style="fill:url(#linearGradient3825);fill-opacity:1;stroke:#3a7304;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="M 52,24.417969 48.411612,28 59,38.601563 78.585938,19 75,15.414063 59,31.40625 z"
|
||||
id="path3787"
|
||||
style="opacity:0.5;fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 51.968752,23.734374 -4.265625,4.25 0.995256,1.104854 8.485282,0.04052 z"
|
||||
id="path3799"
|
||||
style="opacity:0.34893619;fill:url(#linearGradient3827);fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
d="m 60.913297,28.932676 8.536072,0.01148 9.931219,-9.897748 -4.349335,-4.296415 z"
|
||||
id="path3809"
|
||||
style="opacity:0.26382979;fill:url(#linearGradient3829);fill-opacity:1;stroke:none" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,45 @@
|
|||
function openerp_pos_basewidget(instance, module){ //module is instance.point_of_sale
|
||||
|
||||
// This is a base class for all Widgets in the POS. It exposes relevant data to the
|
||||
// templates :
|
||||
// - widget.currency : { symbol: '$' | '€' | ..., position: 'before' | 'after }
|
||||
// - widget.format_currency(amount) : this method returns a formatted string based on the
|
||||
// symbol, the position, and the amount of money.
|
||||
// if the PoS is not fully loaded when you instanciate the widget, the currency might not
|
||||
// yet have been initialized. Use __build_currency_template() to recompute with correct values
|
||||
// before rendering.
|
||||
|
||||
module.PosBaseWidget = instance.web.Widget.extend({
|
||||
init:function(parent,options){
|
||||
this._super(parent);
|
||||
options = options || {};
|
||||
this.pos = options.pos || (parent ? parent.pos : undefined);
|
||||
this.pos_widget = options.pos_widget || (parent ? parent.pos_widget : undefined);
|
||||
this.build_currency_template();
|
||||
},
|
||||
build_currency_template: function(){
|
||||
|
||||
if(this.pos && this.pos.get('currency')){
|
||||
this.currency = this.pos.get('currency');
|
||||
}else{
|
||||
this.currency = {symbol: '$', position: 'after'};
|
||||
}
|
||||
|
||||
this.format_currency = function(amount){
|
||||
if(this.currency.position === 'after'){
|
||||
return Math.round(amount*100)/100 + ' ' + this.currency.symbol;
|
||||
}else{
|
||||
return this.currency.symbol + ' ' + Math.round(amount*100)/100;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
show: function(){
|
||||
this.$element.show();
|
||||
},
|
||||
hide: function(){
|
||||
this.$element.hide();
|
||||
},
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,432 @@
|
|||
|
||||
function openerp_pos_devices(instance,module){ //module is instance.point_of_sale
|
||||
|
||||
var debug_devices = new (instance.web.Class.extend({
|
||||
active: false,
|
||||
payment_status: 'waiting_for_payment',
|
||||
weight: 0,
|
||||
activate: function(){
|
||||
this.active = true;
|
||||
},
|
||||
deactivate: function(){
|
||||
this.active = false;
|
||||
},
|
||||
set_weight: function(weight){ this.activate(); this.weight = weight; },
|
||||
accept_payment: function(){ this.activate(); this.payment_status = 'payment_accepted'; },
|
||||
reject_payment: function(){ this.activate(); this.payment_status = 'payment_rejected'; },
|
||||
delay_payment: function(){ this.activate(); this.payment_status = 'waiting_for_payment'; },
|
||||
}))();
|
||||
|
||||
//window.debug_devices = debug_devices;
|
||||
|
||||
// this object interfaces with the local proxy to communicate to the various hardware devices
|
||||
// connected to the Point of Sale. As the communication only goes from the POS to the proxy,
|
||||
// methods are used both to signal an event, and to fetch information.
|
||||
|
||||
module.ProxyDevice = instance.web.Class.extend({
|
||||
init: function(options){
|
||||
options = options || {};
|
||||
url = options.url || 'http://localhost:8069';
|
||||
|
||||
this.weight = 0;
|
||||
this.weighting = false;
|
||||
|
||||
this.paying = false;
|
||||
this.payment_status = 'waiting_for_payment';
|
||||
|
||||
this.connection = new instance.web.JsonRPC();
|
||||
this.connection.setup(url);
|
||||
|
||||
},
|
||||
message : function(name,params,success_callback, error_callback){
|
||||
success_callback = success_callback || function(){};
|
||||
error_callback = error_callback || function(){};
|
||||
|
||||
if(debug_devices && debug_devices.active){
|
||||
console.log('PROXY:',name,params);
|
||||
}else{
|
||||
this.connection.rpc('/pos/'+name, params || {}, success_callback, error_callback);
|
||||
}
|
||||
},
|
||||
|
||||
//a product has been scanned and recognized with success
|
||||
scan_item_success: function(){
|
||||
this.message('scan_item_success');
|
||||
},
|
||||
|
||||
//a product has been scanned but not recognized
|
||||
scan_item_error_unrecognized: function(){
|
||||
this.message('scan_item_error_unrecognized');
|
||||
},
|
||||
|
||||
//the client is asking for help
|
||||
help_needed: function(){
|
||||
this.message('help_needed');
|
||||
},
|
||||
|
||||
//the client does not need help anymore
|
||||
help_canceled: function(){
|
||||
this.message('help_canceled');
|
||||
},
|
||||
|
||||
//the client is starting to weight
|
||||
weighting_start: function(){
|
||||
this.weight = 0;
|
||||
if(debug_devices){
|
||||
debug_devices.weigth = 0;
|
||||
}
|
||||
this.weighting = true;
|
||||
this.message('weighting_start');
|
||||
},
|
||||
|
||||
//returns the weight on the scale.
|
||||
// is called at regular interval (up to 10x/sec) between a weighting_start()
|
||||
// and a weighting_end()
|
||||
weighting_read_kg: function(){
|
||||
var self = this;
|
||||
if(debug_devices && debug_devices.active){
|
||||
return debug_devices.weight;
|
||||
}else{
|
||||
this.message('weighting_read_kg',{},function(weight){
|
||||
if(self.weighting){
|
||||
self.weight = weight;
|
||||
}
|
||||
});
|
||||
return self.weight;
|
||||
}
|
||||
},
|
||||
|
||||
// the client has finished weighting products
|
||||
weighting_end: function(){
|
||||
this.weight = 0;
|
||||
this.weighting = false;
|
||||
this.message('weighting_end');
|
||||
},
|
||||
|
||||
// the pos asks the client to pay 'price' units
|
||||
// method: 'mastercard' | 'cash' | ... ? TBD
|
||||
// info: 'extra information to display on the payment terminal' ... ? TBD
|
||||
payment_request: function(price, method, info){
|
||||
this.paying = true;
|
||||
this.payment_status = 'waiting_for_payment';
|
||||
if(debug_devices){
|
||||
debug_devices.payment_status = 'waiting_for_payment';
|
||||
}
|
||||
this.message('payment_request',{'price':price,'method':method,'info':info});
|
||||
},
|
||||
|
||||
// is called at regular interval after a payment request to see if the client
|
||||
// has paid the required money
|
||||
// returns 'waiting_for_payment' | 'payment_accepted' | 'payment_rejected'
|
||||
is_payment_accepted: function(){
|
||||
var self = this;
|
||||
if(debug_devices.active){
|
||||
return debug_devices.payment_status;
|
||||
}else{
|
||||
this.message('is_payment_accepted', {}, function(payment_status){
|
||||
if(self.paying){
|
||||
self.payment_status = payment_status;
|
||||
}
|
||||
});
|
||||
return self.payment_status;
|
||||
}
|
||||
},
|
||||
|
||||
// the client cancels his payment
|
||||
payment_canceled: function(){
|
||||
this.paying = false;
|
||||
this.payment_status = 'waiting_for_payment';
|
||||
this.message('payment_canceled');
|
||||
},
|
||||
|
||||
// called when the client logs in or starts to scan product
|
||||
transaction_start: function(){
|
||||
this.message('transaction_start');
|
||||
},
|
||||
|
||||
// called when the clients has finished his interaction with the machine
|
||||
transaction_end: function(){
|
||||
this.message('transaction_end');
|
||||
},
|
||||
|
||||
// called when the POS turns to cashier mode
|
||||
cashier_mode_activated: function(){
|
||||
this.message('cashier_mode_activated');
|
||||
},
|
||||
|
||||
// called when the POS turns to client mode
|
||||
cashier_mode_deactivated: function(){
|
||||
this.message('cashier_mode_deactivated');
|
||||
},
|
||||
|
||||
// ask for the cashbox (the physical box where you store the cash) to be opened
|
||||
open_cashbox: function(){
|
||||
this.message('open_cashbox');
|
||||
},
|
||||
|
||||
/* ask the printer to print a receipt
|
||||
* receipt is a JSON object with the following specs:
|
||||
* receipt{
|
||||
* - orderlines : list of orderlines :
|
||||
* {
|
||||
* quantity: (number) the number of items, or the weight,
|
||||
* unit_name: (string) the name of the item's unit (kg, dozen, ...)
|
||||
* list_price: (number) the price of one unit of the item before discount
|
||||
* discount: (number) the discount on the product in % [0,100]
|
||||
* product_name: (string) the name of the product
|
||||
* price_with_tax: (number) the price paid for this orderline, tax included
|
||||
* price_without_tax: (number) the price paid for this orderline, without taxes
|
||||
* tax: (number) the price paid in taxes on this orderline
|
||||
* }
|
||||
* - paymentlines : list of paymentlines :
|
||||
* {
|
||||
* amount: (number) the amount paid
|
||||
* journal: (string) the name of the journal on wich the payment has been made
|
||||
* }
|
||||
* - total_with_tax: (number) the total of the receipt tax included
|
||||
* - total_without_tax: (number) the total of the receipt without taxes
|
||||
* - total_tax: (number) the total amount of taxes paid
|
||||
* - total_paid: (number) the total sum paid by the client
|
||||
* - change: (number) the amount of change given back to the client
|
||||
* - name: (string) a unique name for this order
|
||||
* - client: (string) name of the client. or null if no client is logged
|
||||
* - cashier: (string) the name of the cashier
|
||||
* - date: { the date at wich the payment has been done
|
||||
* year: (number) the year [2012, ...]
|
||||
* month: (number) the month [0,11]
|
||||
* date: (number) the day of the month [1,31]
|
||||
* day: (number) the day of the week [0,6]
|
||||
* hour: (number) the hour [0,23]
|
||||
* minute: (number) the minute [0,59]
|
||||
* }
|
||||
*/
|
||||
print_receipt: function(receipt){
|
||||
this.message('print_receipt',{receipt: receipt});
|
||||
},
|
||||
});
|
||||
|
||||
// this module interfaces with the barcode reader. It assumes the barcode reader
|
||||
// is set-up to act like a keyboard. Use connect() and disconnect() to activate
|
||||
// and deactivate the barcode reader. Use set_action_callbacks to tell it
|
||||
// what to do when it reads a barcode.
|
||||
module.BarcodeReader = instance.web.Class.extend({
|
||||
actions:[
|
||||
'product',
|
||||
'cashier',
|
||||
'client',
|
||||
'discount',
|
||||
],
|
||||
init: function(attributes){
|
||||
this.pos = attributes.pos;
|
||||
this.action_callback = {};
|
||||
|
||||
this.action_callback_stack = [];
|
||||
|
||||
this.price_prefix_set = attributes.price_prefix_set || {'02':'', '22':'', '24':'', '26':'', '28':''};
|
||||
this.weight_prefix_set = attributes.weight_prefix_set || {'21':'','23':'','27':'','29':'','25':''};
|
||||
this.client_prefix_set = attributes.weight_prefix_set || {'42':''};
|
||||
this.cashier_prefix_set = attributes.weight_prefix_set || {'40':''};
|
||||
this.discount_prefix_set = attributes.weight_prefix_set || {'44':''};
|
||||
},
|
||||
save_callbacks: function(){
|
||||
var callbacks = {};
|
||||
for(name in this.action_callback){
|
||||
callbacks[name] = this.action_callback[name];
|
||||
}
|
||||
this.action_callback_stack.push(callbacks);
|
||||
},
|
||||
restore_callbacks: function(){
|
||||
if(this.action_callback_stack.length){
|
||||
var callbacks = this.action_callback_stack.pop();
|
||||
this.action_callback = callbacks;
|
||||
}
|
||||
},
|
||||
|
||||
// when an ean is scanned and parsed, the callback corresponding
|
||||
// to its type is called with the parsed_ean as a parameter.
|
||||
// (parsed_ean is the result of parse_ean(ean))
|
||||
//
|
||||
// callbacks is a Map of 'actions' : callback(parsed_ean)
|
||||
// that sets the callback for each action. if a callback for the
|
||||
// specified action already exists, it is replaced.
|
||||
//
|
||||
// possible actions include :
|
||||
// 'product' | 'cashier' | 'client' | 'discount'
|
||||
|
||||
set_action_callback: function(action, callback){
|
||||
if(arguments.length == 2){
|
||||
this.action_callback[action] = callback;
|
||||
}else{
|
||||
var actions = arguments[0];
|
||||
for(action in actions){
|
||||
this.set_action_callback(action,actions[action]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//remove all action callbacks
|
||||
reset_action_callbacks: function(){
|
||||
for(action in this.action_callback){
|
||||
this.action_callback[action] = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// returns true if the ean is a valid EAN codebar number by checking the control digit.
|
||||
// ean must be a string
|
||||
check_ean: function(ean){
|
||||
var code = ean.split('');
|
||||
for(var i = 0; i < code.length; i++){
|
||||
code[i] = Number(code[i]);
|
||||
}
|
||||
var st1 = code.slice();
|
||||
var st2 = st1.slice(0,st1.length-1).reverse();
|
||||
// some EAN13 barcodes have a length of 12, as they start by 0
|
||||
while (st2.length < 12) {
|
||||
st2.push(0);
|
||||
}
|
||||
var countSt3 = 1;
|
||||
var st3 = 0;
|
||||
$.each(st2, function() {
|
||||
if (countSt3%2 === 1) {
|
||||
st3 += this;
|
||||
}
|
||||
countSt3 ++;
|
||||
});
|
||||
st3 *= 3;
|
||||
var st4 = 0;
|
||||
var countSt4 = 1;
|
||||
$.each(st2, function() {
|
||||
if (countSt4%2 === 0) {
|
||||
st4 += this;
|
||||
}
|
||||
countSt4 ++;
|
||||
});
|
||||
var st5 = st3 + st4;
|
||||
var cd = (10 - (st5%10)) % 10;
|
||||
return code[code.length-1] === cd;
|
||||
},
|
||||
|
||||
// attempts to interpret an ean (string encoding an ean)
|
||||
// it will check its validity then return an object containing various
|
||||
// information about the ean.
|
||||
// most importantly :
|
||||
// - ean : the ean
|
||||
// - type : the type of the ean:
|
||||
// 'price' | 'weight' | 'unit' | 'cashier' | 'client' | 'discount' | 'error'
|
||||
//
|
||||
// - prefix : the prefix that has ben used to determine the type
|
||||
// - id : the part of the ean that identifies something
|
||||
// - value : if the id encodes a numerical value, it will be put there
|
||||
// - unit : if the encoded value has a unit, it will be put there.
|
||||
// not to be confused with the 'unit' type, which represent an unit of a
|
||||
// unique product
|
||||
|
||||
parse_ean: function(ean){
|
||||
var parse_result = {
|
||||
type:'unknown', //
|
||||
prefix:'',
|
||||
ean:ean,
|
||||
id:'',
|
||||
value: 0,
|
||||
unit: 'none',
|
||||
};
|
||||
var prefix2 = ean.substring(0,2);
|
||||
|
||||
if(!this.check_ean(ean)){
|
||||
parse_result.type = 'error';
|
||||
}else if (prefix2 in this.price_prefix_set){
|
||||
parse_result.type = 'price';
|
||||
parse_result.prefix = prefix2;
|
||||
parse_result.id = ean.substring(0,7);
|
||||
parse_result.value = Number(ean.substring(7,12))/100.0;
|
||||
parse_result.unit = 'euro';
|
||||
} else if (prefix2 in this.weight_prefix_set){
|
||||
parse_result.type = 'weight';
|
||||
parse_result.prefix = prefix2;
|
||||
parse_result.id = ean.substring(0,7);
|
||||
parse_result.value = Number(ean.substring(7,12))/1000.0;
|
||||
parse_result.unit = 'Kg';
|
||||
}else if (prefix2 in this.client_prefix_set){
|
||||
parse_result.type = 'client';
|
||||
parse_result.prefix = prefix2;
|
||||
parse_result.id = ean.substring(0,7);
|
||||
}else if (prefix2 in this.cashier_prefix_set){
|
||||
parse_result.type = 'cashier';
|
||||
parse_result.prefix = prefix2;
|
||||
parse_result.id = ean.substring(0,7);
|
||||
}else if (prefix2 in this.discount_prefix_set){
|
||||
parse_result.type = 'discount';
|
||||
parse_result.prefix = prefix2;
|
||||
parse_result.id = ean.substring(0,7);
|
||||
parse_result.value = Number(ean.substring(7,12))/100.0;
|
||||
parse_result.unit = '%';
|
||||
}else{
|
||||
parse_result.type = 'unit';
|
||||
parse_result.prefix = '';
|
||||
parse_result.id = ean;
|
||||
}
|
||||
return parse_result;
|
||||
},
|
||||
|
||||
// starts catching keyboard events and tries to interpret codebar
|
||||
// calling the callbacks when needed.
|
||||
connect: function(){
|
||||
var self = this;
|
||||
var codeNumbers = [];
|
||||
var timeStamp = 0;
|
||||
var lastTimeStamp = 0;
|
||||
|
||||
// The barcode readers acts as a keyboard, we catch all keyup events and try to find a
|
||||
// barcode sequence in the typed keys, then act accordingly.
|
||||
$('body').delegate('','keyup', function (e){
|
||||
|
||||
//We only care about numbers
|
||||
if (!isNaN(Number(String.fromCharCode(e.keyCode)))) {
|
||||
|
||||
// The barcode reader sends keystrokes with a specific interval.
|
||||
// We look if the typed keys fit in the interval.
|
||||
if (codeNumbers.length==0) {
|
||||
timeStamp = new Date().getTime();
|
||||
} else {
|
||||
if (lastTimeStamp + 30 < new Date().getTime()) {
|
||||
// not a barcode reader
|
||||
codeNumbers = [];
|
||||
timeStamp = new Date().getTime();
|
||||
}
|
||||
}
|
||||
codeNumbers.push(e.keyCode - 48);
|
||||
lastTimeStamp = new Date().getTime();
|
||||
if (codeNumbers.length == 13) {
|
||||
//We have found what seems to be a valid codebar
|
||||
var parse_result = self.parse_ean(codeNumbers.join(''));
|
||||
|
||||
if (parse_result.type === 'error') { //most likely a checksum error, raise warning
|
||||
console.error('ERROR: barcode checksum error:',parse_result);
|
||||
}else if(parse_result.type in {'unit':'', 'weight':'', 'price':''}){ //ean is associated to a product
|
||||
if(self.action_callback['product']){
|
||||
self.action_callback['product'](parse_result);
|
||||
}
|
||||
//this.trigger("codebar",parse_result );
|
||||
}else{
|
||||
if(self.action_callback[parse_result.type]){
|
||||
self.action_callback[parse_result.type](parse_result);
|
||||
}
|
||||
}
|
||||
|
||||
codeNumbers = [];
|
||||
}
|
||||
} else {
|
||||
// NaN
|
||||
codeNumbers = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// stops catching keyboard events
|
||||
disconnect: function(){
|
||||
$('body').undelegate('', 'keyup')
|
||||
},
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
|
||||
function openerp_pos_keyboard(instance, module){ //module is instance.point_of_sale
|
||||
// ---------- OnScreen Keyboard Widget ----------
|
||||
|
||||
// A Widget that displays an onscreen keyboard.
|
||||
// There are two options when creating the widget :
|
||||
//
|
||||
// * 'keyboard_model' : 'simple' | 'full' (default)
|
||||
// The 'full' emulates a PC keyboard, while 'simple' emulates an 'android' one.
|
||||
//
|
||||
// * 'input_selector : (default: '.searchbox input')
|
||||
// defines the dom element that the keyboard will write to.
|
||||
//
|
||||
// The widget is initially hidden. It can be shown with this.show(), and is
|
||||
// automatically shown when the input_selector gets focused.
|
||||
|
||||
module.OnscreenKeyboardWidget = instance.web.Widget.extend({
|
||||
template: 'OnscreenKeyboardSimple',
|
||||
init: function(parent, options){
|
||||
var self = this;
|
||||
this._super(parent,options);
|
||||
options = options || {};
|
||||
|
||||
this.keyboard_model = options.keyboard_model || 'full';
|
||||
if(this.keyboard_model === 'full'){
|
||||
this.template = 'OnscreenKeyboardFull';
|
||||
}
|
||||
|
||||
this.input_selector = options.input_selector || '.searchbox input';
|
||||
|
||||
//show the keyboard when the input zone is clicked.
|
||||
$(this.input_selector).focus(function(){self.show();});
|
||||
|
||||
//Keyboard state
|
||||
this.capslock = false;
|
||||
this.shift = false;
|
||||
this.numlock = false;
|
||||
},
|
||||
|
||||
connect : function(){
|
||||
var self = this;
|
||||
$(this.input_selector).focus(function(){self.show();});
|
||||
},
|
||||
|
||||
// Write a character to the input zone
|
||||
writeCharacter: function(character){
|
||||
var $input = $(this.input_selector);
|
||||
$input[0].value += character;
|
||||
$input.keydown();
|
||||
$input.keyup();
|
||||
},
|
||||
|
||||
// Sends a 'return' character to the input zone. TODO
|
||||
sendReturn: function(){
|
||||
},
|
||||
|
||||
// Removes the last character from the input zone.
|
||||
deleteCharacter: function(){
|
||||
var $input = $(this.input_selector);
|
||||
var input_value = $input[0].value;
|
||||
$input[0].value = input_value.substr(0, input_value.length - 1);
|
||||
$input.keydown();
|
||||
$input.keyup();
|
||||
},
|
||||
|
||||
// Clears the content of the input zone.
|
||||
deleteAllCharacters: function(){
|
||||
var $input = $(this.input_selector);
|
||||
$input[0].value = "";
|
||||
$input.keydown();
|
||||
$input.keyup();
|
||||
},
|
||||
|
||||
// Makes the keyboard show and slide from the bottom of the screen.
|
||||
show: function(){
|
||||
$('.keyboard_frame').show().animate({'height':'235px'}, 500, 'swing');
|
||||
},
|
||||
|
||||
// Makes the keyboard hide by sliding to the bottom of the screen.
|
||||
hide: function(){
|
||||
var self = this;
|
||||
var frame = $('.keyboard_frame');
|
||||
frame.animate({'height':'0'}, 500, 'swing', function(){ frame.hide(); self.reset(); });
|
||||
},
|
||||
|
||||
//What happens when the shift key is pressed : toggle case, remove capslock
|
||||
toggleShift: function(){
|
||||
$('.letter').toggleClass('uppercase');
|
||||
$('.symbol span').toggle();
|
||||
|
||||
self.shift = (self.shift === true) ? false : true;
|
||||
self.capslock = false;
|
||||
},
|
||||
|
||||
//what happens when capslock is pressed : toggle case, set capslock
|
||||
toggleCapsLock: function(){
|
||||
$('.letter').toggleClass('uppercase');
|
||||
self.capslock = true;
|
||||
},
|
||||
|
||||
//What happens when numlock is pressed : toggle symbols and numlock label
|
||||
toggleNumLock: function(){
|
||||
$('.symbol span').toggle();
|
||||
$('.numlock span').toggle();
|
||||
self.numlock = (self.numlock === true ) ? false : true;
|
||||
},
|
||||
|
||||
//After a key is pressed, shift is disabled.
|
||||
removeShift: function(){
|
||||
if (self.shift === true) {
|
||||
$('.symbol span').toggle();
|
||||
if (this.capslock === false) $('.letter').toggleClass('uppercase');
|
||||
|
||||
self.shift = false;
|
||||
}
|
||||
},
|
||||
|
||||
// Resets the keyboard to its original state; capslock: false, shift: false, numlock: false
|
||||
reset: function(){
|
||||
if(this.shift){
|
||||
this.toggleShift();
|
||||
}
|
||||
if(this.capslock){
|
||||
this.toggleCapsLock();
|
||||
}
|
||||
if(this.numlock){
|
||||
this.toggleNumLock();
|
||||
}
|
||||
},
|
||||
|
||||
//called after the keyboard is in the DOM, sets up the key bindings.
|
||||
start: function(){
|
||||
var self = this;
|
||||
|
||||
//this.show();
|
||||
|
||||
|
||||
$('.close_button').click(function(){
|
||||
self.deleteAllCharacters();
|
||||
self.hide();
|
||||
});
|
||||
|
||||
// Keyboard key click handling
|
||||
$('.keyboard li').click(function(){
|
||||
|
||||
var $this = $(this),
|
||||
character = $this.html(); // If it's a lowercase letter, nothing happens to this variable
|
||||
|
||||
if ($this.hasClass('left-shift') || $this.hasClass('right-shift')) {
|
||||
self.toggleShift();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this.hasClass('capslock')) {
|
||||
self.toggleCapsLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this.hasClass('delete')) {
|
||||
self.deleteCharacter();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this.hasClass('numlock')){
|
||||
self.toggleNumLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Special characters
|
||||
if ($this.hasClass('symbol')) character = $('span:visible', $this).html();
|
||||
if ($this.hasClass('space')) character = ' ';
|
||||
if ($this.hasClass('tab')) character = "\t";
|
||||
if ($this.hasClass('return')) character = "\n";
|
||||
|
||||
// Uppercase letter
|
||||
if ($this.hasClass('uppercase')) character = character.toUpperCase();
|
||||
|
||||
// Remove shift once a key is clicked.
|
||||
self.removeShift();
|
||||
|
||||
self.writeCharacter(character);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
openerp.point_of_sale = function(instance) {
|
||||
|
||||
instance.point_of_sale = {};
|
||||
|
||||
var module = instance.point_of_sale;
|
||||
|
||||
openerp_pos_models(instance,module); // import pos_models.js
|
||||
|
||||
openerp_pos_basewidget(instance,module); // import pos_basewidget.js
|
||||
|
||||
openerp_pos_keyboard(instance,module); // import pos_keyboard_widget.js
|
||||
|
||||
openerp_pos_scrollbar(instance,module); // import pos_scrollbar_widget.js
|
||||
|
||||
openerp_pos_screens(instance,module); // import pos_screens.js
|
||||
|
||||
openerp_pos_widgets(instance,module); // import pos_widgets.js
|
||||
|
||||
openerp_pos_devices(instance,module); // import pos_devices.js
|
||||
|
||||
instance.web.client_actions.add('pos.ui', 'instance.point_of_sale.PosWidget');
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,772 @@
|
|||
|
||||
// this file contains the screens definitions. Screens are the
|
||||
// content of the right pane of the pos, containing the main functionalities.
|
||||
// screens are contained in the PosWidget, in pos_widget.js
|
||||
// all screens are present in the dom at all time, but only one is shown at the
|
||||
// same time.
|
||||
//
|
||||
// transition between screens is made possible by the use of the screen_selector,
|
||||
// which is responsible of hiding and showing the screens, as well as maintaining
|
||||
// the state of the screens between different orders.
|
||||
//
|
||||
// all screens inherit from ScreenWidget. the only addition from the base widgets
|
||||
// are show() and hide() which shows and hides the screen but are also used to
|
||||
// bind and unbind actions on widgets and devices. The screen_selector guarantees
|
||||
// that only one screen is shown at the same time and that show() is called after all
|
||||
// hide()s
|
||||
|
||||
function openerp_pos_screens(instance, module){ //module is instance.point_of_sale
|
||||
var QWeb = instance.web.qweb;
|
||||
|
||||
module.ScreenSelector = instance.web.Class.extend({
|
||||
init: function(options){
|
||||
this.pos = options.pos;
|
||||
|
||||
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;
|
||||
|
||||
this.current_popup = null;
|
||||
|
||||
this.current_mode = options.default_mode || 'client';
|
||||
|
||||
this.current_screen = null;
|
||||
|
||||
for(screen_name in this.screen_set){
|
||||
this.screen_set[screen_name].hide();
|
||||
}
|
||||
|
||||
for(popup_name in this.popup_set){
|
||||
this.popup_set[popup_name].hide();
|
||||
}
|
||||
|
||||
this.selected_order = this.pos.get('selectedOrder');
|
||||
this.selected_order.set_screen_data({
|
||||
client_screen: this.default_client_screen,
|
||||
cashier_screen: this.default_cashier_screen,
|
||||
});
|
||||
|
||||
this.pos.bind('change:selectedOrder', this.load_saved_screen, this);
|
||||
},
|
||||
add_screen: function(screen_name, screen){
|
||||
screen.hide();
|
||||
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(){
|
||||
this.close_popup();
|
||||
|
||||
var selectedOrder = this.pos.get('selectedOrder');
|
||||
|
||||
if(this.current_mode === 'client'){
|
||||
this.set_current_screen(selectedOrder.get_screen_data('client_screen') || this.default_client_screen,null,'refresh');
|
||||
}else if(this.current_mode === 'cashier'){
|
||||
this.set_current_screen(selectedOrder.get_screen_data('cashier_screen') || this.default_cashier_screen,null,'refresh');
|
||||
}
|
||||
this.selected_order = selectedOrder;
|
||||
},
|
||||
set_user_mode: function(user_mode){
|
||||
if(user_mode !== this.current_mode){
|
||||
this.close_popup();
|
||||
this.current_mode = user_mode;
|
||||
this.load_saved_screen();
|
||||
}
|
||||
},
|
||||
get_user_mode: function(){
|
||||
return this.current_mode;
|
||||
},
|
||||
set_current_screen: function(screen_name,params,refresh){
|
||||
var screen = this.screen_set[screen_name];
|
||||
if(!screen){
|
||||
console.error("ERROR: set_current_screen("+screen_name+") : screen not found");
|
||||
}
|
||||
|
||||
this.close_popup();
|
||||
var selectedOrder = this.pos.get('selectedOrder');
|
||||
if(this.current_mode === 'client'){
|
||||
selectedOrder.set_screen_data('client_screen',screen_name);
|
||||
if(params){
|
||||
selectedOrder.set_screen_data('client_screen_params',params);
|
||||
}
|
||||
}else{
|
||||
selectedOrder.set_screen_data('cashier_screen',screen_name);
|
||||
if(params){
|
||||
selectedOrder.set_screen_data('cashier_screen_params',params);
|
||||
}
|
||||
}
|
||||
|
||||
if(screen && (refresh || screen !== this.current_screen)){
|
||||
if(this.current_screen){
|
||||
this.current_screen.close();
|
||||
this.current_screen.hide();
|
||||
}
|
||||
this.current_screen = screen;
|
||||
this.current_screen.show();
|
||||
}
|
||||
},
|
||||
get_current_screen_param: function(param){
|
||||
var selected_order = this.pos.get('selectedOrder');
|
||||
if(this.current_mode === 'client'){
|
||||
var params = selected_order.get_screen_data('client_screen_params');
|
||||
}else{
|
||||
var params = selected_order.get_screen_data('cashier_screen_params');
|
||||
}
|
||||
if(params){
|
||||
return params[param];
|
||||
}else{
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
set_default_screen: function(){
|
||||
this.set_current_screen(this.current_mode === 'client' ? this.default_client_screen : this.default_cashier_screen);
|
||||
},
|
||||
});
|
||||
|
||||
module.ScreenWidget = module.PosBaseWidget.extend({
|
||||
|
||||
show_numpad: true,
|
||||
show_leftpane: true,
|
||||
|
||||
init: function(parent,options){
|
||||
this._super(parent,options);
|
||||
this.hidden = false;
|
||||
},
|
||||
|
||||
help_button_action: function(){
|
||||
this.pos_widget.screen_selector.show_popup('help');
|
||||
},
|
||||
|
||||
logout_button_action: function(){
|
||||
this.pos_widget.screen_selector.set_user_mode('client');
|
||||
},
|
||||
|
||||
close_button_action: function(){
|
||||
this.pos_widget.try_close();
|
||||
},
|
||||
|
||||
barcode_product_screen: 'products', //if defined, this screen will be loaded when a product is scanned
|
||||
barcode_product_error_popup: 'error', //if defined, this popup will be loaded when there's an error in the popup
|
||||
|
||||
// what happens when a product is scanned :
|
||||
// it will add the product to the order and go to barcode_product_screen. Or show barcode_product_error_popup if
|
||||
// there's an error.
|
||||
barcode_product_action: function(ean){
|
||||
if(this.pos_widget.scan_product(ean)){
|
||||
this.pos.proxy.scan_item_success();
|
||||
if(this.barcode_product_screen){
|
||||
this.pos_widget.screen_selector.set_current_screen(this.barcode_product_screen);
|
||||
}
|
||||
}else{
|
||||
if(this.barcode_product_error_popup){
|
||||
this.pos_widget.screen_selector.show_popup(this.barcode_product_error_popup);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// what happens when a cashier id barcode is scanned.
|
||||
// the default behavior is the following :
|
||||
// - if there's a user with a matching ean, put it as the active 'cashier', go to cashier mode, and return true
|
||||
// - else : do nothing and return false. You probably want to extend this to show and appropriate error popup...
|
||||
barcode_cashier_action: function(ean){
|
||||
var users = this.pos.get('user_list');
|
||||
for(var i = 0, len = users.length; i < len; i++){
|
||||
if(users[i].ean13 === ean.ean){
|
||||
this.pos.set('cashier',users[i]);
|
||||
this.pos_widget.username.refresh();
|
||||
this.pos.proxy.cashier_mode_activated();
|
||||
this.pos_widget.screen_selector.set_user_mode('cashier');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// what happens when a client id barcode is scanned.
|
||||
// the default behavior is the following :
|
||||
// - if there's a user with a matching ean, put it as the active 'client' and return true
|
||||
// - else : return false.
|
||||
barcode_client_action: function(ean){
|
||||
var users = this.pos.get('user_list');
|
||||
for(var i = 0, len = users.length; i < len; i++){
|
||||
if(users[i].ean13 === ean.ean){
|
||||
this.pos.get('selectedOrder').set_client(users[i]);
|
||||
this.pos_widget.username.refresh();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
//TODO start the transaction
|
||||
},
|
||||
|
||||
// what happens when a discount barcode is scanned : the default behavior
|
||||
// is to set the discount on the last order.
|
||||
barcode_discount_action: function(ean){
|
||||
var last_orderline = this.pos.get('selectedOrder').getLastOrderline();
|
||||
if(last_orderline){
|
||||
last_orderline.set_discount(ean.value)
|
||||
}
|
||||
},
|
||||
|
||||
// this method shows the screen and sets up all the widget related to this screen. Extend this method
|
||||
// if you want to alter the behavior of the screen.
|
||||
show: function(){
|
||||
this.hidden = false;
|
||||
if(this.$element){
|
||||
this.$element.show();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var cashier_mode = this.pos_widget.screen_selector.get_user_mode() === 'cashier';
|
||||
|
||||
this.pos_widget.set_numpad_visible(this.show_numpad && cashier_mode);
|
||||
this.pos_widget.set_leftpane_visible(this.show_leftpane);
|
||||
this.pos_widget.set_cashier_controls_visible(cashier_mode);
|
||||
this.pos_widget.action_bar.set_element_visible('help-button', !cashier_mode, function(){ self.help_button_action(); });
|
||||
this.pos_widget.action_bar.set_element_visible('logout-button', cashier_mode && this.pos.use_selfcheckout, function(){ self.logout_button_action(); });
|
||||
this.pos_widget.action_bar.set_element_visible('close-button', cashier_mode, function(){ self.close_button_action(); });
|
||||
|
||||
this.pos_widget.username.set_user_mode(this.pos_widget.screen_selector.get_user_mode());
|
||||
|
||||
this.pos.barcode_reader.set_action_callback({
|
||||
'cashier': self.barcode_cashier_action ? function(ean){ self.barcode_cashier_action(ean); } : undefined ,
|
||||
'product': self.barcode_product_action ? function(ean){ self.barcode_product_action(ean); } : undefined ,
|
||||
'client' : self.barcode_client_action ? function(ean){ self.barcode_client_action(ean); } : undefined ,
|
||||
'discount': self.barcode_discount_action ? function(ean){ self.barcode_discount_action(ean); } : undefined,
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// this method is called when the screen is closed to make place for a new screen. this is a good place
|
||||
// to put your cleanup stuff as it is guaranteed that for each show() there is one and only one close()
|
||||
close: function(){
|
||||
if(this.pos.barcode_reader){
|
||||
this.pos.barcode_reader.reset_action_callbacks();
|
||||
}
|
||||
if(this.pos_widget.action_bar){
|
||||
this.pos_widget.action_bar.destroy_buttons();
|
||||
}
|
||||
},
|
||||
|
||||
// this methods hides the screen. It's not a good place to put your cleanup stuff as it is called on the
|
||||
// POS initialization.
|
||||
hide: function(){
|
||||
this.hidden = true;
|
||||
if(this.$element){
|
||||
this.$element.hide();
|
||||
}
|
||||
},
|
||||
|
||||
// we need this because some screens re-render themselves when they are hidden
|
||||
// (due to some events, or magic, or both...) we must make sure they remain hidden.
|
||||
// the good solution would probably be to make them not re-render themselves when they
|
||||
// are hidden.
|
||||
renderElement: function(){
|
||||
this._super();
|
||||
if(this.hidden){
|
||||
if(this.$element){
|
||||
this.$element.hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.PopUpWidget = module.PosBaseWidget.extend({
|
||||
show: function(){
|
||||
if(this.$element){
|
||||
this.$element.show();
|
||||
}
|
||||
},
|
||||
hide: function(){
|
||||
if(this.$element){
|
||||
this.$element.hide();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.HelpPopupWidget = module.PopUpWidget.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_widget.screen_selector.close_popup();
|
||||
self.pos.proxy.help_canceled();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
module.ErrorPopupWidget = module.PopUpWidget.extend({
|
||||
template:'ErrorPopupWidget',
|
||||
show: function(){
|
||||
var self = this;
|
||||
this._super();
|
||||
this.pos.proxy.help_needed();
|
||||
this.pos.proxy.scan_item_error_unrecognized();
|
||||
|
||||
this.pos.barcode_reader.save_callbacks();
|
||||
this.pos.barcode_reader.reset_action_callbacks();
|
||||
this.pos.barcode_reader.set_action_callback({
|
||||
'cashier': function(ean){
|
||||
clearInterval(this.intervalID);
|
||||
self.pos.proxy.cashier_mode_activated();
|
||||
self.pos_widget.screen_selector.set_user_mode('cashier');
|
||||
},
|
||||
});
|
||||
},
|
||||
close:function(){
|
||||
this._super();
|
||||
this.pos.proxy.help_canceled();
|
||||
this.pos.barcode_reader.restore_callbacks();
|
||||
},
|
||||
});
|
||||
|
||||
module.ErrorProductNotRecognizedPopupWidget = module.ErrorPopupWidget.extend({
|
||||
template:'ErrorProductNotRecognizedPopupWidget',
|
||||
});
|
||||
|
||||
module.ErrorNoSessionPopupWidget = module.ErrorPopupWidget.extend({
|
||||
template:'ErrorNoSessionPopupWidget',
|
||||
});
|
||||
|
||||
module.ScaleInviteScreenWidget = module.ScreenWidget.extend({
|
||||
template:'ScaleInviteScreenWidget',
|
||||
|
||||
show: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
|
||||
self.pos.proxy.weighting_start();
|
||||
|
||||
this.intervalID = setInterval(function(){
|
||||
var weight = self.pos.proxy.weighting_read_kg();
|
||||
if(weight > 0.001){
|
||||
clearInterval(this.intervalID);
|
||||
self.pos_widget.screen_selector.set_current_screen('scale');
|
||||
}
|
||||
},500);
|
||||
|
||||
this.pos_widget.action_bar.add_new_button(
|
||||
{
|
||||
label: 'back',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
|
||||
click: function(){
|
||||
clearInterval(this.intervalID);
|
||||
self.pos.proxy.weighting_end();
|
||||
self.pos_widget.screen_selector.set_current_screen('products');
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
close: function(){
|
||||
this._super();
|
||||
clearInterval(this.intervalID);
|
||||
},
|
||||
});
|
||||
|
||||
module.ScaleScreenWidget = module.ScreenWidget.extend({
|
||||
template:'ScaleScreenWidget',
|
||||
show: function(){
|
||||
this._super();
|
||||
this.renderElement();
|
||||
var self = this;
|
||||
|
||||
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_widget.screen_selector.set_current_screen('products');
|
||||
}
|
||||
});
|
||||
|
||||
this.validate_button = this.pos_widget.action_bar.add_new_button({
|
||||
label: 'Validate',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/validate.png',
|
||||
click: function(){
|
||||
self.order_product();
|
||||
self.pos_widget.screen_selector.set_current_screen('products');
|
||||
},
|
||||
});
|
||||
|
||||
this.pos.proxy.weighting_start();
|
||||
this.intervalID = setInterval(function(){
|
||||
var weight = self.pos.proxy.weighting_read_kg();
|
||||
if(weight != self.weight){
|
||||
self.weight = weight;
|
||||
self.renderElement();
|
||||
}
|
||||
},200);
|
||||
},
|
||||
renderElement: function(){
|
||||
var self = this;
|
||||
this._super();
|
||||
this.$('.product-picture').click(function(){
|
||||
self.order_product();
|
||||
self.pos_widget.screen_selector.set_current_screen('products');
|
||||
});
|
||||
},
|
||||
get_product: function(){
|
||||
var ss = this.pos_widget.screen_selector;
|
||||
if(ss){
|
||||
return ss.get_current_screen_param('product');
|
||||
}else{
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
order_product: function(){
|
||||
var weight = this.pos.proxy.weighting_read_kg();
|
||||
this.pos.get('selectedOrder').addProduct(this.get_product(),{ quantity:weight });
|
||||
},
|
||||
get_product_name: function(){
|
||||
var product = this.get_product();
|
||||
return (product ? product.get('name') : undefined) || 'Unnamed Product';
|
||||
},
|
||||
get_product_price: function(){
|
||||
var product = this.get_product();
|
||||
return (product ? product.get('list_price') : 0) || 0;
|
||||
},
|
||||
get_product_image: function(){
|
||||
var product = this.get_product();
|
||||
return product ? product.get('product_image_small') : undefined;
|
||||
},
|
||||
get_product_weight: function(){
|
||||
return this.weight || 0;
|
||||
},
|
||||
close: function(){
|
||||
this._super();
|
||||
clearInterval(this.intervalID);
|
||||
this.pos.proxy.weighting_end();
|
||||
},
|
||||
});
|
||||
|
||||
module.ClientPaymentScreenWidget = module.ScreenWidget.extend({
|
||||
template:'ClientPaymentScreenWidget',
|
||||
show: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
|
||||
this.pos.proxy.payment_request(this.pos.get('selectedOrder').getDueLeft(),'card','info'); //TODO TOTAL
|
||||
|
||||
this.intervalID = setInterval(function(){
|
||||
var payment = self.pos.proxy.is_payment_accepted();
|
||||
if(payment === 'payment_accepted'){
|
||||
clearInterval(this.intervalID);
|
||||
|
||||
var currentOrder = self.pos.get('selectedOrder');
|
||||
|
||||
//we get the first cashregister marked as self-checkout
|
||||
var selfCheckoutRegisters = [];
|
||||
for(var i = 0; i < this.pos.get('cashRegisters').models.length; i++){
|
||||
var cashregister = this.pos.get('cashRegisters').models[i];
|
||||
if(cashregister.self_checkout_payment_method){
|
||||
selfCheckoutRegisters.push(cashregister);
|
||||
}
|
||||
}
|
||||
|
||||
var cashregister = selfCheckoutRegisters[0] || this.pos.get('cashRegisters').models[0];
|
||||
currentOrder.addPaymentLine(cashregister);
|
||||
|
||||
self.pos.push_order(currentOrder.exportAsJSON()).then(function() {
|
||||
currentOrder.destroy();
|
||||
self.pos.proxy.transaction_end();
|
||||
self.pos_widget.screen_selector.set_current_screen('welcome');
|
||||
});
|
||||
}else if(payment === 'payment_rejected'){
|
||||
clearInterval(this.intervalID);
|
||||
//TODO show a tryagain thingie ?
|
||||
}
|
||||
},500);
|
||||
|
||||
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.payment_canceled();
|
||||
self.pos_widget.screen_selector.set_current_screen('products');
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
close: function(){
|
||||
this._super();
|
||||
clearInterval(this.intervalID);
|
||||
},
|
||||
});
|
||||
|
||||
module.WelcomeScreenWidget = module.ScreenWidget.extend({
|
||||
template:'WelcomeScreenWidget',
|
||||
|
||||
show_numpad: false,
|
||||
show_leftpane: false,
|
||||
|
||||
barcode_client_action: function(ean){
|
||||
this._super(ean);
|
||||
this.pos_widget.screen_selector.set_current_screen('products');
|
||||
},
|
||||
|
||||
show: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
},
|
||||
});
|
||||
|
||||
module.ProductScreenWidget = module.ScreenWidget.extend({
|
||||
template:'ProductScreenWidget',
|
||||
|
||||
show_numpad: true,
|
||||
show_leftpane: true,
|
||||
|
||||
start: function(){ //FIXME this should work as renderElement... but then the categories aren't properly set. explore why
|
||||
var self = this;
|
||||
this.product_categories_widget = new module.ProductCategoriesWidget(this,{});
|
||||
this.product_categories_widget.replace($('.placeholder-ProductCategoriesWidget'));
|
||||
|
||||
this.product_list_widget = new module.ProductListWidget(this,{
|
||||
click_product_action: function(product){
|
||||
if(product.get('to_weight') && self.pos.use_scale){
|
||||
self.pos_widget.screen_selector.set_current_screen('scale_invite', {product: product});
|
||||
}else{
|
||||
self.pos.get('selectedOrder').addProduct(product);
|
||||
}
|
||||
},
|
||||
});
|
||||
this.product_list_widget.replace($('.placeholder-ProductListWidget'));
|
||||
},
|
||||
|
||||
show: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
|
||||
this.product_categories_widget.reset_category();
|
||||
|
||||
this.pos_widget.order_widget.set_numpad_state(this.pos_widget.numpad.state);
|
||||
if(this.pos.use_virtual_keyboard){
|
||||
this.pos_widget.onscreen_keyboard.connect();
|
||||
}
|
||||
|
||||
if(this.pos_widget.screen_selector.current_mode === 'client'){
|
||||
this.pos_widget.action_bar.add_new_button({
|
||||
label: 'pay',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
|
||||
click: function(){
|
||||
self.pos_widget.screen_selector.set_current_screen('client_payment');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
close: function(){
|
||||
this._super();
|
||||
this.pos_widget.order_widget.set_numpad_state(null);
|
||||
this.pos_widget.payment_screen.set_numpad_state(null);
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
module.ReceiptScreenWidget = module.ScreenWidget.extend({
|
||||
template: 'ReceiptScreenWidget',
|
||||
|
||||
show_numpad: true,
|
||||
show_leftpane: true,
|
||||
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
this.model = options.model;
|
||||
this.user = this.pos.get('user');
|
||||
this.company = this.pos.get('company');
|
||||
this.shop_obj = this.pos.get('shop');
|
||||
},
|
||||
renderElement: function() {
|
||||
this._super();
|
||||
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
|
||||
this.change_selected_order();
|
||||
},
|
||||
show: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
|
||||
this.pos_widget.action_bar.add_new_button({
|
||||
label: 'Print',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/printer.png',
|
||||
click: function(){ self.print(); },
|
||||
});
|
||||
|
||||
this.pos_widget.action_bar.add_new_button({
|
||||
label: 'Next Order',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
|
||||
click: function() { self.finishOrder(); },
|
||||
});
|
||||
},
|
||||
print: function() {
|
||||
window.print();
|
||||
},
|
||||
finishOrder: function() {
|
||||
this.pos.get('selectedOrder').destroy();
|
||||
},
|
||||
change_selected_order: function() {
|
||||
if (this.currentOrderLines)
|
||||
this.currentOrderLines.unbind();
|
||||
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
|
||||
this.currentOrderLines.bind('add', this.refresh, this);
|
||||
this.currentOrderLines.bind('change', this.refresh, this);
|
||||
this.currentOrderLines.bind('remove', this.refresh, this);
|
||||
if (this.currentPaymentLines)
|
||||
this.currentPaymentLines.unbind();
|
||||
this.currentPaymentLines = (this.pos.get('selectedOrder')).get('paymentLines');
|
||||
this.currentPaymentLines.bind('all', this.refresh, this);
|
||||
this.refresh();
|
||||
},
|
||||
refresh: function() {
|
||||
this.currentOrder = this.pos.get('selectedOrder');
|
||||
$('.pos-receipt-container', this.$element).html(QWeb.render('PosTicket',{widget:this}));
|
||||
},
|
||||
});
|
||||
|
||||
module.PaymentScreenWidget = module.ScreenWidget.extend({
|
||||
template: 'PaymentScreenWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
this.model = options.model;
|
||||
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
|
||||
this.bindPaymentLineEvents();
|
||||
this.bind_orderline_events();
|
||||
},
|
||||
show: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
|
||||
if(this.pos.use_cashbox){
|
||||
this.pos.proxy.open_cashbox();
|
||||
}
|
||||
|
||||
this.set_numpad_state(this.pos_widget.numpad.state);
|
||||
|
||||
this.back_button = 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_widget.screen_selector.set_current_screen('products');
|
||||
},
|
||||
});
|
||||
|
||||
this.validate_button = this.pos_widget.action_bar.add_new_button({
|
||||
label: 'Validate',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/validate.png',
|
||||
click: function(){
|
||||
self.validateCurrentOrder();
|
||||
},
|
||||
});
|
||||
},
|
||||
close: function(){
|
||||
this._super();
|
||||
this.pos_widget.order_widget.set_numpad_state(null);
|
||||
this.pos_widget.payment_screen.set_numpad_state(null);
|
||||
},
|
||||
back: function() {
|
||||
this.pos_widget.screen_selector.set_current_screen('products');
|
||||
},
|
||||
validateCurrentOrder: function() {
|
||||
var self = this;
|
||||
var currentOrder = this.pos.get('selectedOrder');
|
||||
|
||||
this.validate_button.$element.attr('disabled','disabled'); //FIXME is the css actually using this attr ?
|
||||
|
||||
this.pos.push_order(currentOrder.exportAsJSON())
|
||||
.then(function() {
|
||||
self.validate_button.$element.removeAttr('disabled');
|
||||
if(self.pos.use_proxy_printer){
|
||||
self.pos.proxy.print_receipt(currentOrder.export_for_printing());
|
||||
self.pos.get('selectedOrder').destroy(); //finish order and go back to scan screen
|
||||
}else{
|
||||
self.pos_widget.screen_selector.set_current_screen('receipt');
|
||||
}
|
||||
});
|
||||
},
|
||||
bindPaymentLineEvents: function() {
|
||||
this.currentPaymentLines = (this.pos.get('selectedOrder')).get('paymentLines');
|
||||
this.currentPaymentLines.bind('add', this.addPaymentLine, this);
|
||||
this.currentPaymentLines.bind('remove', this.renderElement, this);
|
||||
this.currentPaymentLines.bind('all', this.updatePaymentSummary, this);
|
||||
},
|
||||
bind_orderline_events: function() {
|
||||
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
|
||||
this.currentOrderLines.bind('all', this.updatePaymentSummary, this);
|
||||
},
|
||||
change_selected_order: function() {
|
||||
this.currentPaymentLines.unbind();
|
||||
this.bindPaymentLineEvents();
|
||||
this.currentOrderLines.unbind();
|
||||
this.bind_orderline_events();
|
||||
this.renderElement();
|
||||
},
|
||||
addPaymentLine: function(newPaymentLine) {
|
||||
var x = new module.PaymentlineWidget(null, {
|
||||
payment_line: newPaymentLine
|
||||
});
|
||||
x.on_delete.add(_.bind(this.deleteLine, this, x));
|
||||
x.appendTo(this.$('#paymentlines'));
|
||||
},
|
||||
renderElement: function() {
|
||||
this._super();
|
||||
this.$('#paymentlines').empty();
|
||||
this.currentPaymentLines.each(_.bind( function(paymentLine) {
|
||||
this.addPaymentLine(paymentLine);
|
||||
}, this));
|
||||
this.updatePaymentSummary();
|
||||
},
|
||||
deleteLine: function(lineWidget) {
|
||||
this.currentPaymentLines.remove([lineWidget.payment_line]);
|
||||
},
|
||||
updatePaymentSummary: function() {
|
||||
var currentOrder = this.pos.get('selectedOrder');
|
||||
var paidTotal = currentOrder.getPaidTotal();
|
||||
var dueTotal = currentOrder.getTotal();
|
||||
var remaining = dueTotal > paidTotal ? dueTotal - paidTotal : 0;
|
||||
var change = paidTotal > dueTotal ? paidTotal - dueTotal : 0;
|
||||
|
||||
this.$('#payment-due-total').html(dueTotal.toFixed(2));
|
||||
this.$('#payment-paid-total').html(paidTotal.toFixed(2));
|
||||
this.$('#payment-remaining').html(remaining.toFixed(2));
|
||||
this.$('#payment-change').html(change.toFixed(2));
|
||||
},
|
||||
set_numpad_state: function(numpadState) {
|
||||
if (this.numpadState) {
|
||||
this.numpadState.unbind('set_value', this.set_value);
|
||||
this.numpadState.unbind('change:mode', this.setNumpadMode);
|
||||
}
|
||||
this.numpadState = numpadState;
|
||||
if (this.numpadState) {
|
||||
this.numpadState.bind('set_value', this.set_value, this);
|
||||
this.numpadState.bind('change:mode', this.setNumpadMode, this);
|
||||
this.numpadState.reset();
|
||||
this.setNumpadMode();
|
||||
}
|
||||
},
|
||||
setNumpadMode: function() {
|
||||
this.numpadState.set({mode: 'payment'});
|
||||
},
|
||||
set_value: function(val) {
|
||||
this.currentPaymentLines.last().set({amount: val});
|
||||
},
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* This Widget provides a javascript scrollbar that is suitable to use with resistive
|
||||
* tactile screens.
|
||||
*
|
||||
* Options:
|
||||
* target_widget : the widget that will be scrolled.
|
||||
* target_selector : if you don't want to scroll the root element of the the widget, you can provide a
|
||||
* jquery selector string that will match on the widget's dom element. If there is no widget provided,
|
||||
* it will match on the document
|
||||
* step: on each click, the target will be scrolled by it's deplayed size multiplied by this value.
|
||||
* duration: this is the duration of the scrolling animation
|
||||
* wheel_step: the target will be scrolled by wheel_step pixels on each mouse scroll.
|
||||
* track_bottom: the target will be kept on bottom when it's on the bottom and the size has changed
|
||||
* on_show: this function will be called with the scrollbar as sole argument when the scrollbar is shown
|
||||
* on_hide: this function will be called with the scrollbar as sole argument when the scrollbar is hidden
|
||||
*/
|
||||
function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_sale
|
||||
|
||||
module.ScrollbarWidget = instance.web.Widget.extend({
|
||||
template:'ScrollbarWidget',
|
||||
|
||||
init: function(parent,options){
|
||||
var self = this;
|
||||
options = options || {};
|
||||
this._super(parent,options);
|
||||
this.target_widget = options.target_widget;
|
||||
this.target_selector = options.target_selector;
|
||||
this.scroll_target = this.target().scrollTop();
|
||||
this.scroll_step = options.step || 0.8;
|
||||
this.scroll_duration = options.duration || 250;
|
||||
this.wheel_step = options.wheel_step || 80;
|
||||
this.name = options.name || 'unnamed';
|
||||
this.bottom = false; // true if the scroller cannot be scrolled further
|
||||
this.track_bottom = options.track_bottom || false;
|
||||
this.on_show = options.on_show || function(){};
|
||||
this.on_hide = options.on_hide || function(){};
|
||||
|
||||
// these handlers are declared once for the object's lifetime so that we can bind and unbind them.
|
||||
this.resize_handler = function(){
|
||||
setTimeout(function(){
|
||||
if(self.bottom && self.track_bottom){
|
||||
self.set_position(Number.MAX_VALUE);
|
||||
}
|
||||
self.update_scroller_dimensions();
|
||||
self.update_button_status();
|
||||
self.auto_hide(false);
|
||||
},0);
|
||||
};
|
||||
this.target_mousewheel_handler = function(event,delta){
|
||||
self.scroll(delta*self.wheel_step);
|
||||
}
|
||||
},
|
||||
|
||||
renderElement: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
this.$('.up-button').off('click').click(function(){
|
||||
self.page_up();
|
||||
});
|
||||
this.$('.down-button').off('click').click(function(){
|
||||
self.page_down();
|
||||
});
|
||||
this.update_scroller_dimensions(false);
|
||||
this.update_button_status();
|
||||
this.auto_hide(false);
|
||||
this.$element.bind('mousewheel',function(event,delta){
|
||||
self.scroll(delta*self.wheel_step);
|
||||
});
|
||||
this.$element.bind('click',function(event){
|
||||
var vpos = event.pageY - self.$element.offset().top;
|
||||
var spos = self.scroller_dimensions();
|
||||
if(vpos > spos.bar_pos && vpos < spos.pos){
|
||||
self.page_up();
|
||||
}else if( (vpos < spos.bar_pos + spos.bar_height) &&
|
||||
(vpos > spos.pos + spos.height) ){
|
||||
self.page_down();
|
||||
}
|
||||
});
|
||||
// FIXME: use the event bus to handle window resize events
|
||||
$(window).unbind('resize',this.resize_handler);
|
||||
$(window).bind('resize',this.resize_handler);
|
||||
|
||||
this.target().unbind('mousewheel',this.target_mousweheel_handler);
|
||||
this.target().bind('mousewheel',this.target_mousewheel_handler);
|
||||
|
||||
// because the rendering is asynchronous we must wait for the next javascript update
|
||||
// for good dimensions values
|
||||
setTimeout(function(){
|
||||
self.update_scroller_dimensions(false);
|
||||
self.update_button_status();
|
||||
self.auto_hide(false);
|
||||
},0);
|
||||
},
|
||||
|
||||
// binds the window resize and the target scrolling events.
|
||||
// it is good advice not to bind these multiple_times
|
||||
bind_events:function(){
|
||||
$(window).resize(function(){
|
||||
});
|
||||
this.target().bind('mousewheel',function(event,delta){
|
||||
self.scroll(delta*self.wheel_step);
|
||||
});
|
||||
},
|
||||
|
||||
// shows the scrollbar. if animated is true, it will do it in an animated fashion
|
||||
show: function(animated){ //FIXME: animated show and hide don't work ... ?
|
||||
if(animated){
|
||||
this.$element.show().animate({'width':'48px'}, 500, 'swing');
|
||||
}else{
|
||||
this.$element.show().css('width','48px');
|
||||
}
|
||||
this.on_show(this);
|
||||
},
|
||||
|
||||
// hides the scrollbar. if animated is true, it will do it in a animated fashion
|
||||
hide: function(animated){
|
||||
var self = this;
|
||||
if(animated){
|
||||
this.$element.animate({'width':'0px'}, 500, 'swing', function(){ self.$element.hide();});
|
||||
}else{
|
||||
this.$element.hide().css('width','0px');
|
||||
}
|
||||
this.on_hide(this);
|
||||
},
|
||||
|
||||
// returns the scroller position and other information as a dictionnary with the following fields:
|
||||
// pos: the position in pixels of the top of the scroller starting from the top of the scrollbar
|
||||
// height: the height of the scroller in pixels
|
||||
// bar_pos: the position of the top of the scrollbar's inner region, starting from the top
|
||||
// bar_height: the height of the scrollbar's inner region
|
||||
scroller_dimensions: function(){
|
||||
var target = this.target()[0];
|
||||
var scroller_height = target.clientHeight / target.scrollHeight || 0;
|
||||
var scroller_pos = this.scroll_target / target.scrollHeight || 0;
|
||||
var button_up_height = this.$('.up-button')[0].offsetHeight || 48;
|
||||
var button_down_height = this.$('.down-button')[0].offsetHeight || 48;
|
||||
|
||||
var bar_height = this.$element[0].offsetHeight || 96;
|
||||
var scrollbar_height = bar_height - button_up_height - button_down_height;
|
||||
|
||||
scroller_pos = scroller_pos * scrollbar_height + button_up_height;
|
||||
scroller_height = scroller_height * scrollbar_height;
|
||||
|
||||
return { pos: Math.round(scroller_pos),
|
||||
height: Math.round(scroller_height),
|
||||
bar_pos: button_up_height,
|
||||
bar_height: scrollbar_height };
|
||||
},
|
||||
|
||||
|
||||
//checks if it should show or hide the scrollbar based on the target content and then show or hide it
|
||||
// if animated is true, then the scrollbar will be shown or hidden with an animation
|
||||
auto_hide: function(animated){
|
||||
var target = this.target()[0];
|
||||
if(target.clientHeight && (target.clientHeight === target.scrollHeight)){
|
||||
this.hide(animated);
|
||||
}else{
|
||||
this.show(animated);
|
||||
}
|
||||
},
|
||||
|
||||
//returns the pageup/down scrolling distance in pixels
|
||||
get_scroll_step: function(){
|
||||
var target = this.target()[0];
|
||||
var step = target.clientHeight * this.scroll_step;
|
||||
var c = target.scrollHeight / step;
|
||||
var c = Math.max(1,Math.ceil(c));
|
||||
return target.scrollHeight / c;
|
||||
},
|
||||
|
||||
//sets the scroller to the correct size and position based on the target scrolling status
|
||||
//if animated is true, the scroller will move smoothly to its destination
|
||||
update_scroller_dimensions: function(animated){
|
||||
var dim = this.scroller_dimensions();
|
||||
var target = this.target()[0];
|
||||
if(animated){
|
||||
this.$('.scroller').animate({'top':dim.pos+'px', 'height': dim.height+'px'},this.scroll_duration);
|
||||
}else{
|
||||
this.$('.scroller').css({'top':dim.pos+'px', 'height': dim.height+'px'});
|
||||
}
|
||||
if(this.scroll_target + target.clientHeight >= target.scrollHeight){
|
||||
this.bottom = true;
|
||||
}else{
|
||||
this.bottom = false;
|
||||
}
|
||||
},
|
||||
|
||||
//disable or enable the up/down buttons according to the scrolled position
|
||||
update_button_status: function(){
|
||||
var target = this.target()[0];
|
||||
this.$('.up-button').removeClass('disabled');
|
||||
this.$('.down-button').removeClass('disabled');
|
||||
if(this.scroll_target === 0){
|
||||
this.$('.up-button').addClass('disabled');
|
||||
}
|
||||
if(this.scroll_target + target.clientHeight >= target.scrollHeight){
|
||||
this.$('.down-button').addClass('disabled');
|
||||
}
|
||||
},
|
||||
|
||||
//returns the jquery object of the scrolling target
|
||||
target: function(){
|
||||
if(this.target_widget){
|
||||
if(this.target_selector){
|
||||
return this.target_widget.$(this.target_selector);
|
||||
}else{
|
||||
return this.target_widget.$element;
|
||||
}
|
||||
}else if(this.target_selector){
|
||||
return $(this.target_selector);
|
||||
}else{
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
//scroll one page up
|
||||
page_up: function(){
|
||||
return this.set_position(this.scroll_target - this.get_scroll_step(), true);
|
||||
},
|
||||
|
||||
//scroll one page down
|
||||
page_down: function(){
|
||||
return this.set_position(this.scroll_target + this.get_scroll_step(), true);
|
||||
},
|
||||
|
||||
//scrolls up or down by pixels
|
||||
scroll: function(pixels){
|
||||
return this.set_position(this.scroll_target - pixels, false);
|
||||
},
|
||||
|
||||
//scroll to a specific position (in pixels).
|
||||
//if animated is true, it will do this in an animated fashion with a duration equal to scroll_duration
|
||||
set_position: function(position,animated){
|
||||
var self = this;
|
||||
var target = this.target()[0];
|
||||
var bottom = target.scrollHeight-target.clientHeight;
|
||||
this.scroll_target = Math.max(0,Math.min(bottom,position));
|
||||
if(this.scroll_target === 0){
|
||||
this.position = 'top';
|
||||
}else if(this.scroll_target === 'bottom'){
|
||||
this.position = 'bottom';
|
||||
}else{
|
||||
this.position = 'center';
|
||||
}
|
||||
if(animated){
|
||||
this.target().animate({'scrollTop':this.scroll_target},this.scroll_duration);
|
||||
this.update_button_status();
|
||||
this.update_scroller_dimensions(true);
|
||||
}else{
|
||||
this.target().scrollTop(this.scroll_target);
|
||||
this.update_scroller_dimensions(false);
|
||||
this.update_button_status();
|
||||
}
|
||||
return this.scroll_target;
|
||||
},
|
||||
|
||||
//returns the current position of the scrollbar
|
||||
get_position: function(){
|
||||
return this.scroll_target;
|
||||
},
|
||||
|
||||
//returns true if it cannot be scrolled further down
|
||||
is_at_bottom: function(){
|
||||
return this.bottom;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
|
@ -0,0 +1,893 @@
|
|||
function openerp_pos_widgets(instance, module){ //module is instance.point_of_sale
|
||||
var QWeb = instance.web.qweb;
|
||||
|
||||
module.NumpadWidget = module.PosBaseWidget.extend({
|
||||
template:'NumpadWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent);
|
||||
this.state = new module.NumpadState();
|
||||
},
|
||||
start: function() {
|
||||
this.state.bind('change:mode', this.changedMode, this);
|
||||
this.changedMode();
|
||||
this.$element.find('button#numpad-backspace').click(_.bind(this.clickDeleteLastChar, this));
|
||||
this.$element.find('button#numpad-minus').click(_.bind(this.clickSwitchSign, this));
|
||||
this.$element.find('button.number-char').click(_.bind(this.clickAppendNewChar, this));
|
||||
this.$element.find('button.mode-button').click(_.bind(this.clickChangeMode, this));
|
||||
},
|
||||
clickDeleteLastChar: function() {
|
||||
return this.state.deleteLastChar();
|
||||
},
|
||||
clickSwitchSign: function() {
|
||||
return this.state.switchSign();
|
||||
},
|
||||
clickAppendNewChar: function(event) {
|
||||
var newChar;
|
||||
newChar = event.currentTarget.innerText || event.currentTarget.textContent;
|
||||
return this.state.appendNewChar(newChar);
|
||||
},
|
||||
clickChangeMode: function(event) {
|
||||
var newMode = event.currentTarget.attributes['data-mode'].nodeValue;
|
||||
return this.state.changeMode(newMode);
|
||||
},
|
||||
changedMode: function() {
|
||||
var mode = this.state.get('mode');
|
||||
$('.selected-mode').removeClass('selected-mode');
|
||||
$(_.str.sprintf('.mode-button[data-mode="%s"]', mode), this.$element).addClass('selected-mode');
|
||||
},
|
||||
});
|
||||
|
||||
// The paypad allows to select the payment method (cashRegisters)
|
||||
// used to pay the order.
|
||||
module.PaypadWidget = module.PosBaseWidget.extend({
|
||||
template: 'PaypadWidget',
|
||||
renderElement: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
|
||||
this.pos.get('cashRegisters').each(function(cashRegister) {
|
||||
var button = new module.PaypadButtonWidget(self,{
|
||||
pos: self.pos,
|
||||
pos_widget : self.pos_widget,
|
||||
cashRegister: cashRegister,
|
||||
});
|
||||
button.appendTo(self.$element);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.PaypadButtonWidget = module.PosBaseWidget.extend({
|
||||
template: 'PaypadButtonWidget',
|
||||
init: function(parent, options){
|
||||
this._super(parent, options);
|
||||
this.cashRegister = options.cashRegister;
|
||||
},
|
||||
renderElement: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
|
||||
this.$element.click(function(){
|
||||
if (self.pos.get('selectedOrder').get('screen') === 'receipt'){ //TODO Why ?
|
||||
console.warn('TODO should not get there...?');
|
||||
return;
|
||||
}
|
||||
self.pos.get('selectedOrder').addPaymentLine(self.cashRegister);
|
||||
self.pos_widget.screen_selector.set_current_screen('payment');
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
module.OrderlineWidget = module.PosBaseWidget.extend({
|
||||
template: 'OrderlineWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
|
||||
this.model = options.model;
|
||||
this.order = options.order;
|
||||
|
||||
this.model.bind('change', _.bind( function() {
|
||||
this.refresh();
|
||||
}, this));
|
||||
},
|
||||
click_handler: function() {
|
||||
this.order.selectLine(this.model);
|
||||
this.on_selected();
|
||||
},
|
||||
renderElement: function() {
|
||||
this._super();
|
||||
this.$element.click(_.bind(this.click_handler, this));
|
||||
if(this.model.is_selected()){
|
||||
this.$element.addClass('selected');
|
||||
}
|
||||
},
|
||||
refresh: function(){
|
||||
this.renderElement();
|
||||
this.on_refresh();
|
||||
},
|
||||
on_selected: function() {},
|
||||
on_refresh: function(){},
|
||||
});
|
||||
|
||||
module.OrderWidget = module.PosBaseWidget.extend({
|
||||
template:'OrderWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
this.compact = false;
|
||||
this.set_numpad_state(options.numpadState);
|
||||
this.pos.bind('change:selectedOrder', this.change_selected_order, this);
|
||||
this.bind_orderline_events();
|
||||
},
|
||||
set_numpad_state: function(numpadState) {
|
||||
if (this.numpadState) {
|
||||
this.numpadState.unbind('set_value', this.set_value);
|
||||
}
|
||||
this.numpadState = numpadState;
|
||||
if (this.numpadState) {
|
||||
this.numpadState.bind('set_value', this.set_value, this);
|
||||
this.numpadState.reset();
|
||||
}
|
||||
},
|
||||
set_value: function(val) {
|
||||
var order = this.pos.get('selectedOrder');
|
||||
if (order.get('orderLines').length !== 0) {
|
||||
var mode = this.numpadState.get('mode');
|
||||
if( mode === 'quantity'){
|
||||
order.getSelectedLine().set_quantity(val);
|
||||
}else if( mode === 'discount'){
|
||||
order.getSelectedLine().set_discount(val);
|
||||
}else if( mode === 'list_price'){
|
||||
order.getSelectedLine().set_list_price(val);
|
||||
}
|
||||
} else {
|
||||
this.pos.get('selectedOrder').destroy();
|
||||
}
|
||||
},
|
||||
change_selected_order: function() {
|
||||
this.currentOrderLines.unbind();
|
||||
this.bind_orderline_events();
|
||||
this.renderElement();
|
||||
},
|
||||
bind_orderline_events: function() {
|
||||
this.currentOrderLines = (this.pos.get('selectedOrder')).get('orderLines');
|
||||
this.currentOrderLines.bind('add', this.renderElement, this);
|
||||
this.currentOrderLines.bind('remove', this.renderElement, this);
|
||||
},
|
||||
update_numpad: function() {
|
||||
var reset = false;
|
||||
if (this.selected_line !== this.pos.get('selectedOrder').getSelectedLine()) {
|
||||
reset = true;
|
||||
}
|
||||
this.selected_line = this.pos.get('selectedOrder').getSelectedLine();
|
||||
if (reset && this.numpadState)
|
||||
this.numpadState.reset();
|
||||
},
|
||||
renderElement: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
|
||||
if(!this.compact){
|
||||
$('.point-of-sale .order-container').css({'bottom':'0px'});
|
||||
}
|
||||
|
||||
var $content = this.$('.orderlines');
|
||||
this.currentOrderLines.each(_.bind( function(orderLine) {
|
||||
var line = new module.OrderlineWidget(this, {
|
||||
model: orderLine,
|
||||
order: this.pos.get('selectedOrder'),
|
||||
});
|
||||
line.on_selected.add(_.bind(this.update_numpad, this));
|
||||
line.on_refresh.add(_.bind(this.update_summary, this));
|
||||
line.appendTo($content);
|
||||
}, this));
|
||||
this.update_numpad();
|
||||
this.update_summary();
|
||||
|
||||
var position = this.scrollbar ? this.scrollbar.get_position() : 0;
|
||||
var at_bottom = this.scrollbar ? this.scrollbar.is_at_bottom() : false;
|
||||
|
||||
this.scrollbar = new module.ScrollbarWidget(this,{
|
||||
target_widget: this,
|
||||
target_selector: '.order-scroller',
|
||||
name: 'order',
|
||||
track_bottom: true,
|
||||
on_show: function(){
|
||||
self.$('.order-scroller').css({'width':'89%'},100);
|
||||
},
|
||||
on_hide: function(){
|
||||
self.$('.order-scroller').css({'width':'100%'},100);
|
||||
},
|
||||
});
|
||||
|
||||
this.scrollbar.replace(this.$('.placeholder-ScrollbarWidget'));
|
||||
this.scrollbar.set_position(position);
|
||||
|
||||
if( at_bottom ){
|
||||
this.scrollbar.set_position(Number.MAX_VALUE, false);
|
||||
}
|
||||
|
||||
},
|
||||
update_summary: function(){
|
||||
var order = this.pos.get('selectedOrder');
|
||||
var total = order ? order.getTotal() : 0;
|
||||
this.$('.summary .value.total').html(this.format_currency(total));
|
||||
},
|
||||
set_compact: function(compact){
|
||||
if(this.compact !== compact){
|
||||
this.compact = compact;
|
||||
this.renderElement();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.ProductWidget = module.PosBaseWidget.extend({
|
||||
template: 'ProductWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
this.model = options.model;
|
||||
this.model.attributes.weight = options.weight;
|
||||
this.next_screen = options.next_screen;
|
||||
this.click_product_action = options.click_product_action;
|
||||
},
|
||||
add_to_order: function(event) {
|
||||
/* Preserve the category URL */
|
||||
event.preventDefault();
|
||||
return (this.pos.get('selectedOrder')).addProduct(this.model);
|
||||
},
|
||||
set_weight: function(weight){
|
||||
this.model.attributes.weight = weight;
|
||||
this.renderElement();
|
||||
},
|
||||
renderElement: function() {
|
||||
this._super();
|
||||
var self = this;
|
||||
$("a", this.$element).click(function(e){
|
||||
if(self.click_product_action){
|
||||
self.click_product_action(self.model);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
module.PaymentlineWidget = module.PosBaseWidget.extend({
|
||||
template: 'PaymentlineWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
this.payment_line = options.payment_line;
|
||||
this.payment_line.bind('change', this.changedAmount, this);
|
||||
},
|
||||
on_delete: function() {},
|
||||
changeAmount: function(event) {
|
||||
var newAmount;
|
||||
newAmount = event.currentTarget.value;
|
||||
if (newAmount && !isNaN(newAmount)) {
|
||||
this.amount = parseFloat(newAmount);
|
||||
this.payment_line.set_amount(this.amount);
|
||||
}
|
||||
},
|
||||
changedAmount: function() {
|
||||
if (this.amount !== this.payment_line.get_amount())
|
||||
this.renderElement();
|
||||
},
|
||||
renderElement: function() {
|
||||
this.name = this.payment_line.get_cashregister().get('journal_id')[1];
|
||||
this._super();
|
||||
this.$('input').keyup(_.bind(this.changeAmount, this));
|
||||
this.$('.delete-payment-line').click(this.on_delete);
|
||||
},
|
||||
});
|
||||
|
||||
module.OrderButtonWidget = module.PosBaseWidget.extend({
|
||||
template:'OrderButtonWidget',
|
||||
init: function(parent, options) {
|
||||
this._super(parent,options);
|
||||
this.order = options.order;
|
||||
this.order.bind('destroy', _.bind( function() {
|
||||
this.destroy();
|
||||
}, this));
|
||||
this.pos.bind('change:selectedOrder', _.bind( function(pos) {
|
||||
var selectedOrder;
|
||||
selectedOrder = pos.get('selectedOrder');
|
||||
if (this.order === selectedOrder) {
|
||||
this.setButtonSelected();
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
renderElement:function(){
|
||||
this._super();
|
||||
this.$('button.select-order').click(_.bind(this.selectOrder, this));
|
||||
this.$('button.close-order').click(_.bind(this.closeOrder, this));
|
||||
},
|
||||
selectOrder: function(event) {
|
||||
this.pos.set({
|
||||
selectedOrder: this.order
|
||||
});
|
||||
},
|
||||
setButtonSelected: function() {
|
||||
$('.selected-order').removeClass('selected-order');
|
||||
this.$element.addClass('selected-order');
|
||||
},
|
||||
closeOrder: function(event) {
|
||||
this.order.destroy();
|
||||
},
|
||||
});
|
||||
|
||||
module.ActionButtonWidget = instance.web.Widget.extend({
|
||||
template:'ActionButtonWidget',
|
||||
init: function(parent, options){
|
||||
this._super(parent, options);
|
||||
this.label = options.label || 'button';
|
||||
this.rightalign = options.rightalign || false;
|
||||
this.click_action = options.click;
|
||||
if(options.icon){
|
||||
this.icon = options.icon;
|
||||
this.template = 'ActionButtonWidgetWithIcon';
|
||||
}
|
||||
},
|
||||
renderElement: function(){
|
||||
this._super();
|
||||
if(this.click_action){
|
||||
this.$element.click(_.bind(this.click_action, this));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.ActionBarWidget = instance.web.Widget.extend({
|
||||
template:'ActionBarWidget',
|
||||
init: function(parent, options){
|
||||
this._super(parent,options);
|
||||
this.button_list = [];
|
||||
this.fake_buttons = {};
|
||||
this.visibility = {};
|
||||
},
|
||||
set_element_visible: function(element, visible, action){
|
||||
if(visible != this.visibility[element]){
|
||||
this.visibility[element] = visible;
|
||||
if(visible){
|
||||
this.$('.'+element).show();
|
||||
}else{
|
||||
this.$('.'+element).hide();
|
||||
}
|
||||
}
|
||||
if(visible && action){
|
||||
this.$('.'+element).off('click').click(action);
|
||||
}
|
||||
},
|
||||
destroy_buttons:function(){
|
||||
for(var i = 0; i < this.button_list.length; i++){
|
||||
this.button_list[i].destroy();
|
||||
}
|
||||
this.button_list = [];
|
||||
return this;
|
||||
},
|
||||
add_new_button: function(button_options){
|
||||
if(arguments.length == 1){
|
||||
var button = new module.ActionButtonWidget(this,button_options);
|
||||
this.button_list.push(button);
|
||||
button.appendTo($('.pos-actionbar-button-list'));
|
||||
return button;
|
||||
}else{
|
||||
for(var i = 0; i < arguments.length; i++){
|
||||
this.add_new_button(arguments[i]);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
|
||||
module.ProductCategoriesWidget = module.PosBaseWidget.extend({
|
||||
template: 'ProductCategoriesWidget',
|
||||
init: function(parent, options){
|
||||
var self = this;
|
||||
this._super(parent,options);
|
||||
this.product_type = options.product_type || 'all'; // 'all' | 'weightable'
|
||||
this.onlyWeightable = options.onlyWeightable || false;
|
||||
this.category = this.pos.root_category;
|
||||
this.breadcrumb = [];
|
||||
this.subcategories = [];
|
||||
this.set_category();
|
||||
},
|
||||
|
||||
// changes the category. if undefined, sets to root category
|
||||
set_category : function(category){
|
||||
if(!category){
|
||||
this.category = this.pos.root_category;
|
||||
}else{
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
this.breadcrumb = [];
|
||||
for(var i = 1; i < this.category.ancestors.length; i++){
|
||||
this.breadcrumb.push(this.category.ancestors[i]);
|
||||
}
|
||||
if(this.category !== this.pos.root_category){
|
||||
this.breadcrumb.push(this.category);
|
||||
}
|
||||
if(this.product_type === 'weightable'){
|
||||
this.subcategories = [];
|
||||
for(var i = 0; i < this.category.childrens.length; i++){
|
||||
if(this.category.childrens[i].weightable_product_list.length > 0){
|
||||
this.subcategories.push( this.category.childrens[i]);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
this.subcategories = this.category.childrens || [];
|
||||
}
|
||||
},
|
||||
|
||||
renderElement: function(){
|
||||
var self = this;
|
||||
this._super();
|
||||
_.each(this.subcategories, function(category){
|
||||
var button = QWeb.render('CategoryButton',{category:category});
|
||||
button = _.str.trim(button);
|
||||
|
||||
$(button).appendTo(this.$('.category-list')).click(function(event){
|
||||
var id = category.id;
|
||||
var cat = self.pos.categories_by_id[id];
|
||||
self.set_category(cat);
|
||||
self.renderElement();
|
||||
self.search_and_categories(cat);
|
||||
});
|
||||
});
|
||||
// breadcrumb click actions
|
||||
this.$(".oe-pos-categories-list a").click(function(event){
|
||||
var id = $(event.target).data("category-id");
|
||||
var category = self.pos.categories_by_id[id];
|
||||
self.set_category(category);
|
||||
self.renderElement();
|
||||
self.search_and_categories(category);
|
||||
});
|
||||
this.search_and_categories();
|
||||
},
|
||||
|
||||
set_product_type: function(type){ // 'all' | 'weightable'
|
||||
this.product_type = type;
|
||||
this.reset_category();
|
||||
},
|
||||
|
||||
// resets the current category to the root category
|
||||
reset_category: function(){
|
||||
this.set_category();
|
||||
this.renderElement();
|
||||
this.search_and_categories();
|
||||
},
|
||||
|
||||
// filters the products, and sets up the search callbacks
|
||||
search_and_categories: function(category){
|
||||
var self = this;
|
||||
|
||||
var all_products = this.pos.get('product_list');
|
||||
var all_packages = this.pos.get('product.packaging');
|
||||
|
||||
// find all products belonging to the current category
|
||||
var products = [];
|
||||
if(this.product_type === 'weightable'){
|
||||
products = all_products.filter( function(product){
|
||||
return self.category.weightable_product_set[product.id];
|
||||
});
|
||||
}else{
|
||||
products = all_products.filter( function(product){
|
||||
return self.category.product_set[product.id];
|
||||
});
|
||||
}
|
||||
|
||||
// product lists watch for reset events on 'products' to re-render.
|
||||
// FIXME that means all productlist widget re-render... even the hidden ones !
|
||||
this.pos.get('products').reset(products);
|
||||
|
||||
// find all the products whose name match the query in the searchbox
|
||||
this.$('.searchbox input').keyup(function(){
|
||||
var results, search_str;
|
||||
search_str = $(this).val().toLowerCase();
|
||||
if(search_str){
|
||||
results = products.filter( function(p){
|
||||
return p.name.toLowerCase().indexOf(search_str) != -1 ||
|
||||
(p.ean13 && p.ean13.indexOf(search_str) != -1);
|
||||
});
|
||||
self.$element.find('.search-clear').fadeIn();
|
||||
}else{
|
||||
results = products;
|
||||
self.$element.find('.search-clear').fadeOut();
|
||||
}
|
||||
self.pos.get('products').reset(results);
|
||||
});
|
||||
this.$('.searchbox input').click(function(){
|
||||
});
|
||||
|
||||
//reset the search when clicking on reset
|
||||
this.$('.search-clear').click(function(){
|
||||
self.pos.get('products').reset(products);
|
||||
self.$('.searchbox input').val('').focus();
|
||||
self.$('.search-clear').fadeOut();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
module.ProductListWidget = module.ScreenWidget.extend({
|
||||
template:'ProductListWidget',
|
||||
init: function(parent, options) {
|
||||
var self = this;
|
||||
this._super(parent,options);
|
||||
this.model = options.model;
|
||||
this.product_list = [];
|
||||
this.weight = options.weight || 0;
|
||||
this.show_scale = options.show_scale || false;
|
||||
this.next_screen = options.next_screen || false;
|
||||
this.click_product_action = options.click_product_action;
|
||||
|
||||
this.pos.get('products').bind('reset', function(){
|
||||
self.renderElement();
|
||||
});
|
||||
},
|
||||
set_weight: function(weight){
|
||||
for(var i = 0; i < this.product_list.length; i++){
|
||||
this.product_list[i].set_weight(weight);
|
||||
}
|
||||
},
|
||||
renderElement: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
this.product_list = [];
|
||||
this.pos.get('products')
|
||||
.chain()
|
||||
.map(function(product) {
|
||||
var product = new module.ProductWidget(self, {
|
||||
model: product,
|
||||
weight: self.weight,
|
||||
click_product_action: self.click_product_action,
|
||||
})
|
||||
self.product_list.push(product);
|
||||
return product;
|
||||
})
|
||||
.invoke('appendTo', this.$('.product-list'));
|
||||
|
||||
this.scrollbar = new module.ScrollbarWidget(this,{
|
||||
target_widget: this,
|
||||
target_selector: '.product-list-scroller',
|
||||
on_show: function(){
|
||||
self.$('.product-list-scroller').css({'padding-right':'62px'},100);
|
||||
},
|
||||
on_hide: function(){
|
||||
self.$('.product-list-scroller').css({'padding-right':'0px'},100);
|
||||
},
|
||||
});
|
||||
|
||||
this.scrollbar.replace(this.$('.placeholder-ScrollbarWidget'));
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
module.UsernameWidget = module.PosBaseWidget.extend({
|
||||
template: 'UsernameWidget',
|
||||
init: function(parent, options){
|
||||
var options = options || {};
|
||||
this._super(parent,options);
|
||||
this.mode = options.mode || 'cashier';
|
||||
},
|
||||
set_user_mode: function(mode){
|
||||
this.mode = mode;
|
||||
this.refresh();
|
||||
},
|
||||
refresh: function(){
|
||||
this.renderElement();
|
||||
},
|
||||
get_name: function(){
|
||||
var user;
|
||||
if(this.mode === 'cashier'){
|
||||
user = this.pos.get('cashier') || this.pos.get('user');
|
||||
}else{
|
||||
user = this.pos.get('selectedOrder').get_client() || this.pos.get('user');
|
||||
}
|
||||
if(user){
|
||||
return user.name;
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// ---------- Main Point of Sale Widget ----------
|
||||
|
||||
// this is used to notify the user that data is being synchronized on the network
|
||||
module.SynchNotificationWidget = module.PosBaseWidget.extend({
|
||||
template: "SynchNotificationWidget",
|
||||
init: function(parent,options) {
|
||||
options = options || {};
|
||||
this._super(parent,options);
|
||||
},
|
||||
renderElement: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
this.$('.oe_pos_synch-notification-button').click(function(){
|
||||
self.pos.flush();
|
||||
});
|
||||
},
|
||||
start: function(){
|
||||
var self = this;
|
||||
this.pos.bind('change:nbr_pending_operations', function(){
|
||||
self.renderElement();
|
||||
});
|
||||
},
|
||||
get_nbr_pending: function(){
|
||||
return this.pos.get('nbr_pending_operations');
|
||||
},
|
||||
});
|
||||
|
||||
// The PosWidget is the main widget that contains all other widgets in the PointOfSale.
|
||||
// It is mainly composed of :
|
||||
// - a header, containing the list of orders
|
||||
// - a leftpane, containing the list of bought products (orderlines)
|
||||
// - a rightpane, containing the screens (see pos_screens.js)
|
||||
// - an actionbar on the bottom, containing various action buttons
|
||||
// - popups
|
||||
// - an onscreen keyboard
|
||||
// a screen_selector which controls the switching between screens and the showing/closing of popups
|
||||
|
||||
module.PosWidget = module.PosBaseWidget.extend({
|
||||
template: 'PosWidget',
|
||||
init: function() {
|
||||
this._super(arguments[0],{});
|
||||
|
||||
this.pos = new module.PosModel(this.session);
|
||||
this.pos_widget = this; //So that pos_widget's childs have pos_widget set automatically
|
||||
|
||||
this.numpad_visible = true;
|
||||
this.leftpane_visible = true;
|
||||
this.leftpane_width = '440px';
|
||||
this.cashier_controls_visible = true;
|
||||
},
|
||||
|
||||
start: function() {
|
||||
var self = this;
|
||||
return self.pos.ready.then(function() {
|
||||
self.build_currency_template();
|
||||
self.renderElement();
|
||||
|
||||
self.$('.neworder-button').click(_.bind(self.create_new_order, self));
|
||||
|
||||
//when a new order is created, add an order button widget
|
||||
self.pos.get('orders').bind('add', function(new_order){
|
||||
var new_order_button = new module.OrderButtonWidget(null, {
|
||||
order: new_order,
|
||||
pos: self.pos
|
||||
});
|
||||
new_order_button.appendTo($('#orders'));
|
||||
new_order_button.selectOrder();
|
||||
}, self);
|
||||
|
||||
self.pos.get('orders').add(new module.Order({ pos: self.pos }));
|
||||
|
||||
self.build_widgets();
|
||||
|
||||
instance.webclient.set_content_full_screen(true);
|
||||
|
||||
if (!self.pos.get('pos_session')) {
|
||||
self.screen_selector.show_popup('error', 'Sorry, we could not create a user session');
|
||||
}else if(!self.pos.get('pos_config')){
|
||||
self.screen_selector.show_popup('error', 'Sorry, we could not find any PoS Configuration for this session');
|
||||
}
|
||||
|
||||
self.$('.loader').animate({opacity:0},3000,'swing',function(){$('.loader').hide();});
|
||||
self.$('.loader img').hide();
|
||||
|
||||
},function(){ // error when loading models data from the backend
|
||||
self.$('.loader img').hide();
|
||||
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_session_opening']], ['res_id'])
|
||||
.pipe( _.bind(function(res){
|
||||
return instance.connection.rpc('/web/action/load', {'action_id': res[0]['res_id']})
|
||||
.pipe(_.bind(function(result){
|
||||
var action = result.result;
|
||||
this.do_action(action);
|
||||
}, this));
|
||||
}, self));
|
||||
});
|
||||
},
|
||||
|
||||
build_widgets: function() {
|
||||
|
||||
// -------- Screens ---------
|
||||
|
||||
this.product_screen = new module.ProductScreenWidget(this,{});
|
||||
this.product_screen.appendTo($('#rightpane'));
|
||||
|
||||
this.receipt_screen = new module.ReceiptScreenWidget(this, {});
|
||||
this.receipt_screen.appendTo($('#rightpane'));
|
||||
|
||||
this.payment_screen = new module.PaymentScreenWidget(this, {});
|
||||
this.payment_screen.appendTo($('#rightpane'));
|
||||
|
||||
this.welcome_screen = new module.WelcomeScreenWidget(this,{});
|
||||
this.welcome_screen.appendTo($('#rightpane'));
|
||||
|
||||
this.client_payment_screen = new module.ClientPaymentScreenWidget(this, {});
|
||||
this.client_payment_screen.appendTo($('#rightpane'));
|
||||
|
||||
this.scale_invite_screen = new module.ScaleInviteScreenWidget(this, {});
|
||||
this.scale_invite_screen.appendTo($('#rightpane'));
|
||||
|
||||
this.scale_screen = new module.ScaleScreenWidget(this,{});
|
||||
this.scale_screen.appendTo($('#rightpane'));
|
||||
|
||||
// -------- Popups ---------
|
||||
|
||||
this.help_popup = new module.HelpPopupWidget(this, {});
|
||||
this.help_popup.appendTo($('.point-of-sale'));
|
||||
|
||||
this.error_popup = new module.ErrorPopupWidget(this, {});
|
||||
this.error_popup.appendTo($('.point-of-sale'));
|
||||
|
||||
this.error_product_popup = new module.ErrorProductNotRecognizedPopupWidget(this, {});
|
||||
this.error_product_popup.appendTo($('.point-of-sale'));
|
||||
|
||||
this.error_session_popup = new module.ErrorNoSessionPopupWidget(this, {});
|
||||
this.error_session_popup.appendTo($('.point-of-sale'));
|
||||
|
||||
// -------- Misc ---------
|
||||
|
||||
this.notification = new module.SynchNotificationWidget(this,{});
|
||||
this.notification.replace(this.$('.placeholder-SynchNotificationWidget'));
|
||||
|
||||
this.username = new module.UsernameWidget(this,{});
|
||||
this.username.replace(this.$('.placeholder-UsernameWidget'));
|
||||
|
||||
this.action_bar = new module.ActionBarWidget(this);
|
||||
this.action_bar.appendTo($(".point-of-sale #content"));
|
||||
|
||||
this.paypad = new module.PaypadWidget(this, {});
|
||||
this.paypad.replace($('#placeholder-PaypadWidget'));
|
||||
|
||||
this.numpad = new module.NumpadWidget(this);
|
||||
this.numpad.replace($('#placeholder-NumpadWidget'));
|
||||
|
||||
this.order_widget = new module.OrderWidget(this, {});
|
||||
this.order_widget.replace($('#placeholder-OrderWidget'));
|
||||
|
||||
this.onscreen_keyboard = new module.OnscreenKeyboardWidget(this, {
|
||||
'keyboard_model': 'simple'
|
||||
});
|
||||
this.onscreen_keyboard.appendTo($(".point-of-sale #content"));
|
||||
|
||||
// -------- Screen Selector ---------
|
||||
|
||||
this.screen_selector = new module.ScreenSelector({
|
||||
pos: this.pos,
|
||||
screen_set:{
|
||||
'products': this.product_screen,
|
||||
'payment' : this.payment_screen,
|
||||
'client_payment' : this.client_payment_screen,
|
||||
'scale_invite' : this.scale_invite_screen,
|
||||
'scale': this.scale_screen,
|
||||
'receipt' : this.receipt_screen,
|
||||
'welcome' : this.welcome_screen,
|
||||
},
|
||||
popup_set:{
|
||||
'help': this.help_popup,
|
||||
'error': this.error_popup,
|
||||
'error-product': this.error_product_popup,
|
||||
'error-session': this.error_session_popup,
|
||||
},
|
||||
default_client_screen: 'welcome',
|
||||
default_cashier_screen: 'products',
|
||||
default_mode: this.pos.use_selfcheckout ? 'client' : 'cashier',
|
||||
});
|
||||
|
||||
this.screen_selector.set_default_screen();
|
||||
|
||||
this.pos.barcode_reader.connect();
|
||||
},
|
||||
|
||||
//FIXME this method is probably not at the right place ...
|
||||
scan_product: function(parsed_ean){
|
||||
var selectedOrder = this.pos.get('selectedOrder');
|
||||
var scannedProductModel = this.get_product_by_ean(parsed_ean);
|
||||
if (!scannedProductModel){
|
||||
return false;
|
||||
} else {
|
||||
if(parsed_ean.type === 'price'){
|
||||
selectedOrder.addProduct(new module.Product(scannedProductModel), { price:parsed_ean.value});
|
||||
}else if(parsed_ean.type === 'weight'){
|
||||
selectedOrder.addProduct(new module.Product(scannedProductModel), { quantity:parsed_ean.value, merge:false});
|
||||
}else{
|
||||
selectedOrder.addProduct(new module.Product(scannedProductModel));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
get_product_by_ean: function(parsed_ean) {
|
||||
var allProducts = this.pos.get('product_list');
|
||||
var allPackages = this.pos.get('product.packaging');
|
||||
var scannedProductModel = undefined;
|
||||
|
||||
if (parsed_ean.type === 'price' || parsed_ean.type === 'weight') {
|
||||
var itemCode = parsed_ean.id;
|
||||
var scannedPackaging = _.detect(allPackages, function(pack) {
|
||||
return pack.ean && pack.ean.substring(0,7) === itemCode;
|
||||
});
|
||||
if (scannedPackaging) {
|
||||
scannedProductModel = _.detect(allProducts, function(pc) { return pc.id === scannedPackaging.product_id[0];});
|
||||
}else{
|
||||
scannedProductModel = _.detect(allProducts, function(pc) { return pc.ean13 && (pc.ean13.substring(0,7) === parsed_ean.id);});
|
||||
}
|
||||
} else if(parsed_ean.type === 'unit'){
|
||||
scannedProductModel = _.detect(allProducts, function(pc) { return pc.ean13 === parsed_ean.ean;}); //TODO DOES NOT SCALE
|
||||
}
|
||||
return scannedProductModel;
|
||||
},
|
||||
// creates a new order, and add it to the list of orders.
|
||||
create_new_order: function() {
|
||||
var new_order;
|
||||
new_order = new module.Order({ pos: this.pos });
|
||||
this.pos.get('orders').add(new_order);
|
||||
this.pos.set({ selectedOrder: new_order });
|
||||
},
|
||||
changed_pending_operations: function () {
|
||||
var self = this;
|
||||
this.synch_notification.on_change_nbr_pending(self.pos.get('nbr_pending_operations').length);
|
||||
},
|
||||
// shows or hide the numpad and related controls like the paypad.
|
||||
set_numpad_visible: function(visible){
|
||||
if(visible !== this.numpad_visible){
|
||||
this.numpad_visible = visible;
|
||||
if(visible){
|
||||
this.numpad.show();
|
||||
this.paypad.show();
|
||||
this.order_widget.set_compact(true);
|
||||
}else{
|
||||
this.numpad.hide();
|
||||
this.paypad.hide();
|
||||
this.order_widget.set_compact(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
//shows or hide the leftpane (contains the list of orderlines, the numpad, the paypad, etc.)
|
||||
set_leftpane_visible: function(visible){
|
||||
if(visible !== this.leftpane_visible){
|
||||
this.leftpane_visible = visible;
|
||||
if(visible){
|
||||
$('#leftpane').show().animate({'width':this.leftpane_width},500,'swing');
|
||||
$('#rightpane').animate({'left':this.leftpane_width},500,'swing');
|
||||
}else{
|
||||
var leftpane = $('#leftpane');
|
||||
$('#leftpane').animate({'width':'0px'},500,'swing', function(){ leftpane.hide(); });
|
||||
$('#rightpane').animate({'left':'0px'},500,'swing');
|
||||
}
|
||||
}
|
||||
},
|
||||
//shows or hide the controls in the PosWidget that are specific to the cashier ( Orders, close button, etc. )
|
||||
set_cashier_controls_visible: function(visible){
|
||||
if(visible !== this.cashier_controls_visible){
|
||||
this.cashier_controls_visible = visible;
|
||||
if(visible){
|
||||
$('#loggedas').show();
|
||||
$('#rightheader').show();
|
||||
}else{
|
||||
$('#loggedas').hide();
|
||||
$('#rightheader').hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
try_close: function() {
|
||||
var self = this;
|
||||
self.pos.flush().then(function() {
|
||||
self.close();
|
||||
});
|
||||
},
|
||||
close: function() {
|
||||
this.pos.barcode_reader.disconnect();
|
||||
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_close_statement']], ['res_id']).pipe(
|
||||
_.bind(function(res) {
|
||||
return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) {
|
||||
var action = result.result;
|
||||
action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}});
|
||||
this.do_action(action);
|
||||
}, this));
|
||||
}, this));
|
||||
},
|
||||
destroy: function() {
|
||||
instance.webclient.set_content_full_screen(false);
|
||||
self.pos = undefined;
|
||||
this._super();
|
||||
}
|
||||
});
|
||||
}
|
|
@ -2,158 +2,105 @@
|
|||
<!-- vim:fdl=1:
|
||||
-->
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="PointOfSale">
|
||||
<div class="point-of-sale">
|
||||
<div id="topheader">
|
||||
<div id="branding">
|
||||
<img src="/point_of_sale/static/src/img/logo.png" />
|
||||
</div>
|
||||
<div id="loggedas">
|
||||
<span class="oe_pos_synch-notification"></span>
|
||||
<button>Close</button>
|
||||
</div>
|
||||
<div id="rightheader">
|
||||
<div id="order-selector">
|
||||
<button id="neworder-button">+</button>
|
||||
<ol id="orders"></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
||||
<div id="leftpane">
|
||||
<div id="current-order">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Price</td>
|
||||
<td>Disc (%)</td>
|
||||
<td>Qty</td>
|
||||
<td>Total</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="current-order-content"></tbody>
|
||||
</table>
|
||||
<t t-name="PosWidget">
|
||||
<div class="point-of-sale">
|
||||
<div id="topheader">
|
||||
<div id="branding">
|
||||
<img src="/point_of_sale/static/src/img/logo.png" />
|
||||
<span class="placeholder-UsernameWidget"></span>
|
||||
</div>
|
||||
<footer>
|
||||
<ul id="amounts">
|
||||
<li>
|
||||
Subtotal:
|
||||
<t t-if="currency.position == 'before'" t-esc="currency.symbol"/> <span id="subtotal">0</span> <t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
|
||||
</li>
|
||||
<li>
|
||||
Tax:
|
||||
<t t-if="currency.position == 'before'" t-esc="currency.symbol"/> <span id="tax">0</span> <t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
|
||||
</li>
|
||||
<li>
|
||||
Total:
|
||||
<t t-if="currency.position == 'before'" t-esc="currency.symbol"/> <span id="total">0</span> <t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="paypad"></div>
|
||||
<div id="numpad">
|
||||
<button class="input-button number-char">1</button>
|
||||
<button class="input-button number-char">2</button>
|
||||
<button class="input-button number-char">3</button>
|
||||
<button class="mode-button" data-mode='quantity'>Qty</button>
|
||||
<br />
|
||||
<button class="input-button number-char">4</button>
|
||||
<button class="input-button number-char">5</button>
|
||||
<button class="input-button number-char">6</button>
|
||||
<button class="mode-button" data-mode='discount'>Disc</button>
|
||||
<br />
|
||||
<button class="input-button number-char">7</button>
|
||||
<button class="input-button number-char">8</button>
|
||||
<button class="input-button number-char">9</button>
|
||||
<button class="mode-button" data-mode='list_price'>Price</button>
|
||||
<br />
|
||||
<button class="input-button" id="numpad-minus" >+/-</button>
|
||||
<button class="input-button number-char">0</button>
|
||||
<button class="input-button number-char">.</button>
|
||||
<button class="input-button" id="numpad-backspace">
|
||||
<img src="/point_of_sale/static/src/img/backspace.png" width="24" height="21" />
|
||||
</button>
|
||||
<br />
|
||||
<div id="rightheader">
|
||||
<div id="order-selector">
|
||||
<button class="neworder-button">+</button>
|
||||
<ol id="orders"></ol>
|
||||
</div>
|
||||
</footer>
|
||||
<span class="placeholder-SynchNotificationWidget"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rightpane">
|
||||
<div id="products-screen" class="step-screen selected-step">
|
||||
<div id="products-screen-categories"/>
|
||||
<ol id="products-screen-ol" class="product-list"></ol>
|
||||
<div id="content">
|
||||
|
||||
<div id="leftpane">
|
||||
<div id="placeholder-OrderWidget"></div>
|
||||
<footer>
|
||||
<div id="placeholder-PaypadWidget"></div>
|
||||
<div id="placeholder-NumpadWidget"></div>
|
||||
</footer>
|
||||
</div>
|
||||
<div id="payment-screen" class="step-screen" style="display:none">
|
||||
<header><h2>Payment</h2></header>
|
||||
<div class="pos-step-container">
|
||||
<div class="pos-payment-container">
|
||||
<br />
|
||||
<table>
|
||||
<tr>
|
||||
<td class="paymentline-type">Total:</td>
|
||||
<td class="paymentline-amount pos-right-align">
|
||||
<t t-if="currency.position == 'before'" t-esc="currency.symbol"/>
|
||||
<span id="payment-due-total"></span>
|
||||
<t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="paymentlines">
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td class="paymentline-type">Paid:</td>
|
||||
<td class="paymentline-amount pos-right-align">
|
||||
<t t-if="currency.position == 'before'" t-esc="currency.symbol"/>
|
||||
<span id="payment-paid-total"></span>
|
||||
<t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paymentline-type">Change:</td>
|
||||
<td class="paymentline-amount pos-right-align">
|
||||
<t t-if="currency.position == 'before'" t-esc="currency.symbol"/>
|
||||
<span id="payment-remaining"></span>
|
||||
<t t-if="currency.position == 'after'" t-esc="currency.symbol"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pos-payment-buttons">
|
||||
<button class="oe_back_to_products">
|
||||
<img src="/web/static/src/img/icons/gtk-go-back.png"></img>
|
||||
Back to Products</button>
|
||||
<button id="validate-order">
|
||||
<img src="/web/static/src/img/icons/gtk-apply.png"></img>
|
||||
Validate</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rightpane">
|
||||
</div>
|
||||
<span id="receipt-screen"></span>
|
||||
</div>
|
||||
<div class="loader">
|
||||
<img src="/point_of_sale/static/src/img/loader.gif" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="pos-synch-notification">
|
||||
<span>
|
||||
<a t-if="widget.nbr_pending > 0" href="javascript:void(0)" class="oe_pos_synch-notification-button">
|
||||
<t t-esc="widget.nbr_pending"/> pending orders
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<t t-name="SynchNotificationWidget">
|
||||
<div class="oe_pos_synch-notification">
|
||||
<t t-if="widget.get_nbr_pending() > 0" t-esc="widget.get_nbr_pending()"/>
|
||||
<div t-if="widget.get_nbr_pending() > 0" class="oe_status_red"></div>
|
||||
<div t-if="widget.get_nbr_pending() === 0" class="oe_status_green"></div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="pos-close-warning">
|
||||
|
||||
<t t-name="PosCloseWarning">
|
||||
<div>There are pending operations that could not be saved into the database, are you sure you want to exit?</div>
|
||||
</t>
|
||||
<t t-name="pos-category-template">
|
||||
|
||||
<t t-name="PaypadWidget">
|
||||
<div id="paypad">
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="NumpadWidget">
|
||||
<div id="numpad">
|
||||
<button class="input-button number-char">1</button>
|
||||
<button class="input-button number-char">2</button>
|
||||
<button class="input-button number-char">3</button>
|
||||
<button class="mode-button" data-mode='quantity'>Qty</button>
|
||||
<br />
|
||||
<button class="input-button number-char">4</button>
|
||||
<button class="input-button number-char">5</button>
|
||||
<button class="input-button number-char">6</button>
|
||||
<button class="mode-button" data-mode='discount'>Disc</button>
|
||||
<br />
|
||||
<button class="input-button number-char">7</button>
|
||||
<button class="input-button number-char">8</button>
|
||||
<button class="input-button number-char">9</button>
|
||||
<button class="mode-button" data-mode='list_price'>Price</button>
|
||||
<br />
|
||||
<button class="input-button" id="numpad-minus" >+/-</button>
|
||||
<button class="input-button number-char">0</button>
|
||||
<button class="input-button number-char">.</button>
|
||||
<button class="input-button" id="numpad-backspace">
|
||||
<img src="/point_of_sale/static/src/img/backspace.png" width="24" height="21" />
|
||||
</button>
|
||||
<br />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="CategoryButton">
|
||||
<li class='category-button'>
|
||||
<div class="category-img">
|
||||
<img t-att-src="'data:image/gif;base64,'+ category.category_image_small" />
|
||||
</div>
|
||||
<div class="category-name">
|
||||
<t t-esc="category.name"/>
|
||||
</div>
|
||||
</li>
|
||||
</t>
|
||||
|
||||
<t t-name="ProductCategoriesWidget">
|
||||
<header>
|
||||
<ol class="breadcrumb">
|
||||
<li class="oe_pos_categories_list">
|
||||
<li class="oe-pos-categories-list">
|
||||
<a href="javascript:void(0)">
|
||||
<img src="/point_of_sale/static/src/img/home.png" class="homeimg" />
|
||||
</a>
|
||||
</li>
|
||||
<t t-foreach="breadcrumb" t-as="category">
|
||||
<li class="oe_pos_categories_list">
|
||||
<t t-foreach="widget.breadcrumb" t-as="category">
|
||||
<li class="oe-pos-categories-list">
|
||||
<img src="/point_of_sale/static/src/img/bc-arrow.png" class="bc-arrow" />
|
||||
<a href="javascript:void(0)" t-att-data-category-id="category.id">
|
||||
<t t-esc="category.name"/>
|
||||
|
@ -166,81 +113,360 @@
|
|||
<img class="search-clear" src="/point_of_sale/static/src/img/search_reset.gif" />
|
||||
</div>
|
||||
</header>
|
||||
<div id="categories">
|
||||
<ol>
|
||||
<t t-foreach="categories" t-as="category">
|
||||
<li class="oe_pos_categories_list">
|
||||
<a href="javascript:void(0)" t-att-data-category-id="category.id" class="button">
|
||||
<t t-esc="category.name"/>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</ol>
|
||||
<t t-if="widget.subcategories.length > 0">
|
||||
<div id="categories">
|
||||
<div class="white-gradient"></div>
|
||||
<ol class="category-list">
|
||||
</ol>
|
||||
<div class="shadow-top"></div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ProductListWidget">
|
||||
<div class='product-list-container'>
|
||||
<div class="product-list-scroller">
|
||||
<ol id="products-screen-ol" class="product-list">
|
||||
</ol>
|
||||
</div>
|
||||
<div class="shadow-top"></div>
|
||||
<span class="placeholder-ScrollbarWidget" />
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="pos-product-template">
|
||||
<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)"/>
|
||||
|
||||
<t t-name="ProductScreenWidget">
|
||||
<div id="products-screen" class="screen">
|
||||
<table class="layout-table">
|
||||
|
||||
<tr class="header-row">
|
||||
<td class="header-cell">
|
||||
<span class="placeholder-ProductCategoriesWidget" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="content-row">
|
||||
<td class="content-cell">
|
||||
<div class="content-container">
|
||||
<span class="placeholder-ProductListWidget" />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ScaleScreenWidget">
|
||||
<div class="scale-screen screen">
|
||||
<header><h2>Product Weighting</h2></header>
|
||||
<div class="display">
|
||||
<span class="weight">
|
||||
<p>
|
||||
<t t-esc="widget.get_product_weight().toFixed(3)" />
|
||||
Kg
|
||||
</p>
|
||||
</span>
|
||||
<span class="product-name">
|
||||
<t t-esc="widget.get_product_name()" />
|
||||
</span>
|
||||
<div class="product-picture">
|
||||
<span class="product-price">
|
||||
<t t-esc="widget.format_currency(widget.get_product_price()) + '/Kg'" />
|
||||
</span>
|
||||
<t t-if="widget.get_product_image()">
|
||||
<img t-att-src="'data:image/png;base64,'+ widget.get_product_image()" />
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="product-name">
|
||||
<t t-esc="name"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="PaymentScreenWidget">
|
||||
<div id="payment-screen" class="screen">
|
||||
<header><h2>Payment</h2></header>
|
||||
<div class="pos-step-container">
|
||||
<div class="pos-payment-container">
|
||||
<br />
|
||||
<div class="header">
|
||||
<span class="left-block">
|
||||
Total:
|
||||
</span>
|
||||
<span class="right-block">
|
||||
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
|
||||
<span id="payment-due-total"></span>
|
||||
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
|
||||
</span>
|
||||
</div>
|
||||
<table id="paymentlines">
|
||||
</table>
|
||||
<div class="footer">
|
||||
<div class="infoline">
|
||||
<span class='left-block'>
|
||||
Paid:
|
||||
</span>
|
||||
<span class='right-block'>
|
||||
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
|
||||
<span id="payment-paid-total"></span>
|
||||
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="infoline">
|
||||
<span class='left-block'>
|
||||
Remaining:
|
||||
</span>
|
||||
<span class='right-block'>
|
||||
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
|
||||
<span id="payment-remaining"></span>
|
||||
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="infoline">
|
||||
<span class='left-block'>
|
||||
Change:
|
||||
</span>
|
||||
<span class='right-block'>
|
||||
<t t-if="widget.currency.position == 'before'" t-esc="widget.currency.symbol"/>
|
||||
<span id="payment-change"></span>
|
||||
<t t-if="widget.currency.position == 'after'" t-esc="widget.currency.symbol"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</t>
|
||||
<t t-name="pos-orderline-template">
|
||||
<td>
|
||||
<t t-esc="name"/>
|
||||
</td>
|
||||
<td>
|
||||
<t t-esc="format_amount(list_price.toFixed(2))"/>
|
||||
</td>
|
||||
<td>
|
||||
<t t-esc="discount.toFixed(2)"/>
|
||||
</td>
|
||||
<td>
|
||||
<t t-esc="quantity.toFixed(0)"/>
|
||||
</td>
|
||||
<td>
|
||||
<t t-esc="format_amount((list_price * (1 - discount/100) * quantity).toFixed(2))"/>
|
||||
</td>
|
||||
</t>
|
||||
<t t-name="pos-paymentline-template">
|
||||
<td class="paymentline-type">
|
||||
<t t-esc="name"/>
|
||||
</td>
|
||||
<td class="paymentline-amount pos-right-align">
|
||||
<input type="text" t-att-value="amount.toFixed(2)" />
|
||||
<a href='javascript:void(0)' class='delete-payment-line'><img src="/point_of_sale/static/src/img/search_reset.gif" /></a>
|
||||
</td>
|
||||
</t>
|
||||
<t t-name="pos-payment-button-template">
|
||||
<button class="payment-button" t-att-cash-register-id="id">
|
||||
<t t-esc="name"/>
|
||||
</button>
|
||||
<br />
|
||||
</t>
|
||||
<t t-name="pos-order-selector-button-template">
|
||||
<button class="select-order"><t t-esc="widget.order.get('creationDate').toString('t')"/></button>
|
||||
</t>
|
||||
<t t-name="pos-receipt-view">
|
||||
<div id="receipt-screen" class="step-screen" style="display:none">
|
||||
</div>
|
||||
</t> <!-- pos-payment-screen -->
|
||||
|
||||
<t t-name="ReceiptScreenWidget">
|
||||
<div id="receipt-screen" class="screen" >
|
||||
<header><h2>Receipt</h2></header>
|
||||
<div class="pos-step-container">
|
||||
<div class="pos-receipt-container">
|
||||
</div>
|
||||
<div class='receipt-buttons'>
|
||||
<button id="print-the-ticket">
|
||||
Print</button>
|
||||
<button id="pos-finish-order">Next Order</button>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="WelcomeScreenWidget">
|
||||
<div class="welcome-screen screen">
|
||||
<header><h2>Welcome</h2></header>
|
||||
<img src="/point_of_sale/static/src/img/scan.png" />
|
||||
<p> Please scan an item or your member card </p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ScanProductScreenWidget">
|
||||
<div class="scan-product-screen screen">
|
||||
<header><h2>Please scan an item</h2></header>
|
||||
<img src="/point_of_sale/static/src/img/scan.png" />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ClientPaymentScreenWidget">
|
||||
<div class="scan-product-screen screen">
|
||||
<header><h2>Payment</h2></header>
|
||||
<img src="/point_of_sale/static/src/img/bancontact.png" />
|
||||
<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 screen">
|
||||
<header><h2>Please put your product on the scale</h2></header>
|
||||
<img src="/point_of_sale/static/src/img/scale.png" />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ScaleProductSelectionScreenWidget">
|
||||
<div class="scale-product-selection-screen">
|
||||
<span class="placeholder-ProductCategoriesWidget" />
|
||||
<span class="placeholder-ProductListWidget" />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<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="pos-ticket">
|
||||
|
||||
<t t-name="ReceiptPopupWidget">
|
||||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
<p class="message">Welcome Mr. John Smith <br /> Choose your type of receipt:</p>
|
||||
<div class = "button big-left receipt">
|
||||
Ticket
|
||||
</div>
|
||||
<div class = "button big-right invoice">
|
||||
Invoice
|
||||
</div>
|
||||
<div class="footer">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ErrorProductNotRecognizedPopupWidget">
|
||||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
<p class="message">The scanned product was not recognized<br /> Please wait, a cashier is on the way</p>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ErrorNoSessionPopupWidget">
|
||||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
<p class="message">Sorry, we could not create a session for this user.</p>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ErrorPopupWidget">
|
||||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
<p class="message"><t t-esc=" widget.message || 'Error.' " /></p>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ProductWidget">
|
||||
<li class='product'>
|
||||
<a href="#">
|
||||
<div class="product-img">
|
||||
|
||||
<img t-att-src="'data:image/gif;base64,'+ widget.model.get('product_image_small')" />
|
||||
<t t-if="!widget.model.get('to_weight')">
|
||||
<span class="price-tag">
|
||||
<t t-esc="widget.format_currency(widget.model.get('list_price'))"/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="widget.model.get('to_weight')">
|
||||
<span class="price-tag">
|
||||
<t t-esc="widget.format_currency(widget.model.get('list_price'))+'/Kg'"/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="product-name">
|
||||
<t t-esc="widget.model.get('name')"/>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
|
||||
<t t-name="ScrollbarWidget">
|
||||
<div class='scrollbar'>
|
||||
<div class='up-button button oe_e'>
|
||||
&atilde;
|
||||
</div>
|
||||
|
||||
<div class='scroller'>
|
||||
</div>
|
||||
|
||||
<div class='down-button button oe_e'>
|
||||
&auml;
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="OrderWidget">
|
||||
<div class="order-container">
|
||||
<div class="order-scroller">
|
||||
<div class="order">
|
||||
<ul class="orderlines">
|
||||
<t t-if="widget.pos.get('selectedOrder').get('orderLines').length === 0">
|
||||
<li class="orderline empty">
|
||||
Your shopping cart is empty
|
||||
</li>
|
||||
</t>
|
||||
|
||||
</ul>
|
||||
<div class="summary">
|
||||
<span t-attf-class="line #{widget.pos.get('selectedOrder').get('orderLines').length === 0 ? 'empty' : ''}">
|
||||
<span class="label total">Total:</span> <span class="value total">0.00 €</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shadow-top"></div>
|
||||
<span class="placeholder-ScrollbarWidget"></span>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="OrderlineWidget">
|
||||
<li class="orderline">
|
||||
<span class="product-name">
|
||||
<t t-esc="widget.model.get_product().get('name')"/>
|
||||
</span>
|
||||
<span class="price">
|
||||
<t t-esc="widget.format_currency(widget.model.get_price_with_tax())"/>
|
||||
</span>
|
||||
<ul class="info-list">
|
||||
<t t-if="widget.model.get_quantity() !== 1.0">
|
||||
<li class="info">
|
||||
<em>
|
||||
<t t-esc="widget.model.get_quantity()" />
|
||||
</em>
|
||||
<t t-esc="widget.model.get_unit().name" />
|
||||
at
|
||||
<t t-esc="widget.format_currency(widget.model.get_list_price())" />
|
||||
/
|
||||
<t t-esc="widget.model.get_unit().name" />
|
||||
</li>
|
||||
</t>
|
||||
<t t-if="widget.model.get_discount() > 0">
|
||||
<li class="info">
|
||||
With a
|
||||
<em>
|
||||
<t t-esc="widget.model.get_discount()" />%
|
||||
</em>
|
||||
discount
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</li>
|
||||
</t>
|
||||
|
||||
<t t-name="PaymentlineWidget">
|
||||
<tr class="paymentline">
|
||||
<td class="paymentline-type">
|
||||
<t t-esc="widget.name"/>
|
||||
</td>
|
||||
<td class="paymentline-amount pos-right-align">
|
||||
<input type="text" t-att-value="widget.payment_line.get_amount().toFixed(2)" />
|
||||
<a href='javascript:void(0)' class='delete-payment-line'><img src="/point_of_sale/static/src/img/search_reset.gif" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-name="PaypadButtonWidget">
|
||||
<button class="paypad-button" t-att-cash-register-id="widget.cashRegister.get('id')">
|
||||
<t t-esc="widget.cashRegister.get('journal').name"/>
|
||||
</button>
|
||||
<br />
|
||||
</t>
|
||||
|
||||
<t t-name="OrderButtonWidget">
|
||||
<li class="order-selector-button">
|
||||
<button class="select-order"><t t-esc="widget.order.get('creationDate').toString('t')"/></button>
|
||||
</li>
|
||||
</t>
|
||||
|
||||
<t t-name="UsernameWidget">
|
||||
<span class="username">
|
||||
<t t-esc="widget.get_name()" />
|
||||
</span>
|
||||
</t>
|
||||
|
||||
<t t-name="PosTicket">
|
||||
<div class="pos-sale-ticket">
|
||||
<div class="pos-right-align"><t t-esc="new Date().toString(Date.CultureInfo.formatPatterns.shortDate + ' ' +
|
||||
Date.CultureInfo.formatPatterns.longTime)"/></div>
|
||||
|
@ -253,42 +479,196 @@
|
|||
<table>
|
||||
<tr t-foreach="widget.currentOrderLines.toArray()" t-as="order">
|
||||
<td>
|
||||
<t t-esc="order.get('name')"/>
|
||||
<t t-esc="order.get_product().get('name')"/>
|
||||
</td>
|
||||
<td class="pos-right-align">
|
||||
<t t-esc="order.get('quantity').toFixed(0)"/>
|
||||
<t t-esc="order.get_quantity().toFixed(0)"/>
|
||||
</td>
|
||||
<td class="pos-right-align">
|
||||
<t t-esc="format_amount((order.get('list_price') * (1 - order.get('discount')/100) * order.get('quantity')).toFixed(2))"/>
|
||||
<t t-esc="widget.format_currency(order.get_list_price() * (1 - order.get_discount()/100) * order.get_quantity().toFixed(2))"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table>
|
||||
<tr><td>Tax:</td><td class="pos-right-align">
|
||||
<t t-esc="format_amount(widget.currentOrder.getTax().toFixed(2))"/>
|
||||
<t t-esc="widget.format_currency(widget.currentOrder.getTax().toFixed(2))"/>
|
||||
</td></tr>
|
||||
<tr><td>Total:</td><td class="pos-right-align">
|
||||
<t t-esc="format_amount(widget.currentOrder.getTotal().toFixed(2))"/>
|
||||
<t t-esc="widget.format_currency(widget.currentOrder.getTotal().toFixed(2))"/>
|
||||
</td></tr>
|
||||
</table>
|
||||
<br />
|
||||
<table>
|
||||
<tr t-foreach="widget.currentPaymentLines.toArray()" t-as="pline">
|
||||
<td>
|
||||
<t t-esc="pline.get('journal_id')[1]"/>
|
||||
<t t-esc="pline.get_cashregister().get('journal_id')[1]"/>
|
||||
</td>
|
||||
<td class="pos-right-align">
|
||||
<t t-esc="format_amount((pline.getAmount()).toFixed(2))"/>
|
||||
<t t-esc="widget.format_currency((pline.get_amount()).toFixed(2))"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table>
|
||||
<tr><td>Change:</td><td class="pos-right-align">
|
||||
<t t-esc="format_amount((widget.currentOrder.getPaidTotal() - widget.currentOrder.getTotal()).toFixed(2))"/>
|
||||
<t t-esc="widget.format_currency((widget.currentOrder.getPaidTotal() - widget.currentOrder.getTotal()).toFixed(2))"/>
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ActionBarWidget">
|
||||
<div class="pos-actionbar">
|
||||
<div class="pos-actionbar-left-pane">
|
||||
<div class="button help-button">
|
||||
<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 close-button">
|
||||
<div class='icon'>
|
||||
<img src="/point_of_sale/static/src/img/icons/png48/shut-down.png" />
|
||||
<div class='iconlabel'>Close</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'>Client Mode</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="pos-actionbar-button-list">
|
||||
<!-- <li class="button">BUTTOOON</li>
|
||||
<li class="button">JEEENKIINS</li>
|
||||
<li class="button rightalign">ARGH</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ActionButtonWidget">
|
||||
<li t-att-class=" 'button '+ (widget.rightalign ? 'rightalign ' : '')">
|
||||
<div class='label'>
|
||||
<t t-esc="widget.label" />
|
||||
</div>
|
||||
</li>
|
||||
</t>
|
||||
|
||||
<t t-name="ActionButtonWidgetWithIcon">
|
||||
<li t-att-class=" 'button '+ (widget.rightalign ? 'rightalign ' : '')">
|
||||
<div class='icon'>
|
||||
<img t-att-src="widget.icon" />
|
||||
<div class='iconlabel'><t t-esc="widget.label" /></div>
|
||||
</div>
|
||||
</li>
|
||||
</t>
|
||||
|
||||
<!-- Onscreen Keyboard :
|
||||
http://net.tutsplus.com/tutorials/javascript-ajax/creating-a-keyboard-with-css-and-jquery/ -->
|
||||
<t t-name="OnscreenKeyboardFull">
|
||||
<div class="keyboard_frame">
|
||||
<ul class="keyboard full_keyboard">
|
||||
<li class="symbol"><span class="off">`</span><span class="on">~</span></li>
|
||||
<li class="symbol"><span class="off">1</span><span class="on">!</span></li>
|
||||
<li class="symbol"><span class="off">2</span><span class="on">@</span></li>
|
||||
<li class="symbol"><span class="off">3</span><span class="on">#</span></li>
|
||||
<li class="symbol"><span class="off">4</span><span class="on">$</span></li>
|
||||
<li class="symbol"><span class="off">5</span><span class="on">%</span></li>
|
||||
<li class="symbol"><span class="off">6</span><span class="on">^</span></li>
|
||||
<li class="symbol"><span class="off">7</span><span class="on">&</span></li>
|
||||
<li class="symbol"><span class="off">8</span><span class="on">*</span></li>
|
||||
<li class="symbol"><span class="off">9</span><span class="on">(</span></li>
|
||||
<li class="symbol"><span class="off">0</span><span class="on">)</span></li>
|
||||
<li class="symbol"><span class="off">-</span><span class="on">_</span></li>
|
||||
<li class="symbol"><span class="off">=</span><span class="on">+</span></li>
|
||||
<li class="delete lastitem">delete</li>
|
||||
<li class="tab firstitem">tab</li>
|
||||
<li class="letter">q</li>
|
||||
<li class="letter">w</li>
|
||||
<li class="letter">e</li>
|
||||
<li class="letter">r</li>
|
||||
<li class="letter">t</li>
|
||||
<li class="letter">y</li>
|
||||
<li class="letter">u</li>
|
||||
<li class="letter">i</li>
|
||||
<li class="letter">o</li>
|
||||
<li class="letter">p</li>
|
||||
<li class="symbol"><span class="off">[</span><span class="on">{</span></li>
|
||||
<li class="symbol"><span class="off">]</span><span class="on">}</span></li>
|
||||
<li class="symbol lastitem"><span class="off">\</span><span class="on">|</span></li>
|
||||
<li class="capslock firstitem">caps lock</li>
|
||||
<li class="letter">a</li>
|
||||
<li class="letter">s</li>
|
||||
<li class="letter">d</li>
|
||||
<li class="letter">f</li>
|
||||
<li class="letter">g</li>
|
||||
<li class="letter">h</li>
|
||||
<li class="letter">j</li>
|
||||
<li class="letter">k</li>
|
||||
<li class="letter">l</li>
|
||||
<li class="symbol"><span class="off">;</span><span class="on">:</span></li>
|
||||
<li class="symbol"><span class="off">'</span><span class="on">"</span></li>
|
||||
<li class="return lastitem">return</li>
|
||||
<li class="left-shift firstitem">shift</li>
|
||||
<li class="letter">z</li>
|
||||
<li class="letter">x</li>
|
||||
<li class="letter">c</li>
|
||||
<li class="letter">v</li>
|
||||
<li class="letter">b</li>
|
||||
<li class="letter">n</li>
|
||||
<li class="letter">m</li>
|
||||
<li class="symbol"><span class="off">,</span><span class="on"><</span></li>
|
||||
<li class="symbol"><span class="off">.</span><span class="on">></span></li>
|
||||
<li class="symbol"><span class="off">/</span><span class="on">?</span></li>
|
||||
<li class="right-shift lastitem">shift</li>
|
||||
<li class="space firstitem lastitem">&nbsp;</li>
|
||||
</ul>
|
||||
<p class="close_button">close</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="OnscreenKeyboardSimple">
|
||||
<div class="keyboard_frame">
|
||||
<ul class="keyboard simple_keyboard">
|
||||
<li class="symbol firstitem row_qwerty"><span class="off">q</span><span class="on">1</span></li>
|
||||
<li class="symbol"><span class="off">w</span><span class="on">2</span></li>
|
||||
<li class="symbol"><span class="off">e</span><span class="on">3</span></li>
|
||||
<li class="symbol"><span class="off">r</span><span class="on">4</span></li>
|
||||
<li class="symbol"><span class="off">t</span><span class="on">5</span></li>
|
||||
<li class="symbol"><span class="off">y</span><span class="on">6</span></li>
|
||||
<li class="symbol"><span class="off">u</span><span class="on">7</span></li>
|
||||
<li class="symbol"><span class="off">i</span><span class="on">8</span></li>
|
||||
<li class="symbol"><span class="off">o</span><span class="on">9</span></li>
|
||||
<li class="symbol lastitem"><span class="off">p</span><span class="on">0</span></li>
|
||||
|
||||
<li class="symbol firstitem row_asdf"><span class="off">a</span><span class="on">@</span></li>
|
||||
<li class="symbol"><span class="off">s</span><span class="on">#</span></li>
|
||||
<li class="symbol"><span class="off">d</span><span class="on">%</span></li>
|
||||
<li class="symbol"><span class="off">f</span><span class="on">*</span></li>
|
||||
<li class="symbol"><span class="off">g</span><span class="on">/</span></li>
|
||||
<li class="symbol"><span class="off">h</span><span class="on">-</span></li>
|
||||
<li class="symbol"><span class="off">j</span><span class="on">+</span></li>
|
||||
<li class="symbol"><span class="off">k</span><span class="on">(</span></li>
|
||||
<li class="symbol lastitem"><span class="off">l</span><span class="on">)</span></li>
|
||||
|
||||
<li class="symbol firstitem row_zxcv"><span class="off">z</span><span class="on">?</span></li>
|
||||
<li class="symbol"><span class="off">x</span><span class="on">!</span></li>
|
||||
<li class="symbol"><span class="off">c</span><span class="on">"</span></li>
|
||||
<li class="symbol"><span class="off">v</span><span class="on">'</span></li>
|
||||
<li class="symbol"><span class="off">b</span><span class="on">:</span></li>
|
||||
<li class="symbol"><span class="off">n</span><span class="on">;</span></li>
|
||||
<li class="symbol"><span class="off">m</span><span class="on">,</span></li>
|
||||
<li class="delete lastitem">delete</li>
|
||||
|
||||
<li class="numlock firstitem row_space"><span class="off">123</span><span class="on">ABC</span></li>
|
||||
<li class="space">&nbsp;</li>
|
||||
<li class="symbol"><span class="off">.</span><span class="on">.</span></li>
|
||||
<li class="return lastitem">return</li>
|
||||
</ul>
|
||||
<p class="close_button">close</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
|
@ -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>
|