[MERGE] trunk

bzr revid: al@openerp.com-20120810225211-0t3wn5b6u1pdosay
This commit is contained in:
Antony Lesuisse 2012-08-11 00:52:11 +02:00
commit e991f474c3
87 changed files with 1866 additions and 1403 deletions

View File

@ -45,6 +45,9 @@
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to setup a new bank account.
</p><p>
Configure your company's bank account and select those that must
appear on the report footer.
</p><p>
If you use the accounting application of OpenERP, journals and
accounts will be created automatically based on these data.

View File

@ -169,7 +169,7 @@ class account_cash_statement(osv.osv):
return result
_columns = {
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Cash Transactions",
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Transactions",
store = {
'account.bank.statement': (lambda self, cr, uid, ids, context=None: ids, ['line_ids','move_line_ids'], 10),
'account.bank.statement.line': (_get_statement_from_line, ['amount'], 10),

View File

@ -163,8 +163,10 @@
<sheet string="Supplier Invoice">
<div class="oe_title">
<h1>
<label string="Draft Invoice" attrs="{'invisible': [('state', '&lt;&gt;', 'draft')]}"/>
<label string="Invoice" attrs="{'invisible': [('state', '=', 'draft')]}"/>
<label string="Draft Invoice" attrs="{'invisible': ['|',('state','&lt;&gt;','draft'), ('type','&lt;&gt;','in_invoice')]}"/>
<label string="Draft Refund" attrs="{'invisible': ['|',('state','&lt;&gt;','draft'), ('type','&lt;&gt;','in_refund')]}"/>
<label string="Invoice" attrs="{'invisible': ['|',('state', '=', 'draft'), ('type','&lt;&gt;','in_invoice')]}"/>
<label string="Refund" attrs="{'invisible': ['|',('state', '=', 'draft'), ('type','&lt;&gt;','in_refund')]}"/>
<field name="number" class="oe_inline" attrs="{'invisible': [('state', '=', 'draft')]}"/>
</h1>
</div>
@ -309,9 +311,11 @@
</header>
<sheet string="Invoice">
<h1>
<label string="Draft Invoice " attrs="{'invisible': [('state','not in',('draft',))]}"/>
<label string="Draft Invoice " attrs="{'invisible': ['|',('state','not in',('draft',)), ('type','&lt;&gt;','out_invoice')]}"/>
<label string="Draft Refund " attrs="{'invisible': ['|',('state','not in',('draft',)), ('type','&lt;&gt;','out_refund')]}"/>
<label string="Pro Forma Invoice " attrs="{'invisible': [('state','not in',('proforma','proforma2'))]}"/>
<label string="Invoice " attrs="{'invisible': [('state','in',('draft','proforma','proforma2'))]}"/>
<label string="Invoice " attrs="{'invisible': ['|',('state','in',('draft','proforma','proforma2')), ('type','&lt;&gt;','out_invoice')]}"/>
<label string="Refund " attrs="{'invisible': ['|',('state','in',('draft','proforma','proforma2')), ('type','&lt;&gt;','out_refund')]}"/>
<field name="number" readonly="1" class="oe_inline"/>
</h1>
<field name="type" invisible="1"/>
@ -347,7 +351,7 @@
<field name="invoice_line" nolabel="1" widget="one2many_list" context="{'type': type}">
<tree string="Invoice Lines" editable="bottom">
<field name="invoice_line_tax_id" invisible="1"/>
<field name="product_id" invisible="1"/>
<field name="product_id" />
<field name="name"/>
<field name="account_id" groups="account.group_account_user"
domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view')]"

View File

@ -20,6 +20,7 @@
rml="account/report/account_print_invoice.rml"
string="Invoices"
attachment="(object.state in ('open','paid')) and ('INV'+(object.number or '').replace('/','')+'.pdf')"
attachment_use="True"
usage="default"
/>
<report id="account_transfers" model="account.transfer" name="account.transfer" string="Transfers" xml="account/report/transfer.xml" xsl="account/report/transfer.xsl"/>

View File

@ -109,8 +109,8 @@
<field name="zip" class="oe_inline" placeholder="ZIP"/>
<field name="city" class="oe_inline" placeholder="City"/>
</div>
<field name="state_id" placeholder="State"/>
<field name="country_id" placeholder="Country"/>
<field name="state_id" placeholder="State" options='{"no_open": true}'/>
<field name="country_id" placeholder="Country" options='{"no_open": true}'/>
</div>
</group>
<group name="bank" string="Information About the Bank">

View File

@ -43,6 +43,8 @@ class account_config_settings(osv.osv_memory):
string='Default company currency', help="Main currency of the company."),
'paypal_account': fields.related('company_id', 'paypal_account', type='char', size=128,
string='Paypal account', help="Paypal account (email) for receiving online payments (credit card, etc.) If you set a paypal account, the customer will be able to pay your invoices or quotations with a button \"Pay with Paypal\" in automated emails or through the OpenERP portal."),
'company_footer': fields.related('company_id', 'rml_footer2', type='char', size=250, readonly=True,
string='Bank accounts on reports will display as followed', help="Bank accounts as printed in the footer of each customer document. This is for information purpose only, you should configure these bank accounts through the above button \"Configure Bank Accounts\"."),
'has_chart_of_accounts': fields.boolean('Company has a chart of accounts'),
'chart_template_id': fields.many2one('account.chart.template', 'Template', domain="[('visible','=', True)]"),
@ -152,6 +154,7 @@ class account_config_settings(osv.osv_memory):
'expects_chart_of_accounts': company.expects_chart_of_accounts,
'currency_id': company.currency_id.id,
'paypal_account': company.paypal_account,
'company_footer': company.rml_footer2,
'has_chart_of_accounts': has_chart_of_accounts,
'has_fiscal_year': bool(fiscalyear_count),
'chart_template_id': False,

View File

@ -225,6 +225,8 @@
icon="gtk-go-forward"
type="action"
class="oe_inline oe_link"/>
<label for="company_footer"/>
<field name="company_footer"/>
</div>
<div>
<label for="paypal_account"/>

View File

@ -8,6 +8,7 @@
company_id: base.main_company
partner_id: base.main_partner
acc_number: 123456789
footer: True
bank: base.res_bank_1
bank_name: Reserve
-

View File

@ -49,7 +49,6 @@ eInvoicing & Payments module manage all Voucher Entries such as "Reconciliation
"account_voucher_sequence.xml",
"account_voucher_workflow.xml",
"account_voucher_report.xml",
"wizard/account_voucher_unreconcile_view.xml",
"wizard/account_statement_from_invoice_view.xml",
"account_voucher_view.xml",
"voucher_payment_receipt_view.xml",

View File

@ -46,11 +46,7 @@ class account_voucher(osv.osv):
def _check_paid(self, cr, uid, ids, name, args, context=None):
res = {}
for voucher in self.browse(cr, uid, ids, context=context):
paid = False
for line in voucher.move_ids:
if (line.account_id.type, 'in', ('receivable', 'payable')) and line.reconcile_id:
paid = True
res[voucher.id] = paid
res[voucher.id] = any([((line.account_id.type, 'in', ('receivable', 'payable')) and line.reconcile_id) for line in voucher.move_ids])
return res
def _get_type(self, cr, uid, context=None):
@ -186,15 +182,16 @@ class account_voucher(osv.osv):
res['arch'] = etree.tostring(doc)
return res
def _compute_writeoff_amount(self, cr, uid, line_dr_ids, line_cr_ids, amount):
def _compute_writeoff_amount(self, cr, uid, line_dr_ids, line_cr_ids, amount, type):
debit = credit = 0.0
sign = type == 'payment' and -1 or 1
for l in line_dr_ids:
debit += l['amount']
for l in line_cr_ids:
credit += l['amount']
return abs(amount - abs(credit - debit))
return amount - sign * (credit - debit)
def onchange_line_ids(self, cr, uid, ids, line_dr_ids, line_cr_ids, amount, voucher_currency, context=None):
def onchange_line_ids(self, cr, uid, ids, line_dr_ids, line_cr_ids, amount, voucher_currency, type, context=None):
context = context or {}
if not line_dr_ids and not line_cr_ids:
return {'value':{}}
@ -215,7 +212,7 @@ class account_voucher(osv.osv):
if voucher_line.get('currency_id', company_currency) != company_currency:
is_multi_currency = True
break
return {'value': {'writeoff_amount': self._compute_writeoff_amount(cr, uid, line_dr_ids, line_cr_ids, amount), 'is_multi_currency': is_multi_currency}}
return {'value': {'writeoff_amount': self._compute_writeoff_amount(cr, uid, line_dr_ids, line_cr_ids, amount, type), 'is_multi_currency': is_multi_currency}}
def _get_writeoff_amount(self, cr, uid, ids, name, args, context=None):
if not ids: return {}
@ -223,12 +220,13 @@ class account_voucher(osv.osv):
res = {}
debit = credit = 0.0
for voucher in self.browse(cr, uid, ids, context=context):
sign = voucher.type == 'payment' and -1 or 1
for l in voucher.line_dr_ids:
debit += l.amount
for l in voucher.line_cr_ids:
credit += l.amount
currency = voucher.currency_id or voucher.company_id.currency_id
res[voucher.id] = currency_obj.round(cr, uid, currency, abs(voucher.amount - abs(credit - debit)))
res[voucher.id] = currency_obj.round(cr, uid, currency, voucher.amount - sign * (credit - debit))
return res
def _paid_amount_in_company_currency(self, cr, uid, ids, name, args, context=None):
@ -716,7 +714,7 @@ class account_voucher(osv.osv):
default['value']['pre_line'] = 1
elif ttype == 'receipt' and len(default['value']['line_dr_ids']) > 0:
default['value']['pre_line'] = 1
default['value']['writeoff_amount'] = self._compute_writeoff_amount(cr, uid, default['value']['line_dr_ids'], default['value']['line_cr_ids'], price)
default['value']['writeoff_amount'] = self._compute_writeoff_amount(cr, uid, default['value']['line_dr_ids'], default['value']['line_cr_ids'], price, ttype)
return default
def onchange_payment_rate_currency(self, cr, uid, ids, currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context=None):

View File

@ -40,7 +40,7 @@ class invoice(osv.osv):
'domain': '[]',
'context': {
'default_partner_id': inv.partner_id.id,
'default_amount': inv.residual,
'default_amount': inv.type in ('out_refund', 'in_refund') and -inv.residual or inv.residual,
'default_name':inv.name,
'close_after_process': True,
'invoice_type':inv.type,

View File

@ -141,7 +141,7 @@
!context
'type': 'receipt'
-
I create the first voucher of payment with values 240 USD, journal USD,
On the first March, I create the first voucher of payment with values 240 USD, journal USD,
-
!record {model: account.voucher, id: account_voucher_1_case1, view: view_vendor_receipt_form}:
account_id: account.cash
@ -173,12 +173,12 @@
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 10.0
I check that writeoff amount computed is -10.0
-
!python {model: account.voucher}: |
voucher = self.search(cr, uid, [('name', '=', 'First payment: Case 1 USD/USD'), ('partner_id', '=', ref('base.res_partner_seagate'))])
voucher_id = self.browse(cr, uid, voucher[0])
assert (voucher_id.writeoff_amount == 10.0), "Writeoff amount is not 10.0"
assert (voucher_id.writeoff_amount == -10.0), "Writeoff amount is not -10.0"
-
I confirm the voucher
-
@ -235,7 +235,7 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 30.0) , "Residual amount is not correct for first Invoice"
-
I create the second voucher of payment with values 45 USD, journal USD,
On the first April, I create the second voucher of payment with values 45 USD, journal USD,
-
!record {model: account.voucher, id: account_voucher_2_case1}:
account_id: account.cash
@ -266,12 +266,12 @@
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 5.0
I check that writeoff amount computed is -5.0
-
!python {model: account.voucher}: |
voucher = self.search(cr, uid, [('name', '=', 'Second payment: Case 1'), ('partner_id', '=', ref('base.res_partner_seagate'))])
voucher_id = self.browse(cr, uid, voucher[0])
assert (voucher_id.writeoff_amount == 5.0), "Writeoff amount is not 5.0"
assert (voucher_id.writeoff_amount == -5.0), "Writeoff amount is not -5.0"
-
I confirm the voucher
-

View File

@ -107,11 +107,11 @@
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 50.0
I check that writeoff amount computed is -50.0
-
!python {model: account.voucher}: |
voucher = self.browse(cr, uid, ref('account_voucher_eur_usd_case'))
assert (voucher.writeoff_amount == 50.0), "Writeoff amount is not 50.0"
assert (voucher.writeoff_amount == -50.0), "Writeoff amount is not -50.0"
-
I confirm the voucher
-
@ -167,4 +167,4 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 0.0 and move_line.amount_residual == 0.0 and invoice_id.state == 'paid') , "Residual amount is not correct for Invoice"

View File

@ -74,7 +74,7 @@
</group>
<notebook>
<page string="Payment Information">
<field name="line_dr_ids" attrs="{'invisible': [('type', '=', 'receipt')]}" context="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<field name="line_dr_ids" attrs="{'invisible': [('type', '=', 'receipt')]}" context="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, type, context)">
<tree string="Open Supplier Journal Entries" editable="bottom" colors="gray:amount==0">
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
@ -87,7 +87,7 @@
<field name="amount" sum="Total Allocation"/>
</tree>
</field>
<field name="line_cr_ids" attrs="{'invisible': [('type', '=', 'payment')]}" context="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<field name="line_cr_ids" attrs="{'invisible': [('type', '=', 'payment')]}" context="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, type, context)">
<tree string="Open Customer Journal Entries" editable="bottom" colors="gray:amount==0">
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
@ -332,7 +332,7 @@
<notebook>
<page string="Payment Information" groups="base.group_user">
<field name="line_cr_ids" context="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<field name="line_cr_ids" context="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, type, context)">
<tree string="Invoices and outstanding transactions" editable="bottom" colors="gray:amount==0">
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
@ -348,7 +348,7 @@
<field name="amount" sum="Total Allocation" on_change="onchange_amount(amount, amount_unreconciled, context)" string="Allocation"/>
</tree>
</field>
<field name="line_dr_ids" attrs="{'invisible': [('pre_line','=',False)]}" context="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<field name="line_dr_ids" attrs="{'invisible': [('pre_line','=',False)]}" context="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, type, context)">
<tree string="Credits" editable="bottom" colors="gray:amount==0">
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"

View File

@ -19,7 +19,6 @@
#
##############################################################################
import account_voucher_unreconcile
import account_statement_from_invoice
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -75,16 +75,26 @@ class account_statement_from_invoice_lines(osv.osv_memory):
statement.currency.id, amount, context=ctx)
context.update({'move_line_ids': [line.id]})
result = voucher_obj.onchange_partner_id(cr, uid, [], partner_id=line.partner_id.id, journal_id=statement.journal_id.id, amount=abs(amount), currency_id= statement.currency.id, ttype=(amount < 0 and 'payment' or 'receipt'), date=line_date, context=context)
voucher_res = { 'type':(amount < 0 and 'payment' or 'receipt'),
type = 'general'
ttype = amount < 0 and 'payment' or 'receipt'
sign = 1
if line.journal_id.type in ('sale', 'sale_refund'):
type = 'customer'
ttype = 'receipt'
elif line.journal_id.type in ('purchase', 'purhcase_refund'):
type = 'supplier'
ttype = 'payment'
sign = -1
result = voucher_obj.onchange_partner_id(cr, uid, [], partner_id=line.partner_id.id, journal_id=statement.journal_id.id, amount=sign*amount, currency_id= statement.currency.id, ttype=ttype, date=line_date, context=context)
voucher_res = { 'type': ttype,
'name': line.name,
'partner_id': line.partner_id.id,
'journal_id': statement.journal_id.id,
'account_id': result.get('account_id', statement.journal_id.default_credit_account_id.id), # improve me: statement.journal_id.default_credit_account_id.id
'company_id':statement.company_id.id,
'currency_id':statement.currency.id,
'date':line.date,
'amount':abs(amount),
'account_id': result.get('account_id', statement.journal_id.default_credit_account_id.id),
'company_id': statement.company_id.id,
'currency_id': statement.currency.id,
'date': line.date,
'amount': sign*amount,
'period_id':statement.period_id.id}
voucher_id = voucher_obj.create(cr, uid, voucher_res, context=context)
@ -97,12 +107,6 @@ class account_statement_from_invoice_lines(osv.osv_memory):
if voucher_line_dict:
voucher_line_dict.update({'voucher_id': voucher_id})
voucher_line_obj.create(cr, uid, voucher_line_dict, context=context)
if line.journal_id.type == 'sale':
type = 'customer'
elif line.journal_id.type == 'purchase':
type = 'supplier'
else:
type = 'general'
statement_line_obj.create(cr, uid, {
'name': line.name or '?',
'amount': amount,
@ -112,81 +116,10 @@ class account_statement_from_invoice_lines(osv.osv_memory):
'statement_id': statement_id,
'ref': line.ref,
'voucher_id': voucher_id,
'date': time.strftime('%Y-%m-%d'), #time.strftime('%Y-%m-%d'), #line.date_maturity or,
'date': time.strftime('%Y-%m-%d'),
}, context=context)
return {'type': 'ir.actions.act_window_close'}
account_statement_from_invoice_lines()
class account_statement_from_invoice(osv.osv_memory):
"""
Generate Entries by Statement from Invoices
"""
_name = "account.statement.from.invoice"
_description = "Entries by Statement from Invoices"
_columns = {
'date': fields.date('Date payment',required=True),
'journal_ids': fields.many2many('account.journal', 'account_journal_relation', 'account_id', 'journal_id', 'Journal'),
'line_ids': fields.many2many('account.move.line', 'account_move_line_relation', 'move_id', 'line_id', 'Invoices'),
}
_defaults = {
'date': lambda *a: time.strftime('%Y-%m-%d'),
}
def search_invoices(self, cr, uid, ids, context=None):
if context is None:
context = {}
line_obj = self.pool.get('account.move.line')
statement_obj = self.pool.get('account.bank.statement')
journal_obj = self.pool.get('account.journal')
mod_obj = self.pool.get('ir.model.data')
statement_id = 'statement_id' in context and context['statement_id']
data = self.read(cr, uid, ids, context=context)[0]
statement = statement_obj.browse(cr, uid, statement_id, context=context)
args_move_line = []
repeated_move_line_ids = []
# Creating a group that is unique for importing move lines(move lines, once imported into statement lines, should not appear again)
for st_line in statement.line_ids:
args_move_line = []
args_move_line.append(('name', '=', st_line.name))
args_move_line.append(('ref', '=', st_line.ref))
if st_line.partner_id:
args_move_line.append(('partner_id', '=', st_line.partner_id.id))
args_move_line.append(('account_id', '=', st_line.account_id.id))
move_line_id = line_obj.search(cr, uid, args_move_line, context=context)
if move_line_id:
repeated_move_line_ids += move_line_id
journal_ids = data['journal_ids']
if journal_ids == []:
journal_ids = journal_obj.search(cr, uid, [('type', 'in', ('sale', 'cash', 'purchase'))], context=context)
args = [
('reconcile_id', '=', False),
('journal_id', 'in', journal_ids),
('account_id.reconcile', '=', True)]
if repeated_move_line_ids:
args.append(('id', 'not in', repeated_move_line_ids))
line_ids = line_obj.search(cr, uid, args,
context=context)
model_data_ids = mod_obj.search(cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'view_account_statement_from_invoice_lines')], context=context)
resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
return {
'domain': "[('id','in', ["+','.join([str(x) for x in line_ids])+"])]",
'name': _('Import Entries'),
'context': context,
'view_type': 'form',
'view_mode': 'form',
'res_model': 'account.statement.from.invoice.lines',
'views': [(resource_id,'form')],
'type': 'ir.actions.act_window',
'target': 'new',
}
account_statement_from_invoice()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,34 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_account_statement_from_invoice" model="ir.ui.view">
<field name="name">account.statement.from.invoice.form</field>
<field name="model">account.statement.from.invoice</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Import Invoices in Statement" version="7.0">
<group>
<field name="date"/>
<field name="journal_ids" domain="[('type','in',['sale','purchase','cash'])]"/>
</group>
<footer>
<button string="Go" name="search_invoices" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_view_account_statement_from_invoice" model="ir.actions.act_window">
<field name="name">Import Invoices in Statement</field>
<field name="res_model">account.statement.from.invoice</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_account_statement_from_invoice"/>
<field name="target">new</field>
</record>
<record id="view_account_statement_from_invoice_lines" model="ir.ui.view">
<field name="name">account.statement.from.invoice.lines.form</field>
<field name="model">account.statement.from.invoice.lines</field>

View File

@ -1,62 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 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/>.
#
##############################################################################
from osv import osv
from osv import fields
class account_voucher_unreconcile(osv.osv_memory):
_name = "account.voucher.unreconcile"
_description = "Account voucher unreconcile"
_columns = {
'remove':fields.boolean('Want to remove accounting entries too ?', required=False),
}
_defaults = {
'remove': True,
}
def trans_unrec(self, cr, uid, ids, context=None):
# res = self.browse(cr, uid, ids[0])
if context is None:
context = {}
voucher_pool = self.pool.get('account.voucher')
reconcile_pool = self.pool.get('account.move.reconcile')
if context.get('active_id'):
voucher = voucher_pool.browse(cr, uid, context.get('active_id'), context=context)
recs = []
for line in voucher.move_ids:
if line.reconcile_id:
recs += [line.reconcile_id.id]
if line.reconcile_partial_id:
recs += [line.reconcile_partial_id.id]
#for rec in recs:
reconcile_pool.unlink(cr, uid, recs)
# if res.remove:
voucher_pool.cancel_voucher(cr, uid, [context.get('active_id')], context)
# wf_service = netsvc.LocalService("workflow")
# wf_service.trg_validate(uid, 'account.voucher', context.get('active_id'), 'cancel_voucher', cr)
return {'type': 'ir.actions.act_window_close'}
account_voucher_unreconcile()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_account_voucher_unreconcile" model="ir.ui.view">
<field name="name">Account voucher unreconcile</field>
<field name="model">account.voucher.unreconcile</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Unreconciliation" version="7.0">
<separator string="Unreconciliation Transactions" />
<label string="If you unreconciliate transactions, you must also verify all the actions that are linked to those transactions because they will not be disable"/>
<footer>
<button name="trans_unrec" default_focus="1" string="Unreconcile" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_view_account_voucher_unreconcile">
<field name="name">Unreconcile entries</field>
<field name="res_model">account.voucher.unreconcile</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_account_voucher_unreconcile"/>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -14,9 +14,9 @@
<form string="AuditTrail Rule" version="7.0">
<header>
<button string="_Subscribe" name="subscribe" icon="gtk-ok"
type="object" states="draft" />
type="object" states="draft"/>
<button string="UnSubscribe" name="unsubscribe" icon="gtk-cancel"
type="object" states="subscribed" />
type="object" states="subscribed"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
@ -29,11 +29,11 @@
<field name="log_create"/>
<field name="log_action"/>
<field name="log_workflow"/>
<separator string="Users (if User is not added then it will applicable for all users)" colspan="4" />
<field name="user_id" colspan="4" nolabel="1" />
<separator string="Users (if User is not added then it will applicable for all users)" colspan="4"/>
<field name="user_id" colspan="4" nolabel="1"/>
<field name="action_id" colspan="4" readonly="1" groups="base.group_no_one"/>
</group>
</sheet>
</sheet>
</form>
</field>
</record>
@ -44,15 +44,15 @@
<field name="type">tree</field>
<field name="arch" type="xml">
<tree colors="blue:state == 'draft';black:state == 'subscribed'" string="AuditTrail Rules">
<field name="name" />
<field name="name"/>
<field name="object_id"/>
<field name="log_read" />
<field name="log_write" />
<field name="log_unlink" />
<field name="log_create" />
<field name="log_read"/>
<field name="log_write"/>
<field name="log_unlink"/>
<field name="log_create"/>
<field name="log_action"/>
<field name="log_workflow"/>
<field name="state" />
<field name="state"/>
</tree>
</field>
</record>
@ -108,36 +108,36 @@
<form string="Log Lines" version="7.0">
<group col="4">
<field name="field_id" colspan="4"
readonly="1" />
<newline />
readonly="1"/>
<newline/>
<field name="field_description" colspan="4"
readonly="1" />
<newline />
readonly="1"/>
<newline/>
<separator string="Old Value : "
colspan="2" />
colspan="2"/>
<separator string="New Value : "
colspan="2" />
<newline />
colspan="2"/>
<newline/>
<field name="old_value" nolabel="1"
colspan="2" readonly="1" />
colspan="2" readonly="1"/>
<field name="new_value" nolabel="1"
colspan="2" readonly="1" />
<newline />
colspan="2" readonly="1"/>
<newline/>
<separator string="Old Value Text : "
colspan="2" />
colspan="2"/>
<separator string="New Value Text: "
colspan="2" />
<newline />
colspan="2"/>
<newline/>
<field name="old_value_text" nolabel="1"
colspan="2" readonly="1" />
colspan="2" readonly="1"/>
<field name="new_value_text" nolabel="1"
colspan="2" readonly="1" />
colspan="2" readonly="1"/>
</group>
</form>
<tree string="Log Lines">
<field name="field_description" />
<field name="old_value_text" />
<field name="new_value_text" />
<field name="field_description"/>
<field name="old_value_text"/>
<field name="new_value_text"/>
</tree>
</field>
</sheet>
@ -151,11 +151,11 @@
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="AuditTrail Logs">
<field name="timestamp" />
<field name="name" />
<field name="object_id" />
<field name="method" />
<field name="user_id" />
<field name="timestamp"/>
<field name="name"/>
<field name="object_id"/>
<field name="method"/>
<field name="user_id"/>
</tree>
</field>
</record>
@ -185,7 +185,7 @@
<field name="search_view_id" ref="view_audittrail_log_search"/>
</record>
<menuitem id="menu_audit_logs" name="Audit Logs" parent="menu_audit" action="action_audittrail_log_tree" />
<menuitem id="menu_audit_logs" name="Audit Logs" parent="menu_audit" action="action_audittrail_log_tree"/>
</data>
</openerp>

View File

@ -21,7 +21,7 @@
import logging
import os
import sys
import tempfile
import urllib
import werkzeug.urls
@ -31,53 +31,51 @@ from openerp.modules.registry import RegistryManager
try:
import openerp.addons.web.common.http as openerpweb
except ImportError:
import web.common.http as openerpweb
import web.common.http as openerpweb # noqa
from openid import oidutil
from openid.store import memstore
#from openid.store import filestore
from openid.store import filestore
from openid.consumer import consumer
from openid.cryptutil import randomString
from openid.extensions import ax, sreg
from .. import utils
_logger = logging.getLogger(__name__)
oidutil.log = _logger.debug
_storedir = os.path.join(tempfile.gettempdir(), 'openerp-auth_openid-store')
class GoogleAppsAwareConsumer(consumer.GenericConsumer):
def complete(self, message, endpoint, return_to):
if message.getOpenIDNamespace() == consumer.OPENID2_NS:
server_url = message.getArg(consumer.OPENID2_NS, 'op_endpoint', consumer.no_default)
server_url = message.getArg(consumer.OPENID2_NS, 'op_endpoint', '')
if server_url.startswith('https://www.google.com/a/'):
# update fields
for attr in ['claimed_id', 'identity']:
value = message.getArg(consumer.OPENID2_NS, attr)
value = 'https://www.google.com/accounts/o8/user-xrds?uri=%s' % urllib.quote_plus(value)
message.setArg(consumer.OPENID2_NS, attr, value)
# now, resign the message
assoc_handle = message.getArg(consumer.OPENID_NS, 'assoc_handle')
assoc = self.store.getAssociation(server_url, assoc_handle)
message.delArg(consumer.OPENID2_NS, 'sig')
message.delArg(consumer.OPENID2_NS, 'signed')
message = assoc.signMessage(message)
if assoc:
# update fields
for attr in ['claimed_id', 'identity']:
value = message.getArg(consumer.OPENID2_NS, attr, '')
value = 'https://www.google.com/accounts/o8/user-xrds?uri=%s' % urllib.quote_plus(value)
message.setArg(consumer.OPENID2_NS, attr, value)
return super(GoogleAppsAwareConsumer, self).complete(message, endpoint, return_to)
# now, resign the message
message.delArg(consumer.OPENID2_NS, 'sig')
message.delArg(consumer.OPENID2_NS, 'signed')
message = assoc.signMessage(message)
return super(GoogleAppsAwareConsumer, self).complete(message, endpoint, return_to)
class OpenIDController(openerpweb.Controller):
_cp_path = '/auth_openid/login'
_store = memstore.MemoryStore() # TODO use a filestore
_store = filestore.FileOpenIDStore(_storedir)
_REQUIRED_ATTRIBUTES = ['email']
_OPTIONAL_ATTRIBUTES = 'nickname fullname postcode country language timezone'.split()
def _add_extensions(self, request):
"""Add extensions to the request"""
@ -118,8 +116,20 @@ class OpenIDController(openerpweb.Controller):
def _get_realm(self, req):
return req.httprequest.host_url
@openerpweb.httprequest
def verify_direct(self, req, db, url):
result = self._verify(req, db, url)
if 'error' in result:
return werkzeug.exceptions.BadRequest(result['error'])
if result['action'] == 'redirect':
return werkzeug.utils.redirect(result['value'])
return result['value']
@openerpweb.jsonrequest
def verify(self, req, db, url):
return self._verify(req, db, url)
def _verify(self, req, db, url):
redirect_to = werkzeug.urls.Href(req.httprequest.host_url + 'auth_openid/login/process')(session_id=req.session_id)
realm = self._get_realm(req)
@ -145,7 +155,6 @@ class OpenIDController(openerpweb.Controller):
form_html = request.htmlMarkup(realm, redirect_to)
return {'action': 'post', 'value': form_html, 'session_id': req.session_id}
@openerpweb.httprequest
def process(self, req, **kw):
session = getattr(req.session, 'openid_session', None)
@ -185,10 +194,8 @@ class OpenIDController(openerpweb.Controller):
domain += ['|', ('openid_email', '=', False)]
domain += [('openid_email', '=', openid_email)]
domain += [
('openid_url', '=', openid_url),
('active', '=', True),
]
domain += [('openid_url', '=', openid_url), ('active', '=', True)]
ids = Users.search(cr, 1, domain)
assert len(ids) < 2
if ids:
@ -199,12 +206,11 @@ class OpenIDController(openerpweb.Controller):
# TODO fill empty fields with the ones from sreg/ax
cr.commit()
u = req.session.login(dbname, login, key)
req.session.authenticate(dbname, login, key, {})
if not user_id:
session['message'] = 'This OpenID identifier is not associated to any active users'
elif info.status == consumer.SETUP_NEEDED:
session['message'] = info.setup_url
elif info.status == consumer.FAILURE and display_identifier:
@ -217,9 +223,8 @@ class OpenIDController(openerpweb.Controller):
# information in a log.
session['message'] = 'Verification failed.'
fragment = '#loginerror' if not user_id else ''
return werkzeug.utils.redirect('/'+fragment)
return werkzeug.utils.redirect('/' + fragment)
@openerpweb.jsonrequest
def status(self, req):

View File

@ -12,7 +12,7 @@
<header>
<button name="do_tentative" states="needs-action,declined,accepted" string="Uncertain" type="object" class="oe_highlight"/>
<button name="do_accept" string="Accept" states="needs-action,tentative,declined" type="object" class="oe_highlight"/>
<button name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d" string="Delegate" type="action" states="needs-action,tentative,declined,accepted" context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
<button name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d" string="Delegate" type="action" states="needs-action,tentative,declined,accepted" context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}"/>
<button name="do_decline" string="Decline" states="needs-action,tentative,accepted" type="object" class="oe_highlight"/>
<field name="state" widget="statusbar"
statusbar_visible="tentative,needs-action,accepted" statusbar_colors='{"proforma":"blue"}'/>
@ -20,36 +20,36 @@
<sheet>
<div class="oe_title">
<label for="email" string="Invitation To" class="oe_edit_only" />
<label for="email" string="Invitation To" class="oe_edit_only"/>
<h1>
<field name="email" class="oe_inline" />
(<field name="language" class="oe_inline" />)
<field name="email" class="oe_inline"/>
(<field name="language" class="oe_inline"/>)
</h1>
<h2>
From <field name="event_date" class="oe_inline" />
From <field name="event_date" class="oe_inline"/>
to <field name="event_end_date" class="oe_inline"/>
</h2>
</div>
<group>
<group>
<field name="sent_by_uid" string="Invitation From" />
<field name="sent_by_uid" string="Invitation From"/>
<field name="user_id" string="Invited User"/>
<field name="partner_id" string="Contact" />
<field name="partner_id" string="Contact"/>
</group>
<group>
<field name="cutype" string="Invitation Type" />
<field name="role" string="Role" />
<field name="rsvp" />
<field name="cutype" string="Invitation Type"/>
<field name="role" string="Role"/>
<field name="rsvp"/>
<field name="ref" readonly="1"/>
</group>
</group>
<group>
<group string="Delegated From">
<field name="parent_ids" readonly="1" nolabel="1" />
<field name="parent_ids" readonly="1" nolabel="1"/>
</group>
<group string="Delegated To" >
<field name="child_ids" readonly="1" nolabel="1" />
<field name="child_ids" readonly="1" nolabel="1"/>
</group>
</group>
</sheet>
@ -65,12 +65,12 @@
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Invitation details">
<field name="sent_by_uid" string="Invitation From" />
<field name="sent_by_uid" string="Invitation From"/>
<field name="role" string="My Role"/>
<field name="user_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
<field name="cutype" string="Invitation Type"/>
<field name="state" />
<field name="state"/>
<field name="rsvp" string="Required to Join"/>
</tree>
</field>
@ -86,20 +86,20 @@
<search string="Search Invitations">
<field name="email" string="Email"/>
<field name="event_date"/>
<filter icon="terp-gtk-jump-to-ltr" name="toreview" string="To Review" domain="[('state','=', 'needs-action')]" help="Invitations To Review" />
<filter icon="terp-check" string="Accepted" domain="[('state','=', 'accepted')]" help="Accepted Invitations" />
<filter icon="terp-dialog-close" string="Declined" domain="[('state','=', 'declined')]" help="Declined Invitations" />
<filter icon="gtk-sort-descending" string="Delegated" domain="[('state','=', 'delegated')]" help="Delegated Invitations" />
<filter icon="terp-gtk-jump-to-ltr" name="toreview" string="To Review" domain="[('state','=', 'needs-action')]" help="Invitations To Review"/>
<filter icon="terp-check" string="Accepted" domain="[('state','=', 'accepted')]" help="Accepted Invitations"/>
<filter icon="terp-dialog-close" string="Declined" domain="[('state','=', 'declined')]" help="Declined Invitations"/>
<filter icon="gtk-sort-descending" string="Delegated" domain="[('state','=', 'delegated')]" help="Delegated Invitations"/>
<field name="user_id" string="Responsible"/>
<field name="cutype" string="Invitation type"/>
<group expand="0" string="Group By...">
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
<filter string="Contact" icon="terp-personal" domain="[]" context="{'group_by':'partner_id'}" />
<filter string="Type" icon="terp-stock_symbol-selection" help="Invitation Type" domain="[]" context="{'group_by':'cutype'}" />
<filter string="Role" icon="terp-gtk-select-all" domain="[]" context="{'group_by':'role'}" />
<filter string="Required Reply" icon="terp-mail-replied" domain="[]" context="{'group_by':'rsvp'}" />
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Contact" icon="terp-personal" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Type" icon="terp-stock_symbol-selection" help="Invitation Type" domain="[]" context="{'group_by':'cutype'}"/>
<filter string="Role" icon="terp-gtk-select-all" domain="[]" context="{'group_by':'role'}"/>
<filter string="Required Reply" icon="terp-mail-replied" domain="[]" context="{'group_by':'rsvp'}"/>
<filter string="Status" icon="terp-stock_effects-object-colorize" help="Invitation Type"
domain="[]" context="{'group_by':'state'}" />
domain="[]" context="{'group_by':'state'}"/>
</group>
</search>
</field>
@ -110,7 +110,7 @@
<field name="res_model">calendar.attendee</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="base_calendar.base_calendar_attendee_tree_view" />
<field name="view_id" ref="base_calendar.base_calendar_attendee_tree_view"/>
<field name="context">{'default_sent_by_uid': uid}</field>
</record>
@ -122,7 +122,7 @@
<menuitem id="menu_attendee_invitations"
parent="base.menu_calendar_configuration"
sequence="10" action="action_view_attendee_form" />
sequence="10" action="action_view_attendee_form"/>
<!-- ALARM FORM VIEW-->
@ -133,13 +133,13 @@
<field name="arch" type="xml">
<form string="Reminder details" version="7.0">
<group col="4">
<field name="name" />
<field name="active" />
<separator string="Reminder Details" colspan="4" />
<field name="trigger_duration" />
<field name="trigger_interval" />
<field name="trigger_occurs" />
<field name="trigger_related" />
<field name="name"/>
<field name="active"/>
<separator string="Reminder Details" colspan="4"/>
<field name="trigger_duration"/>
<field name="trigger_interval"/>
<field name="trigger_occurs"/>
<field name="trigger_related"/>
</group>
</form>
</field>
@ -169,7 +169,7 @@
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to setup a new alarm type.
Click to setup a new alarm type.
</p><p>
You can define a customized type of calendar alarm that may be
assigned to calendar events or meetings.
@ -195,25 +195,25 @@
<header>
<button name="do_confirm" string="Confirm" states="tentative,cancelled" type="object" class="oe_highlight"/>
<button name="do_tentative" states="confirmed,cancelled" string="Uncertain" type="object" class="oe_highlight"/>
<button name="do_cancel" string="Cancel" states="tentative,confirmed" type="object" />
<button name="do_cancel" string="Cancel" states="tentative,confirmed" type="object"/>
<field name="state" widget="statusbar"
statusbar_visible="tentative,confirmed" statusbar_colors='{"proforma":"blue"}'/>
</header>
<sheet>
<group col="6">
<field name="name" string="Summary"
colspan="4" required="1" />
<field name="allday" colspan="2" on_change="onchange_dates(date,False,False,allday)" />
colspan="4" required="1"/>
<field name="allday" colspan="2" on_change="onchange_dates(date,False,False,allday)"/>
<newline/>
<field name="date" string="Start Date" required="1"
on_change="onchange_dates(date,duration,False,allday)" />
on_change="onchange_dates(date,duration,False,allday)"/>
<field name="duration" widget="float_time"
on_change="onchange_dates(date,duration,False,allday)" attrs="{'invisible': [('allday', '=', True)]}"/>
<field name="date_deadline" string="End Date" required="1"
on_change="onchange_dates(date,False,date_deadline)" />
<field name="location" />
on_change="onchange_dates(date,False,date_deadline)"/>
<field name="location"/>
<field name="alarm_id" string="Reminder"
widget="selection" />
widget="selection"/>
<group colspan="2" col="4" attrs="{'readonly': [('state','=','done')]}">
<field name="recurrency"/>
</group>
@ -222,11 +222,11 @@
<page string="Event">
<group col="6" colspan="4">
<separator colspan="6" string="Visibility"/>
<field name="user_id" string="Responsible User" />
<field name="user_id" string="Responsible User"/>
<field name="show_as" string="Show Time as"/>
<field name="class" string="Privacy"/>
<field name="recurrent_id" invisible="1" />
<field name="recurrent_uid" invisible="1" />
<field name="recurrent_id" invisible="1"/>
<field name="recurrent_uid" invisible="1"/>
</group>
<separator string="Description"/>
<field name="description"/>
@ -241,31 +241,31 @@
<tree string="Invitation details" editable="top">
<field name="sent_by_uid" string="From"/>
<field name="user_id" string="To"/>
<field name="email" />
<field name="role" width="200" />
<field name="state" />
<field name="email"/>
<field name="role" width="200"/>
<field name="state"/>
<button name="do_tentative"
states="needs-action,declined,accepted"
string="Uncertain" type="object"
icon="terp-crm" />
icon="terp-crm"/>
<button name="do_accept" string="Accept"
states="needs-action,tentative,declined"
type="object" icon="gtk-apply" />
type="object" icon="gtk-apply"/>
<button name="do_decline" string="Decline"
states="needs-action,tentative,accepted"
type="object" icon="gtk-cancel" />
type="object" icon="gtk-cancel"/>
<button
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
string="Delegate" type="action"
icon="gtk-sort-descending"
states="needs-action,tentative,declined,accepted"
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}"/>
</tree>
<form string="Invitation details" version="7.0">
<notebook colspan="4">
<page string="Details">
<group col="4">
<field name="email" />
<field name="email"/>
<field name="rsvp"/>
<field name="cutype"/>
<field name="role"/>
@ -276,24 +276,24 @@
states="needs-action,declined,accepted"
string="Uncertain"
type="object"
icon="terp-crm" />
icon="terp-crm"/>
<button name="do_accept"
string="Accept"
states="needs-action,tentative,declined"
type="object"
icon="gtk-apply" />
icon="gtk-apply"/>
<button name="do_decline"
string="Decline"
states="needs-action,tentative,accepted"
type="object"
icon="gtk-cancel" />
icon="gtk-cancel"/>
<button
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
string="Delegate"
type="action"
icon="gtk-sort-descending"
states="needs-action,tentative,declined,accepted"
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}"/>
</group>
</page>
</notebook>
@ -304,49 +304,49 @@
<group col="4" colspan="4" name="rrule">
<group col="4" colspan="4">
<field name="rrule_type" string="Recurrency period"
attrs="{'readonly':[('recurrent_uid','!=',False)]}" />
<field name="interval" />
attrs="{'readonly':[('recurrent_uid','!=',False)]}"/>
<field name="interval"/>
<separator string="End of Recurrence" colspan="4"/>
<field name="end_type" />
<label string=" " colspan="2" />
<newline />
<field name="end_type"/>
<label string=" " colspan="2"/>
<newline/>
<field name="count" attrs="{'invisible' : [('end_type', '!=', 'count')] }"/>
<label string=" " colspan="2" />
<newline />
<label string=" " colspan="2"/>
<newline/>
<field name="end_date" attrs="{'invisible' : [('end_type', '!=', 'end_date')] }"/>
<newline />
<newline/>
</group>
<group col="8" colspan="4" name="Select weekdays" attrs="{'invisible' :[('rrule_type','not in', ['weekly'])]}">
<separator string="Choose day where repeat the meeting" colspan="8"/>
<field name="mo" colspan="1" />
<field name="tu" colspan="1" />
<field name="we" colspan="1" />
<field name="th" colspan="1" />
<field name="mo" colspan="1"/>
<field name="tu" colspan="1"/>
<field name="we" colspan="1"/>
<field name="th" colspan="1"/>
<newline/>
<field name="fr" colspan="1"/>
<field name="sa" colspan="1" />
<field name="su" colspan="1" />
<newline/>
<field name="fr" colspan="1" />
<field name="sa" colspan="1" />
<field name="su" colspan="1" />
<newline />
</group>
<group col="10" colspan="4"
attrs="{'invisible' : [('rrule_type','!=','monthly')]}">
<separator string="Choose day in the month where repeat the meeting" colspan="12"/>
<group col="2" colspan="1">
<field name="select1" />
<field name="select1"/>
</group>
<group col="2" colspan="1">
<field name="day"
attrs="{'required' : [('select1','=','date'), ('rrule_type','=','monthly')],
'invisible' : ['|', ('select1','=','day'), ('rrule_type','!=','monthly')]}" />
'invisible' : ['|', ('select1','=','day'), ('rrule_type','!=','monthly')]}"/>
</group>
<group col="3" colspan="1"
attrs="{'invisible' : ['|', ('select1','=','date'), ('rrule_type','!=','monthly')]}">
<field name="byday" string="The"
attrs="{'required' : [('select1','=','day'), ('rrule_type','=','monthly')]}" />
attrs="{'required' : [('select1','=','day'), ('rrule_type','=','monthly')]}"/>
<field name="week_list" nolabel="1"
attrs="{'required' : [('select1','=','day'), ('rrule_type','=','monthly')]}" />
attrs="{'required' : [('select1','=','day'), ('rrule_type','=','monthly')]}"/>
</group>
</group>
</group>
@ -366,11 +366,11 @@
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Events">
<field name="name" string="Subject" />
<field name="date" string="Event Date" />
<field name="location" />
<field name="show_as" />
<field name="class" string="Privacy" />
<field name="name" string="Subject"/>
<field name="date" string="Event Date"/>
<field name="location"/>
<field name="show_as"/>
<field name="class" string="Privacy"/>
<field name="user_id" invisible="1"/>
<field name="state" invisible="1"/>
</tree>
@ -404,16 +404,16 @@
<field name="name" filter_domain="['|',('name','ilike',self),('location','ilike',self)]" string="Event"/>
<field name="show_as"/>
<field name="class" string="Privacy"/>
<filter icon="terp-go-today" string="My Events" domain="[('user_id','=',uid)]" help="My Events" />
<filter icon="terp-go-today" string="My Events" domain="[('user_id','=',uid)]" help="My Events"/>
<separator/>
<filter icon="terp-check" string="Confirmed" domain="[('state','=','confirmed')]" help="Confirmed Events" />
<filter icon="terp-check" string="Confirmed" domain="[('state','=','confirmed')]" help="Confirmed Events"/>
<field name="user_id"/>
<group expand="0" string="Group By...">
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
<filter string="Availability" icon="terp-camera_test" domain="[]" context="{'group_by':'show_as'}" />
<filter string="Privacy" icon="terp-locked" domain="[]" context="{'group_by':'class'}" />
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}" />
<filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'date'}" />
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Availability" icon="terp-camera_test" domain="[]" context="{'group_by':'show_as'}"/>
<filter string="Privacy" icon="terp-locked" domain="[]" context="{'group_by':'class'}"/>
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'date'}"/>
</group>
</search>
</field>
@ -435,7 +435,7 @@
<menuitem id="menu_events"
name="Events" parent="base.menu_calendar_configuration"
sequence="15" action="action_view_event" />
sequence="15" action="action_view_event"/>
</data>
</openerp>

View File

@ -91,7 +91,7 @@
<page string="Meeting Detail">
<group>
<group>
<field name="user_id" />
<field name="user_id"/>
<field name="categ_ids" widget="many2many_tags"/>
<field name="location"/>
<field name="organizer" groups="base.group_no_one"/>

View File

@ -53,6 +53,8 @@ class sale_config_settings(osv.osv_memory):
_name = 'sale.config.settings'
_inherit = 'res.config.settings'
_columns = {
'module_web_linkedin': fields.boolean('get contacts automatically from LinkedIn',
help="""When you create a new contact (person or company), you will be able to load all the data from LinkedIn (photos, address, etc)."""),
'module_crm': fields.boolean('CRM'),
'module_plugin_thunderbird': fields.boolean('enable Thunderbird plugin',
help="""The plugin allows you archive email and its attachments to the selected

View File

@ -71,6 +71,18 @@
or
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
</header>
<div name="linkedin">
<separator string="Social Network Integration"/>
<group name="LinkedIn">
<label for="id" string="Contacts"/>
<div name="LinkedIn">
<div name="module_web_linkedin" class="oe_inline">
<field name="module_web_linkedin"/>
<label for="module_web_linkedin"/>
</div>
</div>
</group>
</div>
<div name="customer feature">
<separator string="Quotations and Sales Orders"/>
<group name="Customer">

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -15,11 +16,11 @@
# 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/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import board
import wizard
import controllers
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -3,6 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -35,15 +36,19 @@ The user can also publish notes.
'depends': ['base'],
'update_xml': [
'security/ir.model.access.csv',
'wizard/board_menu_create_view.xml',
'board_view.xml',
'board_data_admin.xml',
'board_data_home.xml',
'board_mydashboard_view.xml'
],
'demo_xml': [
'board_demo.xml'
"js": [
'static/src/js/dashboard.js',
],
"css": [
'static/src/css/dashboard.css',
],
'qweb': [
"static/src/xml/*.xml",
],
'installable': True,
'auto_install': False,
'certificate': '0076912305725',

View File

@ -3,6 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -19,75 +20,58 @@
#
##############################################################################
from operator import itemgetter
from textwrap import dedent
from osv import fields, osv
import time
import tools
class board_board(osv.osv):
"""
Board
"""
_name = 'board.board'
_description = "Board"
_auto = False
_columns = {}
def create_view(self, cr, uid, ids, context=None):
"""
Create view
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of Board's IDs
@return: arch of xml view.
"""
arch = """<?xml version="1.0"?>
<form string="My Board" version="7.0">
<board style="1-1">
<column/>
<column/>
</board>
</form>"""
return arch
@tools.cache()
def list(self, cr, uid, context=None):
Actions = self.pool.get('ir.actions.act_window')
Menus = self.pool.get('ir.ui.menu')
IrValues = self.pool.get('ir.values')
act_ids = Actions.search(cr, uid, [('res_model', '=', self._name)], context=context)
refs = ['%s,%s' % (Actions._name, act_id) for act_id in act_ids]
# cannot search "action" field on menu (non stored function field without search_fnct)
irv_ids = IrValues.search(cr, uid, [
('model', '=', 'ir.ui.menu'),
('key', '=', 'action'),
('key2', '=', 'tree_but_open'),
('value', 'in', refs),
], context=context)
menu_ids = map(itemgetter('res_id'), IrValues.read(cr, uid, irv_ids, ['res_id'], context=context))
menu_names = Menus.name_get(cr, uid, menu_ids, context=context)
return [dict(id=m[0], name=m[1]) for m in menu_names]
def _clear_list_cache(self):
self.list.clear_cache(self)
def create(self, cr, user, vals, context=None):
"""
create new record.
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: dictionary of values for every field.
dictionary must use this form: {name_of_the_field: value, ...}
@return: id of new created record of board.board.
"""
return 0
if not 'name' in vals:
return False
id = super(board_board, self).create(cr, user, vals, context=context)
view_id = self.pool.get('ir.ui.view').create(cr, user, {
'name': vals['name'],
'model': 'board.board',
'priority': 16,
'type': 'form',
'arch': self.create_view(cr, user, id, context=context),
})
super(board_board, self).write(cr, user, [id], {'view_id': view_id}, context)
return id
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None,\
toolbar=False, submenu=False):
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
"""
Overrides orm field_view_get.
@return: Dictionary of Fields, arch and toolbar.
"""
res = {}
res = super(board_board, self).fields_view_get(cr, user, view_id, view_type,\
context, toolbar=toolbar, submenu=submenu)
res = super(board_board, self).fields_view_get(cr, user, view_id, view_type,
context, toolbar=toolbar, submenu=submenu)
vids = self.pool.get('ir.ui.view.custom').search(cr, user,\
[('user_id', '=', user), ('ref_id' ,'=', view_id)])
CustView = self.pool.get('ir.ui.view.custom')
vids = CustView.search(cr, user, [('user_id', '=', user), ('ref_id', '=', view_id)], context=context)
if vids:
view_id = vids[0]
arch = self.pool.get('ir.ui.view.custom').browse(cr, user, view_id, context=context)
arch = CustView.browse(cr, user, view_id, context=context)
res['custom_view_id'] = view_id
res['arch'] = arch.arch
res['arch'] = self._arch_preprocessing(cr, user, res['arch'], context=context)
@ -98,10 +82,10 @@ class board_board(osv.osv):
from lxml import etree
def remove_unauthorized_children(node):
for child in node.iterchildren():
if child.tag=='action' and child.get('invisible'):
if child.tag == 'action' and child.get('invisible'):
node.remove(child)
else:
child=remove_unauthorized_children(child)
child = remove_unauthorized_children(child)
return node
def encode(s):
@ -110,16 +94,84 @@ class board_board(osv.osv):
return s
archnode = etree.fromstring(encode(arch))
return etree.tostring(remove_unauthorized_children(archnode),pretty_print=True)
return etree.tostring(remove_unauthorized_children(archnode), pretty_print=True)
class board_create(osv.osv_memory):
def board_create(self, cr, uid, ids, context=None):
assert len(ids) == 1
this = self.browse(cr, uid, ids[0], context=context)
view_arch = dedent("""<?xml version="1.0"?>
<form string="%s" version="7.0">
<board style="2-1">
<column/>
<column/>
</board>
</form>
""".strip() % (this.name,))
view_id = self.pool.get('ir.ui.view').create(cr, uid, {
'name': this.name,
'model': 'board.board',
'priority': 16,
'type': 'form',
'arch': view_arch,
}, context=context)
action_id = self.pool.get('ir.actions.act_window').create(cr, uid, {
'name': this.name,
'view_type': 'form',
'view_mode': 'form',
'res_model': 'board.board',
'usage': 'menu',
'view_id': view_id,
'help': dedent('''<div class="oe_empty_custom_dashboard">
<p>
<b>This dashboard is empty.</b>
</p><p>
To add the first report into this dashboard, go to any
menu, switch to list or graph view, and click <i>'Add to
Dashboard'</i> in the extended search options.
</p><p>
You can filter and group data before inserting into the
dashboard using the search options.
</p>
</div>
''')
}, context=context)
menu_id = self.pool.get('ir.ui.menu').create(cr, uid, {
'name': this.name,
'parent_id': this.menu_parent_id.id,
'action': 'ir.actions.act_window,%s' % (action_id,)
}, context=context)
self.pool.get('board.board')._clear_list_cache()
return {
'type': 'ir.actions.client',
'tag': 'reload',
'params': {
'menu_id': menu_id
},
}
def _default_menu_parent_id(self, cr, uid, context=None):
_, menu_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'menu_reporting_dashboard')
return menu_id
_name = "board.create"
_description = "Board Creation"
_columns = {
'name': fields.char('Dashboard', size=64, required=True),
'view_id': fields.many2one('ir.ui.view', 'Board View'),
'name': fields.char('Board Name', size=64, required=True),
'menu_parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
}
# the following lines added to let the button on dashboard work.
_defaults = {
'name':lambda *args: 'Dashboard'
'menu_parent_id': _default_menu_parent_id,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
</data>
</openerp>

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- neat client actions that can be used in dashboards to display res_widgets -->
<record id="action_application_tiles" model="ir.actions.client">
<field name="name">Applications Tiles</field>
<field name="tag">board.home.applications</field>
</record>
<record id="action_res_widgets_tweets" model="ir.actions.client">
<field name="name">Tweets Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.openerp_favorites_twitter_widget')}"/>
</record>
<record id="action_res_widgets_events" model="ir.actions.client">
<field name="name">Events Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.events_widget')}"/>
</record>
<record id="action_res_widgets_facebook" model="ir.actions.client">
<field name="name">Facebook Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.facebook_widget')}"/>
</record>
<record id="action_res_widgets_note" model="ir.actions.client">
<field name="name">Note Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.note_widget')}"/>
</record>
<record id="action_res_widgets_map" model="ir.actions.client">
<field name="name">Google Maps Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.google_maps_widget')}"/>
</record>
<record id="action_res_widgets_currency_converter" model="ir.actions.client">
<field name="name">Currency Converter Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.currency_converter_widget')}"/>
</record>
</data>
</openerp>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
</data>
</openerp>

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<openerp>
<data>
<data noupdate="1">
<!--My Dashboard-->
<record model="ir.ui.view" id="board_my_dash_view">
<field name="name">My Dashboard</field>

View File

@ -1,64 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Board Search View -->
<record id="view_board_search" model="ir.ui.view">
<field name="name">board.board.search</field>
<field name="model">board.board</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Dashboard">
<field name="name" string="Dashboard"/>
</search>
</field>
</record>
<!-- Board Tree View -->
<record id="view_board_tree" model="ir.ui.view">
<field name="name">board.board.tree</field>
<field name="model">board.board</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Dashboard">
<field name="name"/>
</tree>
</field>
</record>
<!-- Board Form View -->
<record id="view_board_form" model="ir.ui.view">
<field name="name">board.board.form</field>
<field name="model">board.board</field>
<record id="view_board_create" model="ir.ui.view">
<field name="name">board.create.form</field>
<field name="model">board.create</field>
<field name="type">form</field>
<field eval="1" name="priority"/>
<field name="arch" type="xml">
<form string="Dashboard" version="7.0">
<header>
<button name="%(action_board_menu_create)d" string="Create Menu" type="action" class="oe_highlight"/>
</header>
<sheet>
<group>
<field name="name"/>
<field name="view_id" invisible="1"/>
</group>
</sheet>
</form>
<form string="Create New Dashboard" version="7.0">
<group colspan="4">
<field name="name"/>
<field name="menu_parent_id"/>
</group>
<footer>
<button string="Create" name="board_create" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action for DashBoard Definition form -->
<record id="action_view_board_list_form" model="ir.actions.act_window">
<field name="name">Dashboard Definition</field>
<field name="res_model">board.board</field>
<record id="action_board_create" model="ir.actions.act_window">
<field name="name">Create Board</field>
<field name="res_model">board.create</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_board_search"/>
<field name="view_mode">form</field>
<field name="view_id" ref="view_board_create"/>
<field name="target">new</field>
</record>
<menuitem action="action_view_board_list_form"
id="menu_view_board_form" parent="base.menu_reporting_config"
<menuitem action="action_board_create"
id="menu_board_create" parent="base.menu_reporting_config"
groups="base.group_no_one"
sequence="2"/>
</data>
</openerp>

View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
from xml.etree import ElementTree
try:
import openerp.addons.web.common.http as openerpweb
from openerp.addons.web.common import nonliterals
from openerp.addons.web.controllers.main import load_actions_from_ir_values
except ImportError:
import web.common.http as openerpweb # noqa
from web.common import nonliterals # noqa
from web.controllers.main import load_actions_from_ir_values # noqa
class Board(openerpweb.Controller):
_cp_path = '/board'
@openerpweb.jsonrequest
def add_to_dashboard(self, req, menu_id, action_id, context_to_save, domain, view_mode, name=''):
# FIXME move this method to board.board model
to_eval = nonliterals.CompoundContext(context_to_save)
to_eval.session = req.session
ctx = dict((k, v) for k, v in to_eval.evaluate().iteritems()
if not k.startswith('search_default_'))
ctx['dashboard_merge_domains_contexts'] = False # TODO: replace this 6.1 workaround by attribute on <action/>
domain = nonliterals.CompoundDomain(domain)
domain.session = req.session
domain = domain.evaluate()
dashboard_action = load_actions_from_ir_values(req, 'action', 'tree_but_open', [('ir.ui.menu', menu_id)], False)
if dashboard_action:
action = dashboard_action[0][2]
if action['res_model'] == 'board.board' and action['views'][0][1] == 'form':
# Maybe should check the content instead of model board.board ?
view_id = action['views'][0][0]
board = req.session.model(action['res_model']).fields_view_get(view_id, 'form')
if board and 'arch' in board:
xml = ElementTree.fromstring(board['arch'])
column = xml.find('./board/column')
if column is not None:
new_action = ElementTree.Element('action', {
'name': str(action_id),
'string': name,
'view_mode': view_mode,
'context': str(ctx),
'domain': str(domain)
})
column.insert(0, new_action)
arch = ElementTree.tostring(xml, 'utf-8')
return req.session.model('ir.ui.view.custom').create({
'user_id': req.session._uid,
'ref_id': view_id,
'arch': arch
}, req.session.eval_context(req.context))
return False

View File

@ -1,3 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_board_board all,board.board,model_board_board,,1,0,0,0
access_board_board system,board.board system,model_board_board,base.group_system,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_board_board all board.board model_board_board 1 0 0 0
access_board_board system board.board system model_board_board base.group_system 1 1 1 1

View File

@ -0,0 +1,73 @@
.openerp .oe_dashboard_links {
text-align: right;
margin: 0 4px 6px 0;
}
.openerp .oe_dashboard {
width: 100%;
}
.openerp .oe_dashboard .oe_action {
margin: 0 8px 8px 0;
background-color: white;
border: 1px solid;
border-color: #e5e5e5 #dbdbdb #d2d2d2;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}
.openerp .oe_dashboard .oe_action .oe_header {
font-size: 16px;
vertical-align: middle;
margin: 0;
padding: 12px;
-moz-border-radius: 3px 3px 0 0;
-webkit-border-radius: 3px 3px 0 0;
border-radius: 3px 3px 0 0;
}
.openerp .oe_dashboard .oe_action .oe_header:hover {
cursor: move;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_icon {
float: right;
cursor: pointer;
color: #b3b3b3;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_icon:hover {
color: #666666;
text-decoration: none;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_close:after {
content: "×";
margin-left: 4px;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_minimize:after {
content: "-";
margin-left: 4px;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_maximize:after {
content: "+";
margin-left: 4px;
}
.openerp .oe_dashboard .oe_action .oe_header_empty {
padding-top: 0;
padding-bottom: 2px;
}
.openerp .oe_dashboard .oe_action .oe_button_create {
margin-left: 4px;
padding: 0 4px 0 4px;
height: 16px !important;
}
.openerp .oe_dashboard .oe_action .oe_content {
padding: 0 12px 12px 12px;
}
.openerp .oe_dashboard .oe_action .oe_content .oe_view_manager_header {
display: none;
}
.openerp .oe_dashboard .oe_action .oe_content .oe_list_content > thead {
border-bottom: 1px;
}
.openerp .oe_dashboard .oe_action .oe_content .oe_list_content > tbody tr:nth-child(odd) {
background: transparent;
}

View File

@ -0,0 +1,83 @@
@mixin radius($radius: 5px)
-moz-border-radius: $radius
-webkit-border-radius: $radius
border-radius: $radius
@mixin box-shadow($bsval: 0px 1px 4px #777)
-moz-box-shadow: $bsval
-webkit-box-shadow: $bsval
box-shadow: $bsval
.openerp
.oe_dashboard_links
text-align: right
margin: 0 4px 6px 0
.oe_dashboard
width: 100%
.oe_action
margin: 0 8px 8px 0
background-color: white
border: 1px solid
border-color: #e5e5e5 #dbdbdb #d2d2d2
@include radius(3px)
@include box-shadow(0 0 2px rgba(0,0,0,0.2))
.oe_header
font-size: 16px
vertical-align: middle
margin: 0
padding: 12px
@include radius(3px 3px 0 0)
//border-bottom: 1px dotted #dbdbdb
//@include radius(2px 2px 0 0)
//@include vertical-gradient(#FCFCFC, #DEDEDE)
&:hover
cursor: move
.oe_icon
float: right
cursor: pointer
color: #b3b3b3
&:hover
color: #666
text-decoration: none
.oe_close:after
content: "×"
margin-left: 4px
.oe_minimize:after
content: "-"
margin-left: 4px
.oe_maximize:after
content: "+"
margin-left: 4px
.oe_header_empty
padding-top: 0
padding-bottom: 2px
.oe_button_create
margin-left: 4px
padding: 0 4px 0 4px
height: 16px !important
//.oe_rename
//float: left
//padding-right: 4px
//position: relative
//top: 1px
//.oe_input
//height: 16px;
//position: relative;
//top: 2px;
//.ui-sortable-placeholder
//border: 1px dotted black;
//visibility: visible !important;
//height: 50px !important;
//*
//visibility: hidden;
.oe_content
padding: 0 12px 12px 12px
.oe_view_manager_header
display: none
.oe_list_content
> thead
border-bottom: 1px
> tbody
tr:nth-child(odd)
background: transparent

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,378 @@
openerp.board = function(instance) {
var QWeb = instance.web.qweb,
_t = instance.web._t;
if (!instance.board) {
/** @namespace */
instance.board = {};
}
instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
init: function(view, node) {
this._super(view, node);
this.form_template = 'DashBoard';
this.actions_attrs = {};
this.action_managers = [];
},
start: function() {
var self = this;
this._super.apply(this, arguments);
this.$element.find('.oe_dashboard_column').sortable({
connectWith: '.oe_dashboard_column',
handle: '.oe_header',
scroll: false
}).disableSelection().bind('sortstop', self.do_save_dashboard);
// Events
this.$element.find('.oe_dashboard_link_reset').click(this.on_reset);
this.$element.find('.oe_dashboard_link_change_layout').click(this.on_change_layout);
this.$element.delegate('.oe_dashboard_column .oe_fold', 'click', this.on_fold_action);
this.$element.delegate('.oe_dashboard_column .oe_close', 'click', this.on_close_action);
// Init actions
_.each(this.node.children, function(column, column_index) {
_.each(column.children, function(action, action_index) {
delete(action.attrs.width);
delete(action.attrs.height);
delete(action.attrs.colspan);
var action_id = _.str.toNumber(action.attrs.name);
if (!_.isNaN(action_id)) {
self.rpc('/web/action/load', {action_id: action_id}, function(result) {
self.on_load_action(result, column_index + '_' + action_index, action.attrs);
});
}
});
});
},
on_reset: function() {
this.rpc('/web/view/undo_custom', {
view_id: this.view.fields_view.view_id,
reset: true
}, this.do_reload);
},
on_change_layout: function() {
var self = this;
var qdict = {
current_layout : this.$element.find('.oe_dashboard').attr('data-layout')
};
var $dialog = instance.web.dialog($('<div>'), {
modal: true,
title: _t("Edit Layout"),
width: 'auto',
height: 'auto'
}).html(QWeb.render('DashBoard.layouts', qdict));
$dialog.find('li').click(function() {
var layout = $(this).attr('data-layout');
$dialog.dialog('destroy');
self.do_change_layout(layout);
});
},
do_change_layout: function(new_layout) {
var $dashboard = this.$element.find('.oe_dashboard');
var current_layout = $dashboard.attr('data-layout');
if (current_layout != new_layout) {
var clayout = current_layout.split('-').length,
nlayout = new_layout.split('-').length,
column_diff = clayout - nlayout;
if (column_diff > 0) {
var $last_column = $();
$dashboard.find('.oe_dashboard_column').each(function(k, v) {
if (k >= nlayout) {
$(v).find('.oe_action').appendTo($last_column);
} else {
$last_column = $(v);
}
});
}
$dashboard.toggleClass('oe_dashboard_layout_' + current_layout + ' oe_dashboard_layout_' + new_layout);
$dashboard.attr('data-layout', new_layout);
this.do_save_dashboard();
}
},
on_fold_action: function(e) {
var $e = $(e.currentTarget),
$action = $e.parents('.oe_action:first'),
id = parseInt($action.attr('data-id'), 10);
if ($e.is('.oe_minimize')) {
$action.data('action_attrs').fold = '1';
} else {
delete($action.data('action_attrs').fold);
}
$e.toggleClass('oe_minimize oe_maximize');
$action.find('.oe_content').toggle();
this.do_save_dashboard();
},
on_close_action: function(e) {
if (confirm(_t("Are you sure you want to remove this item ?"))) {
$(e.currentTarget).parents('.oe_action:first').remove();
this.do_save_dashboard();
}
},
do_save_dashboard: function() {
var self = this;
var board = {
form_title : this.view.fields_view.arch.attrs.string,
style : this.$element.find('.oe_dashboard').attr('data-layout'),
columns : []
};
this.$element.find('.oe_dashboard_column').each(function() {
var actions = [];
$(this).find('.oe_action').each(function() {
var action_id = $(this).attr('data-id'),
new_attrs = _.clone($(this).data('action_attrs'));
if (new_attrs.domain) {
new_attrs.domain = new_attrs.domain_string;
delete(new_attrs.domain_string);
}
if (new_attrs.context) {
new_attrs.context = new_attrs.context_string;
delete(new_attrs.context_string);
}
actions.push(new_attrs);
});
board.columns.push(actions);
});
var arch = QWeb.render('DashBoard.xml', board);
this.rpc('/web/view/add_custom', {
view_id: this.view.fields_view.view_id,
arch: arch
}, function() {
self.$element.find('.oe_dashboard_link_reset').show();
});
},
on_load_action: function(result, index, action_attrs) {
var self = this,
action = result.result,
view_mode = action_attrs.view_mode;
if (action_attrs.context && action_attrs.context['dashboard_merge_domains_contexts'] === false) {
// TODO: replace this 6.1 workaround by attribute on <action/>
action.context = action_attrs.context || {};
action.domain = action_attrs.domain || [];
} else {
if (action_attrs.context) {
action.context = _.extend((action.context || {}), action_attrs.context);
}
if (action_attrs.domain) {
action.domain = action.domain || [];
action.domain.unshift.apply(action.domain, action_attrs.domain);
}
}
var action_orig = _.extend({ flags : {} }, action);
if (view_mode && view_mode != action.view_mode) {
action.views = _.map(view_mode.split(','), function(mode) {
mode = mode === 'tree' ? 'list' : mode;
return _(action.views).find(function(view) { return view[1] == mode; })
|| [false, mode];
});
}
action.flags = {
search_view : false,
sidebar : false,
views_switcher : false,
action_buttons : false,
pager: false,
low_profile: true,
display_title: false,
list: {
selectable: false
}
};
var am = new instance.web.ActionManager(this),
// FIXME: ideally the dashboard view shall be refactored like kanban.
$action = $('#' + this.view.element_id + '_action_' + index);
$action.parent().data('action_attrs', action_attrs);
this.action_managers.push(am);
am.appendTo($action);
am.do_action(action);
am.do_action = function (action) {
self.do_action(action);
};
if (action_attrs.creatable && action_attrs.creatable !== 'false') {
var action_id = parseInt(action_attrs.creatable, 10);
$action.parent().find('button.oe_dashboard_button_create').click(function() {
if (isNaN(action_id)) {
action_orig.flags.default_view = 'form';
self.do_action(action_orig);
} else {
self.rpc('/web/action/load', {
action_id: action_id
}, function(result) {
result.result.flags = result.result.flags || {};
result.result.flags.default_view = 'form';
self.do_action(result.result);
});
}
});
}
if (am.inner_widget) {
am.inner_widget.on_mode_switch.add(function(mode) {
var new_views = [];
_.each(action_orig.views, function(view) {
new_views[view[1] === mode ? 'unshift' : 'push'](view);
});
if (!new_views.length || new_views[0][1] !== mode) {
new_views.unshift([false, mode]);
}
action_orig.views = new_views;
action_orig.res_id = am.inner_widget.dataset.ids[am.inner_widget.dataset.index];
self.do_action(action_orig);
});
}
},
renderElement: function() {
this._super();
var check = _.detect(this.node.children, function(column, column_index) {
return _.detect(column.children,function(element){
return element.tag === "action"? element: false;
});
});
if (!check) {
return this.no_result();
}
// We should start with three columns available
for (var i = this.node.children.length; i < 3; i++) {
this.node.children.push({
tag: 'column',
attrs: {},
children: []
});
}
var rendered = QWeb.render(this.form_template, this);
this.$element.html(rendered);
},
no_result: function() {
if (this.view.options.action.help) {
this.$element.append(
$('<div class="oe_view_nocontent">')
.append($('<div>').html(this.view.options.action.help || " "))
);
}
},
do_reload: function() {
var view_manager = this.view.getParent(),
action_manager = view_manager.getParent();
this.view.destroy();
action_manager.do_action(view_manager.action);
}
});
instance.web.form.DashBoardLegacy = instance.web.form.DashBoard.extend({
renderElement: function() {
if (this.node.tag == 'hpaned') {
this.node.attrs.style = '2-1';
} else if (this.node.tag == 'vpaned') {
this.node.attrs.style = '1';
}
this.node.tag = 'board';
_.each(this.node.children, function(child) {
if (child.tag.indexOf('child') == 0) {
child.tag = 'column';
var actions = [], first_child = child.children[0];
if (first_child && first_child.tag == 'vpaned') {
_.each(first_child.children, function(subchild) {
actions.push.apply(actions, subchild.children);
});
child.children = actions;
}
}
});
this._super(this);
}
});
instance.web.form.tags.add('hpaned', 'instance.web.form.DashBoardLegacy');
instance.web.form.tags.add('vpaned', 'instance.web.form.DashBoardLegacy');
instance.web.form.tags.add('board', 'instance.web.form.DashBoard');
instance.board.AddToDashboard = instance.web.search.Input.extend({
template: 'SearchView.addtodashboard',
_in_drawer: true,
start: function () {
var self = this;
this.$element
.on('click', 'h4', this.proxy('show_option'))
.on('submit', 'form', function (e) {
e.preventDefault();
self.add_dashboard();
});
return this.load_data().then(this.proxy("render_data"));
},
load_data:function(){
var board = new instance.web.Model('board.board');
return board.call('list');
},
_x:function() {
if (!instance.webclient) { return $.Deferred().reject(); }
var dashboard_menu = instance.webclient.menu.data.data.children;
return new instance.web.Model('ir.model.data')
.query(['res_id'])
.filter([['name','=','menu_reporting_dashboard']])
.first().pipe(function (result) {
var menu = _(dashboard_menu).chain()
.pluck('children')
.flatten(true)
.find(function (child) { return child.id === result.res_id; })
.value();
return menu ? menu.children : [];
});
},
render_data: function(dashboard_choices){
var selection = instance.web.qweb.render(
"SearchView.addtodashboard.selection", {
selections: dashboard_choices});
this.$("input").before(selection)
},
add_dashboard: function(){
var self = this;
var getParent = this.getParent();
var view_parent = this.getParent().getParent();
if (! view_parent.action || ! this.$element.find("select").val()) {
this.do_warn("Can't find dashboard action");
return;
}
var data = getParent.build_search_data();
var context = new instance.web.CompoundContext(getParent.dataset.get_context() || []);
var domain = new instance.web.CompoundDomain(getParent.dataset.get_domain() || []);
_.each(data.contexts, context.add, context);
_.each(data.domains, domain.add, domain);
this.rpc('/board/add_to_dashboard', {
menu_id: this.$element.find("select").val(),
action_id: view_parent.action.id,
context_to_save: context,
domain: domain,
view_mode: view_parent.active_view,
name: this.$element.find("input").val()
}, function(r) {
if (r === false) {
self.do_warn("Could not add filter to dashboard");
} else {
self.$element.toggleClass('oe_opened');
self.do_notify("Filter added to dashboard", '');
}
});
},
show_option:function(){
this.$element.toggleClass('oe_opened');
if (! this.$element.hasClass('oe_opened'))
return;
this.$("input").val(this.getParent().fields_view.name || "" );
}
});
instance.web.SearchView.include({
add_common_inputs: function() {
this._super();
(new instance.board.AddToDashboard(this));
}
});
};

View File

@ -0,0 +1,80 @@
<template>
<t t-name="DashBoard">
<div class="oe_dashboard_links">
<button type="button" class="button oe_dashboard_link_reset" title="Reset Layout.." t-att-style="view.fields_view.custom_view_id ? null : 'display: none'">
<img src="/board/static/src/img/layout_2-1.png" width="16" height="16"/>
<span> Reset </span>
</button>
<button type="button" class="button oe_dashboard_link_change_layout" title="Change Layout..">
<img src="/board/static/src/img/layout_1-1-1.png" width="16" height="16"/>
<span> Change Layout </span>
</button>
</div>
<table t-att-data-layout="node.attrs.style" t-attf-class="oe_dashboard oe_dashboard_layout_#{node.attrs.style}" cellspacing="0" cellpadding="0" border="0">
<tr>
<td t-foreach="node.children" t-as="column" t-if="column.tag == 'column'"
t-att-id="view.element_id + '_column_' + column_index" t-attf-class="oe_dashboard_column index_#{column_index}">
<t t-foreach="column.children" t-as="action" t-if="action.tag == 'action'" t-call="DashBoard.action"/>
</td>
</tr>
</table>
</t>
<t t-name="DashBoard.action">
<div t-att-data-id="action.attrs.name" class="oe_action">
<h2 t-attf-class="oe_header #{action.attrs.string ? '' : 'oe_header_empty'}">
<t t-esc="action.attrs.string"/>
<t t-if="!action.attrs.string">&amp;nbsp;</t>
<button t-if="action.attrs.creatable and action.attrs.creatable !== 'false'" class="oe_button oe_button_create">Create</button>
<span class='oe_icon oe_close'></span>
<span class='oe_icon oe_minimize oe_fold' t-if="!action.attrs.fold"></span>
<span class='oe_icon oe_maximize oe_fold' t-if="action.attrs.fold"></span>
</h2>
<div t-attf-id="#{view.element_id}_action_#{column_index}_#{action_index}" class="oe_content" t-att-style="action.attrs.fold ? 'display: none' : null"></div>
</div>
</t>
<t t-name="DashBoard.layouts">
<div class="oe_dashboard_layout_selector">
<p>
<strong>Choose dashboard layout</strong>
</p>
<ul>
<li t-foreach="'1 1-1 1-1-1 1-2 2-1'.split(' ')" t-as="layout" t-att-data-layout="layout">
<img t-attf-src="/board/static/src/img/layout_#{layout}.png"/>
<img t-if="layout == current_layout"
src="/web/static/src/img/icons/gtk-apply.png" width="16" height="16" class="oe_dashboard_selected_layout"/>
</li>
</ul>
</div>
</t>
<t t-name="DashBoard.xml">
<form t-att-string="form_title" version="7.0">
<board t-att-style="style">
<column t-foreach="columns" t-as="column">
<action t-foreach="column" t-as="action" t-att="action"/>
</column>
</board>
</form>
</t>
<div t-name="HomeWidget" class="oe_dashboard_home_widget"/>
<t t-name="HomeWidget.content">
<h3><t t-esc="widget.title"/></h3>
<iframe width="100%" frameborder="0" t-att-src="url"/>
</t>
<div t-name="SearchView.addtodashboard" class="oe_searchview_dashboard">
<h4>Add to Dashboard</h4>
<form>
<p><input placeholder="Title of new dashboard item"/></p>
<button class="oe_apply" type="submit">Add</button>
</form>
</div>
<t t-name="SearchView.addtodashboard.selection">
<select>
<option t-foreach="selections" t-as="element"
t-att-value="element.id ">
<t t-esc="element.name"/></option>
</select>
</t>
</template>

View File

@ -1,25 +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 board_menu_create
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,102 +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/>.
#
##############################################################################
from osv import fields, osv
from tools.translate import _
class board_menu_create(osv.osv_memory):
"""
Create Menu
"""
def view_init(self, cr, uid, fields, context=None):
"""
This function checks for precondition before wizard executes
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
check dashboard view on menu name field.
@return: False
"""
data = context and context.get('active_id', False) or False
if data:
return False
def board_menu_create(self, cr, uid, ids, context=None):
"""
Create Menu.
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of Board Menu Create's IDs
@return: Dictionary {}.
"""
if context is None:
context = {}
context_id = context and context.get('active_id', False) or False
if context_id:
board = self.pool.get('board.board').browse(cr, uid, context_id, context=context)
action_id = self.pool.get('ir.actions.act_window').create(cr, uid, {
'name': board.name,
'view_type': 'form',
'view_mode': 'form',
'res_model': 'board.board',
'view_id': board.view_id.id,
'help': _('''<div class="oe_empty_custom_dashboard">
<p>
<b>This dashboard is empty.</b>
</p><p>
To add the first report into this dashboard, go to any
menu, switch to list or graph view, and click <i>'Add to
Dashboard'</i> in the extended search options.
</p><p>
You can filter and group data before inserting into the
dashboard using the search options.
</p>
</div>
''')
})
obj_menu = self.pool.get('ir.ui.menu')
#start Loop
for data in self.browse(cr, uid, ids, context=context):
obj_menu.create(cr, uid, {
'name': data.menu_name,
'parent_id': data.menu_parent_id.id,
'action': 'ir.actions.act_window,' + str(action_id)
}, context=context)
#End Loop
return {'type': 'ir.actions.act_window_close'}
_name = "board.menu.create"
_description = "Menu Create"
_columns = {
'menu_name': fields.char('Menu Name', size=64, required=True),
'menu_parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
}
board_menu_create()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!--Board menu create wizard -->
<record id="view_board_menu_create" model="ir.ui.view">
<field name="name">board.menu.create.form</field>
<field name="model">board.menu.create</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Create Menu For Dashboard" version="7.0">
<group colspan="4" string="Menu Information">
<field name="menu_name"/>
<field name="menu_parent_id"/>
</group>
<footer>
<button string="Create Menu" name="board_menu_create" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action for Board Menu create wizard. -->
<record id="action_board_menu_create" model="ir.actions.act_window">
<field name="name">Create Board Menu</field>
<field name="res_model">board.menu.create</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_board_menu_create"/>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -41,7 +41,7 @@
<!--
CRM CASE STAGE
-->
-->
<!-- Stage Search view -->
<record id="crm_lead_stage_search" model="ir.ui.view">
@ -77,7 +77,7 @@
<!--
LEADS/OPPORTUNITIES CATEGORIES
-->
-->
<!-- Categories Form View -->
<record id="crm_lead_categ_action" model="ir.actions.act_window">
@ -89,7 +89,7 @@
<field name="domain">[('object_id.model', '=', 'crm.lead')]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new sales tag.
Click to define a new sales tag.
</p><p>
Create specific tags that fit your company's activities
to better classify and analyse your leads and opportunities.
@ -105,7 +105,7 @@
<!--
LEADS
-->
-->
<act_window
id="act_crm_opportunity_crm_phonecall_new"
name="Phone calls"
@ -134,7 +134,7 @@
<header>
<button name="%(crm.action_crm_lead2opportunity_partner)d" string="Convert to Opportunity" type="action"
states="draft,open,pending" help="Convert to Opportunity" class="oe_highlight"/>
<button name="case_escalate" string="Escalate" type="object"
<button name="case_escalate" string="Escalate" type="object"
states="draft,open,pending"/>
<button name="case_reset" string="Reset" type="object"
states="cancel"/>
@ -156,7 +156,7 @@
<group>
<group>
<field name="partner_name" string="Company Name"/>
<field name="partner_id" string="Customer"
<field name="partner_id" string="Customer"
on_change="on_change_partner(partner_id)" />
<label for="street" string="Address"/>
<div>
@ -174,7 +174,7 @@
<label for="contact_name" />
<div>
<field name="contact_name" class="oe_inline"/>,
<field name="title" placeholder="Title" domain="[('domain', '=', 'contact')]" class="oe_inline"/>
<field name="title" placeholder="Title" domain="[('domain', '=', 'contact')]" class="oe_inline" options='{"no_open": true}'/>
</div>
<field name="email_from" widget="email"/>
<field name="function" />
@ -189,7 +189,7 @@
-->
</group>
<group>
<field name="user_id" />
<field name="user_id"/>
<field name="section_id"/>
<field name="type" invisible="1"/>
</group>
@ -285,286 +285,265 @@
</field>
</record>
<!-- CRM Lead Kanban View -->
<record model="ir.ui.view" id="crm_case_kanban_view_leads">
<field name="name">CRM - Leads Kanban</field>
<field name="model">crm.lead</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<kanban default_group_by="stage_id">
<field name="state" groups="base.group_no_one"/>
<field name="color"/>
<field name="priority"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="user_email"/>
<field name="user_id"/>
<field name="partner_address_email"/>
<field name="message_summary"/>
<field name="needaction_pending"/>
<templates>
<t t-name="lead_details">
<ul class="oe_kanban_tooltip">
<li t-if="record.phone.raw_value"><b>Phone:</b> <field name="phone"/></li>
<li><b>Probability:</b> <field name="probability"/>%%</li>
<li><b>Creation date:</b> <field name="create_date"/></li>
<li t-if="record.date_deadline.raw_value"><b>Date Deadline:</b> <field name="date_deadline"/></li>
</ul>
</t>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu">
<li><a type="edit" >Edit...</a></li>
<li><a type="delete">Delete</a></li>
<li><a name="%(mail.action_email_compose_message_wizard)d" type="action">Send Email</a></li>
<li><a name="%(opportunity2phonecall_act)d" type="action">Log Call</a></li>
<li><a name="action_makeMeeting" type="object">Schedule Meeting</a></li>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
<!-- CRM Lead Kanban View -->
<record model="ir.ui.view" id="crm_case_kanban_view_leads">
<field name="name">CRM - Leads Kanban</field>
<field name="model">crm.lead</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<kanban default_group_by="stage_id">
<field name="state" groups="base.group_no_one"/>
<field name="color"/>
<field name="priority"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="user_email"/>
<field name="user_id"/>
<field name="partner_address_email"/>
<field name="message_summary"/>
<field name="needaction_pending"/>
<templates>
<t t-name="lead_details">
<ul class="oe_kanban_tooltip">
<li t-if="record.phone.raw_value"><b>Phone:</b> <field name="phone"/></li>
<li><b>Probability:</b> <field name="probability"/>%%</li>
<li><b>Creation date:</b> <field name="create_date"/></li>
<li t-if="record.date_deadline.raw_value"><b>Date Deadline:</b> <field name="date_deadline"/></li>
</ul>
</t>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu">
<li><a type="edit" >Edit...</a></li>
<li><a type="delete">Delete</a></li>
<li><a name="%(mail.action_email_compose_message_wizard)d" type="action">Send Email</a></li>
<li><a name="%(opportunity2phonecall_act)d" type="action">Log Call</a></li>
<li><a name="action_makeMeeting" type="object">Schedule Meeting</a></li>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
<div class="oe_kanban_content">
<div>
<b><field name="name"/></b>
<t t-if="record.planned_revenue.raw_value">
- <b><t t-esc="Math.round(record.planned_revenue.value)"/>
<field name="company_currency"/></b>
</t>
</div>
<div>
<field name="partner_id"/>
</div>
<div style="padding-left: 0.5em">
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kanban_text_red</t>
<span t-attf-class="#{red || ''}"><field name="date_action"/></span>
<t t-if="record.date_action.raw_value"> : </t>
<field name="title_action"/>
</div>
<div class="oe_kanban_bottom_right">
<a t-if="record.priority.raw_value == 1" type="object" name="set_normal_priority" class="oe_e oe_star_on">7</a>
<a t-if="record.priority.raw_value != 1" type="object" name="set_high_priority" class="oe_e oe_star_off">7</a>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
<div class="oe_kanban_footer_left">
<t t-if="record.needaction_pending.raw_value"><span class="oe_kanban_mail_new">New</span></t>
<t t-raw="record.message_summary.raw_value"/>
</div>
</div>
<div class="oe_clear"></div>
</div>
<div class="oe_kanban_content">
<div>
<b><field name="name"/></b>
<t t-if="record.planned_revenue.raw_value">
- <b><t t-esc="Math.round(record.planned_revenue.value)"/>
<field name="company_currency"/></b>
</t>
</div>
<div>
<field name="partner_id"/>
</div>
<div style="padding-left: 0.5em">
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kanban_text_red</t>
<span t-attf-class="#{red || ''}"><field name="date_action"/></span>
<t t-if="record.date_action.raw_value"> : </t>
<field name="title_action"/>
</div>
<div class="oe_kanban_bottom_right">
<a t-if="record.priority.raw_value == 1" type="object" name="set_normal_priority" class="oe_e oe_star_on">7</a>
<a t-if="record.priority.raw_value != 1" type="object" name="set_high_priority" class="oe_e oe_star_off">7</a>
<!--
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kaban_status_red</t>
<span t-attf-class="oe_kanban_status #{red}"> </span>
-->
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value and record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
<div class="oe_kanban_footer_left">
<t t-if="record.needaction_pending.raw_value"><span class="oe_kanban_mail_new">New</span></t>
<t t-raw="record.message_summary.raw_value"/>
</div>
</div>
<div class="oe_clear"></div>
</div>
<!--
<div class="oe_kanban_right">
<a name="case_mark_lost" string="Mark Lost" states="open,pending" type="object" icon="kanban-stop" />
<a name="case_pending" string="Pending" states="draft,open" type="object" icon="kanban-pause" />
<a name="case_open" string="Open" states="pending" type="object" icon="gtk-media-play" />
<a name="case_mark_won" string="Mark Won" states="open,pending" type="object" icon="kanban-apply" />
</div>
-->
</t>
</templates>
</kanban>
</field>
</record>
</t>
</templates>
</kanban>
</field>
</record>
<!-- CRM Lead Search View -->
<record id="view_crm_case_leads_filter" model="ir.ui.view">
<field name="name">CRM - Leads Search</field>
<field name="model">crm.lead</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Leads">
<field name="name" string="Lead / Customer" filter_domain="['|','|',('partner_name','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike',self)]" />
<!-- subjects is not set as store=True so, it is placed outside filter_domain-->
<field name="subjects"/>
<field name="create_date"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" name="new" help="New Leads" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Open" name="open" domain="[('state','=','open')]"/>
<separator/>
<filter string="Unassigned Leads" icon="terp-personal-" domain="[('user_id','=', False)]" help="Unassigned Leads" />
<separator/>
<filter string="Leads Assigned to Me or My Team(s)" icon="terp-personal+" context="{'invisible_section': False}"
domain="['|', ('section_id.user_id','=',uid), ('section_id.member_ids', 'in', [uid])]"
help="Leads that are assigned to one of the sale teams I manage, or to me"/>
<field name="user_id"/>
<field name="section_id" context="{'invisible_section': False}"/>
<field name="country_id" context="{'invisible_country': False}"/>
<group expand="0" string="Group By...">
<filter string="Salesperson" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Team" icon="terp-personal+" domain="[]" context="{'group_by':'section_id'}"/>
<filter string="Referrer" icon="terp-personal" domain="[]" context="{'group_by':'referred'}"/>
<filter string="Campaign" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'type_id'}" />
<filter string="Channel" icon="terp-call-start" domain="[]" context="{'group_by':'channel_id'}" />
<separator orientation="vertical"/>
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<filter string="Creation" help="Create date" icon="terp-go-month" domain="[]" context="{'group_by':'create_date'}" groups="base.group_no_one"/>
</group>
<group string="Display">
<filter string="Show Countries" icon="terp-personal+" context="{'invisible_country': False}" help="Show Countries"/>
<filter string="Show Sales Team" icon="terp-personal+" context="{'invisible_section': False}" domain="[]" help="Show Sales Team"/>
</group>
</search>
</field>
</record>
<!-- CRM Lead Search View -->
<record id="view_crm_case_leads_filter" model="ir.ui.view">
<field name="name">CRM - Leads Search</field>
<field name="model">crm.lead</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Leads">
<field name="name" string="Lead / Customer" filter_domain="['|','|',('partner_name','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike',self)]" />
<!-- subjects is not set as store=True so, it is placed outside filter_domain-->
<field name="subjects"/>
<field name="create_date"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" name="new" help="New Leads" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Open" name="open" domain="[('state','=','open')]"/>
<separator/>
<filter string="Unassigned Leads" icon="terp-personal-" domain="[('user_id','=', False)]" help="Unassigned Leads" />
<separator/>
<filter string="Leads Assigned to Me or My Team(s)" icon="terp-personal+" context="{'invisible_section': False}"
domain="['|', ('section_id.user_id','=',uid), ('section_id.member_ids', 'in', [uid])]"
help="Leads that are assigned to one of the sale teams I manage, or to me"/>
<field name="user_id"/>
<field name="section_id" context="{'invisible_section': False}"/>
<field name="country_id" context="{'invisible_country': False}"/>
<group expand="0" string="Group By...">
<filter string="Salesperson" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Team" icon="terp-personal+" domain="[]" context="{'group_by':'section_id'}"/>
<filter string="Referrer" icon="terp-personal" domain="[]" context="{'group_by':'referred'}"/>
<filter string="Campaign" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'type_id'}" />
<filter string="Channel" icon="terp-call-start" domain="[]" context="{'group_by':'channel_id'}" />
<separator orientation="vertical"/>
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<filter string="Creation" help="Create date" icon="terp-go-month" domain="[]" context="{'group_by':'create_date'}" groups="base.group_no_one"/>
</group>
<group string="Display">
<filter string="Show Countries" icon="terp-personal+" context="{'invisible_country': False}" help="Show Countries"/>
<filter string="Show Sales Team" icon="terp-personal+" context="{'invisible_section': False}" domain="[]" help="Show Sales Team"/>
</group>
</search>
</field>
</record>
<!--
OPPORTUNITY
<!--
OPPORTUNITY
-->
<!-- Opportunities Form View -->
<record model="ir.ui.view" id="crm_case_form_view_oppor">
<field name="name">Opportunities</field>
<field name="model">crm.lead</field>
<field name="type">form</field>
<field name="priority">20</field>
<field name="arch" type="xml">
<form string="Opportunities" version="7.0">
<header>
<button name="case_mark_won" string="Mark Won" type="object"
states="open" class="oe_highlight"/>
<button name="case_mark_won" string="Mark Won" type="object"
states="draft,pending"/>
<button name="case_escalate" string="Escalate" type="object"
states="open" />
<button name="case_mark_lost" string="Mark Lost" type="object"
states="draft,open"/>
<button name="case_cancel" string="Cancel" type="object"
states="draft"/>
<field name="stage_id" widget="statusbar" clickable="True"/>
</header>
<sheet>
<div class="oe_right oe_button_box">
<button string="Schedule/Log Call"
name="%(opportunity2phonecall_act)d"
type="action"/>
<button string="Meeting"
name="action_makeMeeting"
type="object"
context="{'search_default_attendee_id': active_id, 'default_attendee_id' : active_id}"
/>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<label for="planned_revenue" class="oe_edit_only"/>
<h2>
<field name="planned_revenue" class="oe_inline"/>
<field name="company_currency" class="oe_inline"/> at
<field name="probability" class="oe_inline" widget="integer"/>%% success rate
</h2>
</div>
<group>
<group>
<field name="partner_id"
on_change="onchange_partner_id(partner_id, email_from)"
string="Customer"
context="{'default_name': partner_name, 'default_email': email_from, 'default_phone': phone}"/>
<field name="email_from" string="Email"/>
<field name="phone"/>
</group>
<group>
<label for="title_action"/>
<div>
<field name="date_action" nolabel="1"/> <label string="-" attrs="{'invisible': ['|', ('date_action', '=', False), ('title_action', '=', False)]}"/>
<field name="title_action" class="oe_inline" nolabel="1" placeholder="e.g. Call for proposal"/>
</div>
<field name="date_deadline"/>
<field name="priority"/>
</group>
<group>
<field name="user_id"/>
<field name="section_id" colspan="1" widget="selection"/>
</group>
<group>
<field name="categ_ids"
string="Categories" widget="many2many_tags"
domain="[('object_id.model', '=', 'crm.lead')]"/>
</group>
</group>
<!--<button string="Mail"
name="%(mail.action_email_compose_message_wizard)d"
context="{'mail':'new', 'model': 'crm.lead'}"
icon="terp-mail-message-new" type="action" />-->
<notebook colspan="4">
<page string="Internal Notes">
<field name="description"/>
</page>
<page string="Lead">
<!-- Opportunities Form View -->
<record model="ir.ui.view" id="crm_case_form_view_oppor">
<field name="name">Opportunities</field>
<field name="model">crm.lead</field>
<field name="type">form</field>
<field name="priority">20</field>
<field name="arch" type="xml">
<form string="Opportunities" version="7.0">
<header>
<button name="case_mark_won" string="Mark Won" type="object"
states="draft,open,pending" class="oe_highlight"/>
<button name="case_mark_lost" string="Mark Lost" type="object"
states="draft,open" class="oe_highlight"/>
<button name="case_escalate" string="Escalate" type="object"
states="open" />
<field name="stage_id" widget="statusbar" clickable="True"/>
</header>
<sheet>
<div class="oe_right oe_button_box">
<button string="Schedule/Log Call"
name="%(opportunity2phonecall_act)d"
type="action"/>
<button string="Meeting"
name="action_makeMeeting"
type="object"
context="{'search_default_attendee_id': active_id, 'default_attendee_id' : active_id}"
/>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<label for="planned_revenue" class="oe_edit_only"/>
<h2>
<field name="planned_revenue" class="oe_inline"/>
<field name="company_currency" class="oe_inline"/> at
<field name="probability" class="oe_inline" widget="integer"/>%% success rate
</h2>
</div>
<group>
<group>
<field name="partner_name"/>
<label for="street" string="Address"/>
<field name="partner_id"
on_change="onchange_partner_id(partner_id, email_from)"
string="Customer"
context="{'default_name': partner_name, 'default_email': email_from, 'default_phone': phone}"/>
<field name="email_from" string="Email"/>
<field name="phone"/>
</group>
<group>
<label for="title_action"/>
<div>
<field name="street" placeholder="Street..."/>
<field name="street2"/>
<div class="address_format">
<field name="city" placeholder="City" style="width: 40%%"/>
<field name="state_id" options='{"no_open": true}' placeholder="State" style="width: 24%%"/>
<field name="zip" placeholder="ZIP" style="width: 34%%"/>
<field name="date_action" nolabel="1"/> <label string="-" attrs="{'invisible': ['|', ('date_action', '=', False), ('title_action', '=', False)]}"/>
<field name="title_action" class="oe_inline" nolabel="1" placeholder="e.g. Call for proposal"/>
</div>
<field name="date_deadline"/>
<field name="priority"/>
</group>
<group>
<field name="user_id"/>
<field name="section_id" colspan="1" widget="selection"/>
</group>
<group>
<field name="categ_ids"
string="Categories" widget="many2many_tags"
domain="[('object_id.model', '=', 'crm.lead')]"/>
</group>
</group>
<notebook colspan="4">
<page string="Internal Notes">
<field name="description"/>
</page>
<page string="Lead">
<group>
<group>
<field name="partner_name"/>
<label for="street" string="Address"/>
<div>
<field name="street" placeholder="Street..."/>
<field name="street2"/>
<div class="address_format">
<field name="city" placeholder="City" style="width: 40%%"/>
<field name="state_id" options='{"no_open": true}' placeholder="State" style="width: 24%%"/>
<field name="zip" placeholder="ZIP" style="width: 34%%"/>
</div>
<field name="country_id" placeholder="Country" options='{"no_open": true}'/>
</div>
<field name="country_id" placeholder="Country" options='{"no_open": true}'/>
</div>
</group>
</group>
<group>
<label for="contact_name" />
<div>
<field name="contact_name" class="oe_inline"/>
<field name="title" placeholder="Title" domain="[('domain', '=', 'contact')]" options='{"no_open": true}' class="oe_inline"/>
</div>
<field name="function" />
<field name="mobile"/>
<field name="fax"/>
</group>
<group string="Categorization">
<field name="type_id" widget="selection"/>
<field name="channel_id" widget="selection"/>
</group>
<group string="Mailings">
<field name="opt_out" />
</group>
<group string="Misc">
<field name="active"/>
<field name="day_open" groups="base.group_no_one"/>
<field name="day_close" groups="base.group_no_one"/>
<field name="referred"/>
<field name="state" groups="base.group_no_one"/>
<field name="type" invisible="1"/>
</group>
<group string="References">
<field name="ref"/>
<field name="ref2"/>
</group>
</group>
</page>
<page string="Fund Raising" groups="crm.group_fund_raising">
<group>
<label for="contact_name" />
<div>
<field name="contact_name" class="oe_inline"/>
<field name="title" placeholder="Title" domain="[('domain', '=', 'contact')]" options='{"no_open": true}' class="oe_inline"/>
</div>
<field name="function" />
<field name="mobile"/>
<field name="fax"/>
<field name="payment_mode" widget="selection"/>
<field name="planned_cost"/>
</group>
<group string="Categorization">
<field name="type_id" widget="selection"/>
<field name="channel_id" widget="selection"/>
</group>
<group string="Mailings">
<field name="opt_out" />
</group>
<group string="Misc">
<field name="active"/>
<field name="day_open" groups="base.group_no_one"/>
<field name="day_close" groups="base.group_no_one"/>
<field name="referred"/>
<field name="state" groups="base.group_no_one"/>
<field name="type" invisible="1"/>
</group>
<group string="References">
<field name="ref"/>
<field name="ref2"/>
</group>
</group>
</page>
<page string="Fund Raising" groups="crm.group_fund_raising">
<group>
<field name="payment_mode" widget="selection"/>
<field name="planned_cost"/>
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<!-- Opportunities Tree View -->
<record model="ir.ui.view" id="crm_case_tree_view_oppor">
@ -596,48 +575,48 @@
</record>
<!-- Opportunities Search View -->
<record id="view_crm_case_opportunities_filter" model="ir.ui.view">
<field name="name">CRM - Opportunities Search</field>
<field name="model">crm.lead</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Opportunities">
<field name="name" string="Opportunity / Customer"
filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike', self)]" />
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" help="New Opportunities" name="new" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Open" help="Open Opportunities" name="open" domain="[('state','=','open')]"/>
<separator/>
<filter string="Unassigned Opportunities" icon="terp-personal-" domain="[('user_id','=', False)]" help="Unassigned Opportunities" />
<separator/>
<filter string="Opportunities Assigned to Me or My Team(s)" icon="terp-personal+"
domain="['|', ('section_id.user_id','=',uid), ('section_id.member_ids', 'in', [uid])]" context="{'invisible_section': False}"
help="Opportunities that are assigned to either me or one of the sale teams I manage" />
<field name="user_id"/>
<field name="country_id"/>
<field name="partner_id"/>
<field name="section_id" context="{'invisible_section': False, 'default_section_id': self}"/>
<group expand="0" string="Group By..." colspan="16">
<filter string="Salesperson" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
<filter string="Team" help="Sales Team" icon="terp-personal+" domain="[]" context="{'group_by':'section_id'}"/>
<filter string="Customer" help="Partner" icon="terp-personal+" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}" />
<filter string="Priority" icon="terp-rating-rated" domain="[]" context="{'group_by':'priority'}" />
<filter string="Campaign" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'type_id'}"/>
<filter string="Channel" icon="terp-call-start" domain="[]" context="{'group_by':'channel_id'}" />
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<filter string="Creation" icon="terp-go-month" domain="[]" context="{'group_by':'create_date'}" groups="base.group_no_one"/>
<filter string="Exp.Closing" icon="terp-go-month" help="Expected Closing" domain="[]" context="{'group_by':'date_deadline'}" />
</group>
<group string="Display">
<filter string="Show Sales Team" icon="terp-personal+" context="{'invisible_section': False}" domain="[]" help="Show Sales Team"/>
</group>
</search>
</field>
</record>
<!-- Opportunities Search View -->
<record id="view_crm_case_opportunities_filter" model="ir.ui.view">
<field name="name">CRM - Opportunities Search</field>
<field name="model">crm.lead</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search Opportunities">
<field name="name" string="Opportunity / Customer"
filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike', self)]" />
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" help="New Opportunities" name="new" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Open" help="Open Opportunities" name="open" domain="[('state','=','open')]"/>
<separator/>
<filter string="Unassigned Opportunities" icon="terp-personal-" domain="[('user_id','=', False)]" help="Unassigned Opportunities" />
<separator/>
<filter string="Opportunities Assigned to Me or My Team(s)" icon="terp-personal+"
domain="['|', ('section_id.user_id','=',uid), ('section_id.member_ids', 'in', [uid])]" context="{'invisible_section': False}"
help="Opportunities that are assigned to either me or one of the sale teams I manage" />
<field name="user_id"/>
<field name="country_id"/>
<field name="partner_id"/>
<field name="section_id" context="{'invisible_section': False, 'default_section_id': self}"/>
<group expand="0" string="Group By..." colspan="16">
<filter string="Salesperson" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
<filter string="Team" help="Sales Team" icon="terp-personal+" domain="[]" context="{'group_by':'section_id'}"/>
<filter string="Customer" help="Partner" icon="terp-personal+" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}" />
<filter string="Priority" icon="terp-rating-rated" domain="[]" context="{'group_by':'priority'}" />
<filter string="Campaign" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'type_id'}"/>
<filter string="Channel" icon="terp-call-start" domain="[]" context="{'group_by':'channel_id'}" />
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<filter string="Creation" icon="terp-go-month" domain="[]" context="{'group_by':'create_date'}" groups="base.group_no_one"/>
<filter string="Exp.Closing" icon="terp-go-month" help="Expected Closing" domain="[]" context="{'group_by':'date_deadline'}" />
</group>
<group string="Display">
<filter string="Show Sales Team" icon="terp-personal+" context="{'invisible_section': False}" domain="[]" help="Show Sales Team"/>
</group>
</search>
</field>
</record>
</data>
</openerp>

View File

@ -14,9 +14,9 @@
<record id="action_crm_phonecall_unread" model="ir.values">
<field name="name">action_crm_phonecall_unread</field>
<field name="action_id" ref="actions_server_crm_phonecall_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_phonecall_unread'))" />
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_phonecall_unread'))"/>
<field name="key">action</field>
<field name="model_id" ref="model_crm_phonecall" />
<field name="model_id" ref="model_crm_phonecall"/>
<field name="model">crm.phonecall</field>
<field name="key2">client_action_multi</field>
</record>
@ -32,9 +32,9 @@
<record id="action_crm_phonecall_read" model="ir.values">
<field name="name">action_crm_phonecall_read</field>
<field name="action_id" ref="actions_server_crm_phonecall_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_phonecall_read'))" />
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_crm_phonecall_read'))"/>
<field name="key">action</field>
<field name="model_id" ref="model_crm_phonecall" />
<field name="model_id" ref="model_crm_phonecall"/>
<field name="model">crm.phonecall</field>
<field name="key2">client_action_multi</field>
</record>
@ -82,10 +82,10 @@
name="%(phonecall2opportunity_act)d"
states="open,pending"
icon="gtk-index"
type="action" attrs="{'invisible':[('opportunity_id','!=',False)]}" />
type="action" attrs="{'invisible':[('opportunity_id','!=',False)]}"/>
<button string="Meeting"
states="open,pending" icon="gtk-redo"
name="action_make_meeting" type="object" />
name="action_make_meeting" type="object"/>
<field name="state"/>
<button name="case_open" string="Confirm" type="object"
states="draft,pending" icon="gtk-go-forward"/>
@ -115,14 +115,14 @@
<button string="Convert to Opportunity"
name="%(phonecall2opportunity_act)d"
type="action"
attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state','!=', 'open')]}" />
attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state','!=', 'open')]}"/>
<button string="Convert to Opportunity" class="oe_highlight"
name="%(phonecall2opportunity_act)d"
type="action"
attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state','!=', 'done')]}" />
attrs="{'invisible':[ '|', ('opportunity_id','!=',False), ('state','!=', 'done')]}"/>
<button string="Schedule Other Call"
name="%(phonecall_to_phonecall_act)d"
type="action" />
type="action"/>
<button string="Schedule a Meeting" name="action_make_meeting" type="object"/>
<button name="case_cancel" string="Cancel" type="object"
states="draft,open,pending"/>
@ -131,28 +131,28 @@
<sheet string="Phone Call">
<div class="oe_title">
<div class="oe_edit_only">
<label for="name" string="Title"/>
<label for="name" string="Title"/>
</div>
<h1><field name="name" required="1"/></h1>
<div class="oe_edit_only">
<label for="partner_phone" string="Phone" />
<label for="partner_phone" string="Phone"/>
</div>
<h2><field name="partner_phone"/></h2>
</div>
<group col="4">
<field name="date" />
<field name="user_id" />
<field name="duration" widget="float_time" />
<field name="section_id" colspan="1" widget="selection" />
<field name="date"/>
<field name="user_id"/>
<field name="duration" widget="float_time"/>
<field name="section_id" colspan="1" widget="selection"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="categ_id" widget="selection"
domain="[('object_id.model', '=', 'crm.phonecall')]"/>
<field name="partner_mobile" />
<field name="partner_mobile"/>
<field name="priority"/>
<field name="opportunity_id"/>
</group>
<field name="description" placeholder="Description..." />
<field name="description" placeholder="Description..."/>
</sheet>
<div class="oe_chatter">
<field name="message_ids" widget="mail_thread"/>
@ -186,15 +186,15 @@
<button string="Schedule Other Call"
icon="terp-call-start"
name="%(phonecall_to_phonecall_act)d"
type="action" />
type="action"/>
<button string="Meeting"
icon="gtk-redo"
name="action_make_meeting" type="object" />
name="action_make_meeting" type="object"/>
<button string="Convert to Opportunity"
name="%(phonecall2opportunity_act)d"
states="open,pending"
icon="gtk-index"
type="action" attrs="{'invisible':[('opportunity_id','!=',False)]}" />
type="action" attrs="{'invisible':[('opportunity_id','!=',False)]}"/>
</tree>
</field>
</record>
@ -230,15 +230,15 @@
<filter string="Unassigned Phonecalls" icon="terp-personal-" domain="[('user_id','=',False)]" help="Unassigned Phonecalls"/>
<separator/>
<filter string="Phone Calls Assigned to Me or My Team(s)" icon="terp-personal+" domain="['|', ('section_id.user_id','=',uid), ('section_id.member_ids', 'in', [uid])]"
help="Phone Calls that are assigned to me or to my team(s)" />
help="Phone Calls that are assigned to me or to my team(s)"/>
<field name="partner_id"/>
<field name="user_id"/>
<field name="section_id" string="Sales Team"/>
<group expand="0" string="Group By...">
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}" />
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
<filter string="Creation" icon="terp-go-month" help="Creation Date" domain="[]" context="{'group_by':'create_date'}" />
<filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'date'}" help="Date of Call" />
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Creation" icon="terp-go-month" help="Creation Date" domain="[]" context="{'group_by':'create_date'}"/>
<filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'date'}" help="Date of Call"/>
</group>
</search>
</field>

View File

@ -1,5 +1,7 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="view_crm_lead2opportunity_partner" model="ir.ui.view">
<field name="name">crm.lead2opportunity.partner.form</field>
<field name="model">crm.lead2opportunity.partner</field>
@ -16,20 +18,20 @@
<separator string="Select Opportunities" attrs="{'invisible': [('name', '=', 'convert')]}"/>
<field name="opportunity_ids" attrs="{'invisible': [('name', '=', 'convert')]}">
<tree>
<field name="name" />
<field name="partner_id" />
<field name="user_id" />
<field name="section_id" />
<field name="name"/>
<field name="partner_id"/>
<field name="user_id"/>
<field name="section_id"/>
</tree>
</field>
<footer>
<button name="action_apply" string="Create Opportunity" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
</record>
<record id="view_crm_lead2opportunity_partner_mass" model="ir.ui.view">
<field name="name">crm.lead2opportunity.partner.mass.form</field>
@ -40,18 +42,18 @@
<field name="action"/>
<field name="name" colspan="4"/>
<group string="Assigned Opportunities to">
<field name="section_id" />
<field name="section_id"/>
</group>
<separator string="Select Salesman"/>
<field name="user_ids">
<tree>
<field name="name" />
<field name="name"/>
</tree>
</field>
<footer>
<button name="mass_convert" string="Convert into Opportunities" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
@ -65,13 +67,13 @@
<field name="view_id" ref="view_crm_lead2opportunity_partner"/>
<field name="target">new</field>
</record>
<act_window id="action_crm_send_mass_convert"
<act_window id="action_crm_send_mass_convert"
multi="True"
key2="client_action_multi" name="Convert opportunities"
res_model="crm.lead2opportunity.partner.mass" src_model="crm.lead"
view_mode="form" target="new" view_type="form"
context="{'mass_convert' : True}"
view_id="view_crm_lead2opportunity_partner_mass"/>
view_id="view_crm_lead2opportunity_partner_mass"/>
</data>
</openerp>

View File

@ -13,16 +13,16 @@
<separator string="Select Opportunities"/>
<field name="opportunity_ids">
<tree>
<field name="name" />
<field name="partner_id" />
<field name="user_id" />
<field name="section_id" />
<field name="name"/>
<field name="partner_id"/>
<field name="user_id"/>
<field name="section_id"/>
</tree>
</field>
<footer>
<button name="action_merge" type="object" string="_Merge" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
@ -43,7 +43,7 @@
multi="True"
key2="client_action_multi" name="Merge Opportunities"
res_model="crm.merge.opportunity" src_model="crm.lead"
view_mode="form" target="new" view_type="form" />
view_mode="form" target="new" view_type="form"/>
</data>
</openerp>

View File

@ -15,7 +15,7 @@
<field name="name"/>
<field name="date" string="Planned Date" attrs="{'invisible': [('action','=','log')]}"/>
<field name="partner_id" readonly="True"/>
<field name="user_id" />
<field name="user_id"/>
<field name="section_id"/>
</group>
<footer>

View File

@ -2,27 +2,26 @@
<openerp>
<data>
<record model="ir.ui.view" id="crm_lead_forward_to_partner_form">
<field name="name">crm_lead_forward_to_partner</field>
<field name="model">crm.lead.forward.to.partner</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Send Mail" version="7.0">
<separator string="Forward to Partner" colspan="4" />
<separator string="Forward to Partner" colspan="4"/>
<group col="4" colspan="6">
<field name="history" colspan="2" on_change="on_change_history(history, context)"/>
<field name="send_to" colspan="2" />
<field name="send_to" colspan="2"/>
<group col="2" colspan="2" attrs="{ 'invisible' : [('send_to','!=','user')]}">
<field name="user_id"
attrs="{ 'required' : [('send_to','=','user')]}"
on_change="on_change_email(user_id)" />
on_change="on_change_email(user_id)"/>
</group>
<group col="4" colspan="4" attrs="{'invisible' : [('send_to','!=','partner')]}">
<field name="partner_id" attrs="{'required' : [('send_to','=','partner')]}" on_change="on_change_partner(partner_id)" colspan="2" />
<field name="partner_id" attrs="{'required' : [('send_to','=','partner')]}" on_change="on_change_partner(partner_id)" colspan="2"/>
</group>
</group>
<separator string="" colspan="4" />
<separator string="" colspan="4"/>
<group col="6" colspan="4">
<field name="email_from" colspan="4" required="1"/>
<field name="email_to" colspan="4" required="1"/>
@ -44,7 +43,7 @@
<footer>
<button name="action_forward" string="Send" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
@ -60,7 +59,7 @@
</record>
<act_window id="action_crm_send_mass_forward"
multi="True"
key2="client_action_multi" name="Mass forward to partner"
@ -68,7 +67,7 @@
view_mode="form" target="new" view_type="form"
context="{'mail.compose.message.mode' : 'mass_mail'}"
view_id="crm_lead_forward_to_partner_form"
/>
/>

View File

@ -1,3 +1,4 @@
<?xml version="1.0"?>
<openerp>
<data>
<menuitem name="Document Management" id="menu_document_management_configuration" parent="knowledge.menu_document_configuration" sequence="1"/>

View File

@ -47,6 +47,13 @@ class res_company(osv.osv):
result['logo'] = company.logo # already base64-encoded
if company.paypal_account:
result['paypal_account'] = company.paypal_account
# bank info: include only bank account supposed to be displayed in document footers
res_partner_bank = self.pool.get('res.partner.bank')
bank_ids = res_partner_bank.search(cr, uid, [('company_id','=',company.id),('footer','=',True)], context=context)
if bank_ids:
result['bank_ids'] = res_partner.edi_m2m(cr, uid,
res_partner_bank.browse(cr, uid, bank_ids, context=context),
context=context)
return result
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -65,7 +65,7 @@
<page string="Personal Information" groups="base.group_hr_user">
<group col="4">
<group>
<field name="country_id"/>
<field name="country_id" options='{"no_open": true}'/>
<field name="bank_account_id"/>
<field name="address_home_id"/>
</group>

View File

@ -310,7 +310,7 @@
<a type="object" name="set_priority" args="['1']">
<img t-attf-src="/web/static/src/img/icons/star-#{priority == 1 ? 'on' : 'off'}.png" width="16" height="16" title="Excellent"/>
</a>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
</div>

View File

@ -7,8 +7,8 @@
<field name="type">form</field>
<field name="inherit_id" ref="base_calendar.view_crm_meeting_form"/>
<field name="arch" type="xml">
<field name="categ_id" position="replace">
<field name="categ_id" widget="selection" domain="[('user_id', 'in', [uid, False])]"/>
<field name="categ_ids" position="attributes">
<attribute name="domain">[('user_id', 'in', [uid, False])]</attribute>
</field>
</field>
</record>

View File

@ -101,8 +101,8 @@ class res_users(osv.osv):
self.message_subscribe(cr, uid, [user_id], [user_id], context=context)
# create a welcome message
company_name = user.company_id.name if user.company_id else _('the company')
message = _('%s has joined %s! Welcome to OpenERP !') % (user.name, company_name)
self.message_append_note(cr, uid, [user_id], subject='Welcome to OpenERP', body=message, type='comment', context=context)
message = _('%s joined the %s network! Take a moment to welcome %s.') % (user.name, company_name, user.name)
self.message_append_note(cr, uid, [user_id], body=message, type='comment', context=context)
return user_id
def write(self, cr, uid, ids, vals, context=None):

View File

@ -51,7 +51,6 @@ Main features:
'wizard/pos_confirm.xml',
'wizard/pos_discount.xml',
'wizard/pos_open_statement.xml',
'wizard/pos_close_statement.xml',
'wizard/pos_payment_report_user_view.xml',
'wizard/pos_sales_user.xml',
'wizard/pos_receipt_view.xml',

View File

@ -55,7 +55,7 @@ class pos_config(osv.osv):
'shop_id' : fields.many2one('sale.shop', 'Shop',
required=True),
'journal_id' : fields.many2one('account.journal', 'Sale Journal',
required=True, domain=[('type', '=', 'sale')],
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."),
@ -195,23 +195,17 @@ class pos_session(osv.osv):
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)]}
),
'name' : fields.char('Session ID', size=32, required=True, readonly=True),
'user_id' : fields.many2one('res.users', 'Responsible',
required=True,
select=1,
# readonly=True,
# states={'draft' : [('readonly', False)]}
readonly=True,
states={'opening_control' : [('readonly', False)]}
),
'start_at' : fields.datetime('Opening Date'),
'stop_at' : fields.datetime('Closing Date'),
'start_at' : fields.datetime('Opening Date', readonly=True),
'stop_at' : fields.datetime('Closing Date', readonly=True),
'state' : fields.selection(POS_SESSION_STATE, 'State',
required=True, readonly=True,
@ -281,7 +275,7 @@ class pos_session(osv.osv):
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'),
('state', 'not in', ('closed','closing_control')),
('user_id', '=', uid)
]
count = self.search_count(cr, uid, domain, context=context)
@ -307,11 +301,31 @@ class pos_session(osv.osv):
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)
# journal_id is not required on the pos_config because it does not
# exists at the installation. If nothing is configured at the
# installation we do the minimal configuration. Impossible to do in
# the .xml files as the CoA is not yet installed.
jobj = self.pool.get('pos.config')
pos_config = jobj.browse(cr, uid, config_id, context=context)
if not pos_config.journal_id:
jid = jobj.default_get(cr, uid, ['journal_id'], context=context)['journal_id']
if jid:
jobj.write(cr, uid, [pos_config.id], {'journal_id': jid}, context=context)
else:
raise osv.except_osv( _('error!'),
_("Unable to open the session. You have to assign a sale journal to your point of sale."))
# define some cash journal if no payment method exists
if not pos_config.journal_ids:
cashids = self.pool.get('account.journal').search(cr, uid, [('journal_user','=',True)], context=context)
if not cashids:
cashids = self.pool.get('account.journal').search(cr, uid, [('type','=','cash')], context=context)
self.pool.get('account.journal').write(cr, uid, cashids, {'journal_user': True})
jobj.write(cr, uid, [pos_config.id], {'journal_ids': [(6,0, cashids)]})
pos_config = jobj.browse(cr, uid, config_id, context=context)
bank_statement_ids = []
for journal in pos_config.journal_ids:
bank_values = {
@ -323,7 +337,8 @@ class pos_session(osv.osv):
values.update({
'name' : pos_config.sequence_id._next(),
'statement_ids' : [(6, 0, bank_statement_ids)]
'statement_ids' : [(6, 0, bank_statement_ids)],
'config_id': config_id
})
return super(pos_session, self).create(cr, uid, values, context=context)
@ -335,7 +350,7 @@ class pos_session(osv.osv):
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
# second browse because we need to refetch the data from the DB for cash_register_id
for record in self.browse(cr, uid, ids, context=context):
values = {}
if not record.start_at:
@ -344,7 +359,8 @@ class pos_session(osv.osv):
record.write(values, context=context)
for st in record.statement_ids:
st.button_open(context=context)
return True
return self.open_frontend_cb(cr, uid, ids, context=context)
def wkf_action_opening_control(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'opening_control'}, context=context)
@ -352,7 +368,7 @@ class pos_session(osv.osv):
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.id <> session.cash_register_id.id:
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})
@ -377,7 +393,7 @@ class pos_session(osv.osv):
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,))
_("Please set your profit and loss accounts on your payment method '%s'. This will allow OpenERP to post the difference of %.2f in your ending balance. To close this session, you can update the 'Closing Cash Control' to avoid any difference.") % (st.journal_id.name,st.difference))
bsl.create(cr, uid, {
'statement_id': st.id,
'amount': st.difference,
@ -388,7 +404,15 @@ class pos_session(osv.osv):
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)
self.write(cr, uid, ids, {'state' : 'closed'}, context=context)
obj = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'point_of_sale', 'menu_point_root')[1]
return {
'type' : 'ir.actions.client',
'name' : 'Point of Sale Menu',
'tag' : 'reload',
'params' : {'menu_id': obj},
}
def _confirm_orders(self, cr, uid, ids, context=None):
wf_service = netsvc.LocalService("workflow")
@ -413,10 +437,8 @@ class pos_session(osv.osv):
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',

View File

@ -12,10 +12,13 @@
<field name="type">automatic</field>
<field name="sequence">100</field>
</record>
<record model="pos.config" id="pos_config_main">
<field name="name">Main</field>
</record>
</data>
<data>
<record model="pos.config" id="pos_config_main">
<field name="name">Main PoS</field>
<record id="sale.todo_open_sale_menu" model="ir.actions.todo">
<field name="state">done</field>
</record>
</data>
@ -29,6 +32,181 @@
If you install the PoS proxy, you will be able to interface OpenERP with retail materials; barcode scanners, printers, cash registers, weighing machine, credit card payments.</value>
</function>
<record id="unreferenced_product" model="product.product">
<field name="list_price">1.00</field>
<field name="name">Unreferenced Products</field>
<field name="pos_categ_id" ref="categ_others"/>
<field name="image">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</field>
</record>
</data>
</openerp>

View File

@ -3,9 +3,9 @@
<data>
<!-- Top menu item -->
<menuitem name="PoS Backend"
<menuitem name="Point of Sale"
id="menu_point_root"
groups="group_pos_manager"
groups="group_pos_manager,group_pos_user"
sequence="140"/>
<record id="categ_others" model="pos.category">
@ -32,7 +32,7 @@
<group col="4" colspan="4">
<field name="name"/>
<field name="date_order"/>
<field name="session_id" required="1" />
<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 colspan="4">
@ -61,14 +61,14 @@
<group class="oe_subtotal_footer">
<field name="amount_tax"/>
<field name="amount_total"/>
<button name="button_dummy" string="Update" icon="gtk-execute" states="draft" />
<button name="button_dummy" string="Update" icon="gtk-execute" states="draft"/>
</group>
</page>
<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" />
<field name="statement_id"/>
<field name="amount"/>
</tree>
<form string="Statement lines" version="7.0">
@ -114,6 +114,15 @@
<field name="view_mode">tree,form</field>
<field name="view_id" eval="False"/>
<field name="domain">[]</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new order.
</p><p>
Use this menu to browse your preceeding orders. To record new
orders, you should better use the menu <i>Your Session</i> for
the touchscreen interface.
</p>
</field>
</record>
<record model="ir.ui.view" id="view_pos_order_tree">
<field name="name">Sales</field>
@ -155,8 +164,8 @@
</field>
</record>
<menuitem name="Daily Operations" id="menu_point_of_sale" parent="menu_point_root" sequence="10" />
<menuitem parent="menu_point_of_sale" id="menu_point_ofsale" action="action_pos_pos_form" sequence="1" groups="group_pos_manager,group_pos_user"/>
<menuitem name="Daily Operations" id="menu_point_of_sale" parent="menu_point_root" sequence="10"/>
<menuitem parent="menu_point_of_sale" id="menu_point_ofsale" action="action_pos_pos_form" sequence="2" groups="group_pos_manager,group_pos_user"/>
<menuitem name="Products" id="menu_point_of_sale_product" parent="menu_point_root" sequence="15" />
<record id="product_normal_action" model="ir.actions.act_window">
@ -166,6 +175,7 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form,kanban</field>
<field name="context" eval="{'default_pos_categ_id': ref('point_of_sale.categ_others')}"/>
<field name="domain" eval="[('pos_categ_id','&lt;&gt;',False)]"/>
<field name="view_id" ref="product.product_product_tree_view"/>
<field name="search_view_id" ref="product.product_search_form_view"/>
<field name="help" type="html">
@ -691,6 +701,18 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" eval="False"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new category.
</p><p>
Categories are used to browse your products through the
touchscreen interface.
</p><p>
If you put a photo on the category, the layout of the
touchscreen interface will automatically. We suggest not to put
a photo on categories for small (1024x768) screens.
</p>
</field>
</record>
<menuitem action="pos_category_action" id="menu_pos_category" parent="menu_point_of_sale_product" sequence="0" />
<!-- END -->
@ -710,7 +732,9 @@
Click to add a payment method.
</p><p>
Payment methods are defined by accounting journals having the
field <i>Payment Method</i> checked.
field <i>PoS Payment Method</i> checked. In order to be useable
from the touchscreen interface, you must set the payment method
on the <i>Point of Sale</i> configuration.
</p>
</field>
</record>
@ -764,18 +788,6 @@
</record>
<!-- Top menu item -->
<!--
right now it's not possible to directly call a client action
from a menuitem, so we can't use this shortcut element and
use an explicit record element instead
-->
<record id="menu_point_root_touchscreen" model="ir.ui.menu">
<field name="name">Point of Sale</field>
<field name="action" ref="action_pos_pos"/>
<field name="groups_id" eval="[(6, 0, [ref('point_of_sale.group_pos_manager'), ref('point_of_sale.group_pos_user')])]"/>
<field name="sequence">150</field>
</record>
<record model="ir.ui.view" id="view_pos_config_form">
<field name="name">pos.config.form.view</field>
<field name="model">pos.config</field>
@ -896,81 +908,93 @@
<field name="arch" type="xml">
<form string="Point of Sale Session" version="7.0">
<header>
<button name="open" type="workflow" string="Validate &amp; Open Session" states="opening_control" />
<button name="cashbox_control" type="workflow" string="End of Session" states="opened" />
<button name="close" type="workflow" string="Validate &amp; Close" states="closing_control,opened" />
<button name="open" type="workflow" string="Validate &amp; Open Session" states="opening_control" class="oe_highlight"/>
<button name="cashbox_control" type="workflow" string="End of Session" states="opened"
class="oe_highlight"/>
<button name="close" type="workflow" string="Validate Closing &amp; Post Entries" states="closing_control"
class="oe_highlight"/>
<button name="open_frontend_cb" type="object" string="Start Selling" states="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"/>
<div class="oe_right oe_button_box">
<button name="%(action_pos_box_in)d" string="Put Money In" type="action" states="opened,closing_control"/>
<button name="%(action_pos_box_out)d" string="Take Money Out" type="action" states="opened,closing_control"/>
</div>
<h1 class="oe_title">
Point of Sale Session:
<field name="name" attrs="{'invisible': [('name','=','/')]}" class="oe_inline"/>
</h1>
<field name="config_id" invisible="1"/>
<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>
<group>
<group>
<field name="user_id"/>
</group>
<group>
<field name="start_at" attrs="{'invisible' : [('state', '=', 'opening_control')]}"/>
<field name="stop_at" attrs="{'invisible' : [('state', '&lt;&gt;', 'closed')]}"/>
</group>
<newline/>
<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 string="Opening Cash Control">
<field name="opening_details_ids" nolabel="1" colspan="2" attrs="{'readonly' : [('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)" />
<field name="subtotal_opening" string="Opening Subtotal" sum="Total"/>
</tree>
</field>
</group>
<group string="Closing Cash Control" attrs="{'invisible': [('state', '=', 'opening_control')]}">
<field name="details_ids" nolabel="1" colspan="2">
<tree string="Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_closing"/>
<field name="subtotal_closing"/>
</tree>
</field>
</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>
<div>
<group class="oe_subtotal_footer oe_right">
<field name="cash_register_balance_start" readonly="1" string="Opening Balance" class="oe_subtotal_footer_separator"/>
<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 Balance"/>
</group>
<div attrs="{'invisible' : [('state', '&lt;&gt;', 'opening_control')]}" class="oe_view_nocontent" groups="point_of_sale.group_pos_manager">
<p class="oe_view_nocontent_create">
You can define another list of available currencies on the
<i>Cash Registers</i> tab of the <b><field name="cash_register_id" class="oe_inline"/></b>
payment method.
</p>
</div>
</div>
<group class="oe_subtotal_footer oe_right" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
<field name="cash_register_balance_end_real" class="oe_subtotal_footer_separator"/>
<field name="cash_register_difference" class="oe_subtotal_footer_separator"/>
</group>
</group>
<separator string="Summary by Payment Methods" attrs="{'invisible' : [('state', '=', 'opening_control')]}"/>
<field name="statement_ids" 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>
</sheet>
</form>
</field>
@ -987,6 +1011,7 @@
<field name="user_id" />
<field name="start_at" />
<field name="stop_at" />
<field name="state" />
</tree>
</field>
</record>
@ -1021,18 +1046,11 @@
<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"
sequence="1"
groups="group_pos_manager"/>
<record id="view_pos_order_filter" model="ir.ui.view">
@ -1060,7 +1078,9 @@
</field>
</record>
<menuitem action="action_pos_session_opening" parent="menu_point_of_sale" id="menu_pos_session_opening" sequence="0" />
<menuitem action="action_pos_session_opening"
parent="menu_point_of_sale"
id="menu_pos_session_opening" sequence="0"/>
</data>
</openerp>

View File

@ -875,7 +875,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
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(
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['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;

View File

@ -22,7 +22,6 @@
import pos_confirm
import pos_discount
import pos_open_statement
import pos_close_statement
import pos_details
import pos_sales_user
import pos_sales_user_today

View File

@ -13,16 +13,16 @@
<field name="journal_id"/>
<field name="product_id"/>
<field name="amount"/>
<field name="session_id" />
<field name="session_id"/>
<field name="name"/>
<field name="user_id" invisible="1" />
<field name="user_id" invisible="1"/>
<separator colspan="4"/>
<group colspan="4" col="4">
<group col="2" colspan="2"/>
<button icon="gtk-stop" special="cancel"
string="Cancel" />
string="Cancel"/>
<button name="get_in" string="Put Money"
colspan="1" type="object" icon="gtk-apply" />
colspan="1" type="object" icon="gtk-apply"/>
</group>
</form>
</field>
@ -34,7 +34,7 @@
view_mode="form"
target="new"
key2="client_action_multi"
id="action_box_entries" />
id="action_box_entries"/>
<act_window name="Put Money In"
res_model="pos.box.entries"
@ -42,7 +42,7 @@
view_mode="form"
target="new"
key2="client_action_multi"
id="action_pos_session_box_entries" />
id="action_pos_session_box_entries"/>
</data>

View File

@ -1,76 +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/>.
#
##############################################################################
from osv import osv
from tools.translate import _
class pos_close_statement(osv.osv_memory):
_name = 'pos.close.statement'
_description = 'Close Statements'
def cancel_wizard(self, cr, uid, ids, context=None):
if context.get('cancel_action'):
return context['cancel_action']
def close_statement(self, cr, uid, ids, context=None):
"""
Close the statements
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param context: A standard dictionary
@return : Blank Dictionary
"""
context = context or {}
mod_obj = self.pool.get('ir.model.data')
statement_obj = self.pool.get('account.bank.statement')
journal_obj = self.pool.get('account.journal')
j_ids = journal_obj.search(cr, uid, [('journal_user','=',1)], context=context)
ids = statement_obj.search(cr, uid, [('state', '!=', 'confirm'), ('user_id', '=', uid), ('journal_id', 'in', j_ids)], context=context)
if not ids:
raise osv.except_osv(_('Message'), _('Cash registers are already closed.'))
for statement in statement_obj.browse(cr, uid, ids, context=context):
statement_obj.write(cr, uid, [statement.id], {
'balance_end_real': statement.balance_end
}, context=context)
if not statement.journal_id.check_dtls:
statement_obj.button_confirm_cash(cr, uid, [statement.id], context=context)
tree_res = mod_obj.get_object_reference(cr, uid, 'point_of_sale', 'view_cash_statement_pos_tree')
tree_id = tree_res and tree_res[1] or False
form_res = mod_obj.get_object_reference(cr, uid, 'account', 'view_bank_statement_form2')
form_id = form_res and form_res[1] or False
search_res = mod_obj.get_object_reference(cr, uid, 'account', 'view_account_bank_statement_filter')
return {
'domain': str([('id', 'in', ids)]),
'name': _('Close Cash Registers'),
'view_type': 'form',
'view_mode': 'tree,form',
'search_view_id': search_res and search_res[1] or False,
'res_model': 'account.bank.statement',
'views': [(tree_id, 'tree'), (form_id, 'form')],
'type': 'ir.actions.act_window'
}
pos_close_statement()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Point of Sale Confirm -->
<record id="view_pos_close_statement" model="ir.ui.view">
<field name="name">Close Statements</field>
<field name="model">pos.close.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Close Cash Registers" version="7.0">
<header>
<button name="close_statement" string="Yes"
type="object" class="oe_highlight" />
<button type="object" name="cancel_wizard"
string="No" invisible="not context.get('cancel_action')" class="oe_highlight" />
or
<button string="Cancel" class="oe_link" special="cancel" />
</header>
<separator string="Do you want to close your cash registers?"/>
<label string="OpenERP will close all cash registers he can close automatically without validation. He will also open all cash registers for which you have to control the ending balance before closing manually."/>
</form>
</field>
</record>
<!--
<act_window name="Close Statements"
res_model="pos.close.statement"
src_model="account.bank.statement"
view_mode="form"
target="new"
key2="client_action_multi"
id="act_pos_open_statement"/>
-->
<record id="action_pos_close_statement" model="ir.actions.act_window">
<field name="name">Close Cash Register</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.close.statement</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -10,8 +10,26 @@ class pos_session_opening(osv.osv_memory):
_columns = {
'pos_config_id' : fields.many2one('pos.config', 'Point of Sale', required=True),
'pos_session_id' : fields.many2one('pos.session', 'PoS Session'),
'pos_state' : fields.char('Session State'),
}
def open_ui(self, cr, uid, ids, context=None):
context = context or {}
data = self.browse(cr, uid, ids[0], context=context)
context['active_id'] = data.pos_session_id.id
return {
'type' : 'ir.actions.client',
'name' : 'Start Point Of Sale',
'tag' : 'pos.ui',
'context' : context
}
def open_existing_session_cb_close(self, cr, uid, ids, context=None):
wf_service = netsvc.LocalService("workflow")
wizard = self.browse(cr, uid, ids[0], context=context)
wf_service.trg_validate(uid, 'pos.session', wizard.pos_session_id.id, 'cashbox_control', cr)
return self.open_session_cb(cr, uid, ids, context)
def open_session_cb(self, cr, uid, ids, context=None):
assert len(ids) == 1, "you can open only one session at a time"
proxy = self.pool.get('pos.session')
@ -42,18 +60,21 @@ class pos_session_opening(osv.osv_memory):
}
def on_change_config(self, cr, uid, ids, config_id, context=None):
result = {
'pos_session_id': False,
'pos_state': False
}
if not config_id:
return {}
return {'value': result}
proxy = self.pool.get('pos.session')
session_ids = proxy.search(cr, uid, [
('state', '<>', 'closed'),
('config_id', '=', config_id),
], context=context)
return {
'value' : {
'pos_session_id' : session_ids and session_ids[0] or False,
}
}
if session_ids:
result['pos_state'] = proxy.browse(cr, uid, session_ids[0], context=context).state
result['pos_session_id'] = session_ids[0]
return {'value' : result}
def default_get(self, cr, uid, fieldnames, context=None):
so = self.pool.get('pos.session')
@ -63,9 +84,10 @@ class pos_session_opening(osv.osv_memory):
else:
current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
result = current_user.pos_config and current_user.pos_config.id or False
if not result:
r = self.pool.get('pos.config').search(cr, uid, [], context=context)
result = r and r[0] or False
return {
'pos_config_id' : result,
'pos_session_id': session_ids and session_ids[0] or False
'pos_config_id' : result
}
pos_session_opening()

View File

@ -7,28 +7,54 @@
<field name="arch" type="xml">
<form string="PoS Session Opening" version="7.0">
<separator string="Select your Point of Sale" colspan="4" />
<field name="pos_config_id" on_change="on_change_config(pos_config_id)" widget="selection" domain="[('state','=','active')]"/>
<field name="pos_session_id" invisible="1"/>
<group colspan="4">
<button special="cancel" icon="gtk-cancel" string="Cancel" />
<button name="open_existing_session_cb" type="object" string="Open Session" icon="gtk-ok"
attrs="{'invisible' : [('pos_session_id', '=', False)]}"
/>
<button name="open_session_cb" type="object" string="New Session" icon="gtk-ok"
attrs="{'invisible' : [('pos_session_id', '!=', False)]}"
/>
<group>
<field name="pos_config_id" on_change="on_change_config(pos_config_id)"
widget="selection" domain="[('state','=','active')]"
class="oe_inline"/>
</group>
<field name="pos_session_id" invisible="1"/>
<field name="pos_state" invisible="1"/>
<button name="open_ui" type="object" string="Start Selling"
attrs="{'invisible' : [('pos_state', 'not in', ('opened',))]}"
class="oe_highlight"
/>
<button name="open_existing_session_cb" type="object" string="Open Session"
attrs="{'invisible' : [('pos_state', 'not in', ('opening_control',))]}"
class="oe_highlight"
/>
<button name="open_existing_session_cb_close" type="object" string="Close Session"
attrs="{'invisible' : [('pos_state', 'not in', ('opened',))]}"
/>
<button name="open_existing_session_cb" type="object" string="Close Session"
attrs="{'invisible' : [('pos_state', 'not in', ('closing_control',))]}"
class="oe_highlight"
/>
<button name="open_session_cb" type="object" string="New Session"
attrs="{'invisible' : ['|', ('pos_state', '!=', False),('pos_config_id','=',False)]}"
class="oe_highlight"
/>
<div attrs="{'invisible' : ['|', ('pos_state', '!=', False),('pos_config_id','=',False)]}" class="oe_view_nocontent">
<p class="oe_view_nocontent_create">
Click to start a session.
</p><p>
You will first have to control your cash amount in your cash register.
Then you will be able to open the session and start selling with the touchscreen
interface.
</p>
</div>
</form>
</field>
</record>
<record id="action_pos_session_opening" model="ir.actions.act_window">
<field name="name">Open/Close a Session</field>
<field name="name">Your Session</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.session.opening</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="target">inline</field>
</record>
</data>
</openerp>

View File

@ -36,8 +36,8 @@
<field name="street2"/>
<field name="zip"/>
<field name="city"/>
<field name="country_id"/>
<field name="state_id"/>
<field name="country_id" options='{"no_open": true}'/>
<field name="state_id" options='{"no_open": true}'/>
<templates>
<t t-name="kanban-box">
<h4><field name="name"/></h4>

View File

@ -49,7 +49,7 @@
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())">
<span t-attf-class="oe_kanban_status oe_kaban_status_red"> </span>
</t>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
</div>
</div>

View File

@ -788,7 +788,7 @@ class task(base_stage, osv.osv):
}),
'user_id': fields.many2one('res.users', 'Assigned to'),
'delegated_user_id': fields.related('child_ids', 'user_id', type='many2one', relation='res.users', string='Delegated To'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'partner_id': fields.many2one('res.partner', 'Contact'),
'work_ids': fields.one2many('project.task.work', 'task_id', 'Work done'),
'manager_id': fields.related('project_id', 'analytic_account_id', 'user_id', type='many2one', relation='res.users', string='Project Manager'),
'company_id': fields.many2one('res.company', 'Company'),

View File

@ -71,7 +71,7 @@
<!-- Categories -->
<record id="project_category_01" model="project.category">
<field name="name">Partner's suggestion</field>
<field name="name">Contact's suggestion</field>
</record>
<record id="project_category_02" model="project.category">
<field name="name">Feature request</field>

View File

@ -89,7 +89,7 @@
<group>
<group>
<field name="user_id" string="Project Manager" attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"/>
<field name="partner_id" string = "Contact" on_change="onchange_partner_id(partner_id)"/>
<field name="partner_id" string="Contact" on_change="onchange_partner_id(partner_id)"/>
<field name="privacy_visibility"/>
<field name="analytic_account_id" invisible="1" required="0"/>
</group>
@ -171,10 +171,10 @@
<separator/>
<filter string="Project(s) Manager" domain="[('user_id','=',uid)]" help="Projects in which I am a manager" icon="terp-personal"/>
<field name="user_id" string="Project Manager"/>
<field name="partner_id" string="Partner"/>
<field name="partner_id" string="Contact"/>
<group expand="0" string="Group By...">
<filter string="Manager" name="Manager" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Partner" name="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Contact" name="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Parent" name="Parent" help="Parent" icon="terp-folder-blue" domain = "[]" context="{'group_by':'parent_id'}"/>
</group>
</search>
@ -328,7 +328,7 @@
<field colspan="4" name="name"/>
<field name="hours" widget="float_time"/>
<field name="date"/>
<field name="user_id"/>
<field name="user_id" options='{"no_open": true}'/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
</form>
@ -422,7 +422,7 @@
<group>
<group>
<field name="project_id" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/>
<field name="user_id" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
<field name="user_id" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}" options='{"no_open": true}'/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
<group>
@ -549,7 +549,7 @@
<a t-if="record.kanban_state.raw_value === 'blocked'" type="object" string="Blocked" name="set_kanban_state_normal" class="oe_kanban_status oe_kanban_status_red"> </a>
<a t-if="record.priority.raw_value == 1" type="object" string="Priority" name="set_normal_priority" class="oe_e oe_star_on">7</a>
<a t-if="record.priority.raw_value != 1" type="object" string="Priority" name="set_high_priority" class="oe_e oe_star_off">7</a>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
<div class="oe_kanban_footer_left">
<span groups="project.group_time_work_estimation_tasks" title="Remaining hours">

View File

@ -53,7 +53,7 @@ class report_project_task_user(osv.osv):
'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),
'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'Status', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True, groups="base.group_multi_company"),
'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
'partner_id': fields.many2one('res.partner', 'Contact', readonly=True),
}
_order = 'name desc, project_id'

View File

@ -80,7 +80,7 @@
<group expand="1" string="Group By...">
<filter string="Project" name="project" icon="terp-folder-violet" context="{'group_by':'project_id'}"/>
<filter string="Task" icon="terp-stock_align_left_24" context="{'group_by':'name'}" />
<filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Assigned to" name="User" icon="terp-personal" context="{'group_by':'user_id'}" />
<filter string="Status" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
<filter string="Company" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>

View File

@ -98,8 +98,8 @@
<field name="inherit_id" ref="project.view_task_form2" />
<field name="arch" type="xml">
<field name="progress" position="after">
<field name="context_id" widget="selection"/>
<field name="timebox_id" widget="selection"/>
<field name="context_id" widget="selection" options='{"no_open": true}'/>
<field name="timebox_id" widget="selection" options='{"no_open": true}'/>
</field>
</field>
</record>

View File

@ -9,7 +9,7 @@
<field name="arch" type="xml">
<form string="Plannify Timebox" version="7.0">
<group col="4">
<field name="timebox_id" widget="selection"/>
<field name="timebox_id" widget="selection" options='{"no_open": true}'/>
<field name="timebox_to_id" widget="selection"/>
</group>
<field name="task_ids" domain="[('timebox_id','=',timebox_id),('state','=','open')]" />

View File

@ -219,7 +219,7 @@ class project_issue(base_stage, osv.osv):
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
select=True, help='Sales team to which Case belongs to.\
Define Responsible user and Email account for mail gateway.'),
'partner_id': fields.many2one('res.partner', 'Partner', select=1),
'partner_id': fields.many2one('res.partner', 'Contact', select=1),
'company_id': fields.many2one('res.company', 'Company'),
'description': fields.text('Description'),
'state': fields.related('stage_id', 'state', type="selection", store=True,

View File

@ -210,7 +210,7 @@
<field name="project_id"/>
<group expand="0" string="Group By..." >
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Contact" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Project" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/>
<filter string="Version" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'version_id'}"/>
<filter string="Category" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'categ_id'}"/>
@ -298,7 +298,7 @@
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())">
<span t-attf-class="oe_kanban_status oe_kaban_status_red"> </span>
</t>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
</div>
</div>

View File

@ -63,7 +63,7 @@ class project_issue_report(osv.osv):
'project_id':fields.many2one('project.project', 'Project',readonly=True),
'version_id': fields.many2one('project.issue.version', 'Version'),
'user_id' : fields.many2one('res.users', 'Assigned to',readonly=True),
'partner_id': fields.many2one('res.partner','Partner',domain="[('object_id.model', '=', 'project.issue')]"),
'partner_id': fields.many2one('res.partner','Contact',domain="[('object_id.model', '=', 'project.issue')]"),
'channel_id': fields.many2one('crm.case.channel', 'Channel',readonly=True),
'task_id': fields.many2one('project.task', 'Task',domain="[('object_id.model', '=', 'project.issue')]" ),
'email': fields.integer('# Emails', size=128, readonly=True),

View File

@ -62,7 +62,7 @@
<field name="version_id"/>
<group expand="1" string="Group By...">
<filter string="Assigned to" name="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
<filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Sale Team" icon="terp-personal+" domain="[]" context="{'group_by':'section_id'}" />
<filter string="Project" name="project" icon="terp-folder-violet" context="{'group_by':'project_id'}" />
<filter string="Task" icon="terp-stock_align_left_24" domain="[]" context="{'group_by':'task_id'}"/>

View File

@ -36,7 +36,7 @@
<field name="inherit_id" ref="analytic_contract_project.project_invoice_form"/>
<field name="arch" type="xml">
<field name="partner_id" position="replace">
<field name="partner_id" on_change="onchange_partner_id(partner_id)" string="Customer" attrs="{'required':[('to_invoice','!=',False)]}"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)" string="Contact" attrs="{'required':[('to_invoice','!=',False)]}"/>
</field>
</field>
</record>

View File

@ -9,8 +9,9 @@
<field name="inherit_id" ref="crm.crm_case_form_view_oppor"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/header/button[@name='case_mark_won']" position="before">
<button string="Convert to Quote" name="%(action_crm_make_sale)d" type="action" class="oe_highlight"/>
<xpath expr="/form/header/button[@name='case_mark_lost']" position="after">
<button states="done" string="Convert to Quote" name="%(action_crm_make_sale)d" type="action" class="oe_highlight"/>
<button states="draft,open,pending" string="Convert to Quote" name="%(action_crm_make_sale)d" type="action"/>
</xpath>
</data>
</field>

View File

@ -19,14 +19,20 @@
#
##############################################################################
import web.common.http
try:
# embedded
import openerp.addons.web.common.http as openerpweb
except ImportError:
# standalone
import web.common.http as openerpweb
import base64
import urllib2
class Binary(web.common.http.Controller):
class Binary(openerpweb.Controller):
_cp_path = "/web_linkedin/binary"
@web.common.http.jsonrequest
@openerpweb.jsonrequest
def url2binary(self, req,url):
bfile = urllib2.urlopen(url)
return base64.b64encode(bfile.read())