[MERGE] from trunk
bzr revid: rco@openerp.com-20121001073103-q8fajwquos2rm57f
This commit is contained in:
commit
27b4a70343
|
@ -31,7 +31,7 @@ import decimal_precision as dp
|
|||
from tools.translate import _
|
||||
from tools.float_utils import float_round
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
import tools
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -227,7 +227,7 @@ class account_account(osv.osv):
|
|||
while pos < len(args):
|
||||
|
||||
if args[pos][0] == 'code' and args[pos][1] in ('like', 'ilike') and args[pos][2]:
|
||||
args[pos] = ('code', '=like', str(args[pos][2].replace('%', ''))+'%')
|
||||
args[pos] = ('code', '=like', tools.ustr(args[pos][2].replace('%', ''))+'%')
|
||||
if args[pos][0] == 'journal_id':
|
||||
if not args[pos][2]:
|
||||
del args[pos]
|
||||
|
@ -682,7 +682,7 @@ class account_journal_view(osv.osv):
|
|||
_name = "account.journal.view"
|
||||
_description = "Journal View"
|
||||
_columns = {
|
||||
'name': fields.char('Journal View', size=64, required=True),
|
||||
'name': fields.char('Journal View', size=64, required=True, translate=True),
|
||||
'columns_id': fields.one2many('account.journal.column', 'view_id', 'Columns')
|
||||
}
|
||||
_order = "name"
|
||||
|
@ -1908,7 +1908,7 @@ class account_tax(osv.osv):
|
|||
'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
|
||||
'include_base_amount': fields.boolean('Included in base amount', help="Indicates if the amount of tax must be included in the base amount for the computation of the next taxes"),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True),
|
||||
'description': fields.char('Tax Code',size=32),
|
||||
'description': fields.char('Tax Code'),
|
||||
'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."),
|
||||
'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Application', required=True)
|
||||
|
||||
|
@ -2518,7 +2518,7 @@ class account_account_template(osv.osv):
|
|||
'reconcile': fields.boolean('Allow Reconciliation', help="Check this option if you want the user to reconcile entries in this account."),
|
||||
'shortcut': fields.char('Shortcut', size=12),
|
||||
'note': fields.text('Note'),
|
||||
'parent_id': fields.many2one('account.account.template', 'Parent Account Template', ondelete='cascade'),
|
||||
'parent_id': fields.many2one('account.account.template', 'Parent Account Template', ondelete='cascade', domain=[('type','=','view')]),
|
||||
'child_parent_ids':fields.one2many('account.account.template', 'parent_id', 'Children'),
|
||||
'tax_ids': fields.many2many('account.tax.template', 'account_account_template_tax_rel', 'account_id', 'tax_id', 'Default Taxes'),
|
||||
'nocreate': fields.boolean('Optional create', help="If checked, the new chart of accounts will not contain this by default."),
|
||||
|
@ -2536,20 +2536,6 @@ class account_account_template(osv.osv):
|
|||
(_check_recursion, 'Error!\nYou cannot create recursive account templates.', ['parent_id']),
|
||||
]
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if 'parent_id' in vals:
|
||||
parent = self.read(cr, uid, [vals['parent_id']], ['type'])
|
||||
if parent and parent[0]['type'] != 'view':
|
||||
raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'."))
|
||||
return super(account_account_template, self).create(cr, uid, vals, context=context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if 'parent_id' in vals:
|
||||
parent = self.read(cr, uid, [vals['parent_id']], ['type'])
|
||||
if parent and parent[0]['type'] != 'view':
|
||||
raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'."))
|
||||
return super(account_account_template, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
if not ids:
|
||||
return []
|
||||
|
@ -2828,7 +2814,7 @@ class account_tax_template(osv.osv):
|
|||
'ref_base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."),
|
||||
'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
|
||||
'include_base_amount': fields.boolean('Include in Base Amount', help="Set if the amount of tax must be included in the base amount before computing the next taxes."),
|
||||
'description': fields.char('Internal Name', size=32),
|
||||
'description': fields.char('Internal Name'),
|
||||
'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Use In', required=True,),
|
||||
'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."),
|
||||
}
|
||||
|
|
|
@ -457,6 +457,8 @@ class account_bank_statement(osv.osv):
|
|||
return res and res[0] or 0.0
|
||||
|
||||
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
|
||||
if not journal_id:
|
||||
return {}
|
||||
balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context)
|
||||
|
||||
journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['default_debit_account_id', 'company_id'], context=context)
|
||||
|
|
|
@ -508,8 +508,10 @@ class account_invoice(osv.osv):
|
|||
if journal_id:
|
||||
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
|
||||
currency_id = journal.currency and journal.currency.id or journal.company_id.currency_id.id
|
||||
company_id = journal.company_id.id
|
||||
result = {'value': {
|
||||
'currency_id': currency_id,
|
||||
'company_id': company_id,
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -1371,7 +1373,10 @@ class account_invoice_line(osv.osv):
|
|||
'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True)
|
||||
}
|
||||
|
||||
def _default_account_id(self, cr, uid, ids, context=None):
|
||||
def _default_account_id(self, cr, uid, context=None):
|
||||
# XXX this gets the default account for the user's company,
|
||||
# it should get the default account for the invoice's company
|
||||
# however, the invoice's company does not reach this point
|
||||
prop = self.pool.get('ir.property').get(cr, uid, 'property_account_income_categ', 'product.category', context=context)
|
||||
return prop and prop.id or False
|
||||
|
||||
|
@ -1401,7 +1406,7 @@ class account_invoice_line(osv.osv):
|
|||
context = {}
|
||||
company_id = company_id if company_id != None else context.get('company_id',False)
|
||||
context = dict(context)
|
||||
context.update({'company_id': company_id})
|
||||
context.update({'company_id': company_id, 'force_company': company_id})
|
||||
if not partner_id:
|
||||
raise osv.except_osv(_('No Partner Defined !'),_("You must first select a partner !") )
|
||||
if not product:
|
||||
|
@ -1556,16 +1561,19 @@ class account_invoice_line(osv.osv):
|
|||
def onchange_account_id(self, cr, uid, ids, product_id, partner_id, inv_type, fposition_id, account_id):
|
||||
if not account_id:
|
||||
return {}
|
||||
taxes = self.pool.get('account.account').browse(cr, uid, account_id).tax_ids
|
||||
unique_tax_ids = []
|
||||
fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False
|
||||
tax_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
|
||||
|
||||
product_change_result = self.product_id_change(cr, uid, ids, product_id, False, type=inv_type,
|
||||
partner_id=partner_id, fposition_id=fposition_id)
|
||||
unique_tax_ids = set(tax_ids)
|
||||
if product_change_result and 'value' in product_change_result and 'invoice_line_tax_id' in product_change_result['value']:
|
||||
unique_tax_ids |= set(product_change_result['value']['invoice_line_tax_id'])
|
||||
return {'value':{'invoice_line_tax_id': list(unique_tax_ids)}}
|
||||
account = self.pool.get('account.account').browse(cr, uid, account_id)
|
||||
if not product_id:
|
||||
taxes = account.tax_ids
|
||||
unique_tax_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
|
||||
else:
|
||||
product_change_result = self.product_id_change(cr, uid, ids, product_id, False, type=inv_type,
|
||||
partner_id=partner_id, fposition_id=fposition_id,
|
||||
company_id=account.company_id.id)
|
||||
if product_change_result and 'value' in product_change_result and 'invoice_line_tax_id' in product_change_result['value']:
|
||||
unique_tax_ids = product_change_result['value']['invoice_line_tax_id']
|
||||
return {'value':{'invoice_line_tax_id': unique_tax_ids}}
|
||||
|
||||
account_invoice_line()
|
||||
|
||||
|
@ -1650,14 +1658,13 @@ class account_invoice_tax(osv.osv):
|
|||
|
||||
for line in inv.invoice_line:
|
||||
for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, line.product_id, inv.partner_id)['taxes']:
|
||||
tax['price_unit'] = cur_obj.round(cr, uid, cur, tax['price_unit'])
|
||||
val={}
|
||||
val['invoice_id'] = inv.id
|
||||
val['name'] = tax['name']
|
||||
val['amount'] = tax['amount']
|
||||
val['manual'] = False
|
||||
val['sequence'] = tax['sequence']
|
||||
val['base'] = tax['price_unit'] * line['quantity']
|
||||
val['base'] = cur_obj.round(cr, uid, cur, tax['price_unit'] * line['quantity'])
|
||||
|
||||
if inv.type in ('out_invoice','in_invoice'):
|
||||
val['base_code_id'] = tax['base_code_id']
|
||||
|
|
|
@ -278,6 +278,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
@ -299,8 +300,8 @@
|
|||
<button name="invoice_open" states="draft" string="Validate" class="oe_highlight"/>
|
||||
<button name="invoice_open" states="proforma2" string="Validate"/>
|
||||
<button name="invoice_proforma2" states="draft" string="PRO-FORMA" groups="account.group_proforma_invoices"/>
|
||||
<button name="%(action_account_invoice_refund)d" type='action' string='Refund Invoice' states='paid'/>
|
||||
<button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" groups="base.group_no_one"/>
|
||||
<button name="%(action_account_invoice_refund)d" type='action' string='Refund Invoice' states='open,proforma2,paid'/>
|
||||
<button name="invoice_cancel" states="draft,proforma2,open" string="Cancel" groups="base.group_no_one"/>
|
||||
<button name="action_cancel_draft" states="cancel" string="Reset to Draft" type="object"/>
|
||||
<button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','<>','paid'), ('reconciled', '=', True)]}" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/>
|
||||
<!--button name="%(account_invoices)d" string="Print Invoice" type="action" states="open,paid,proforma,sale,proforma2"/-->
|
||||
|
@ -437,6 +438,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -562,6 +562,7 @@ class account_move_line(osv.osv):
|
|||
'journal_id': lambda self, cr, uid, c: c.get('journal_id', False),
|
||||
'credit': 0.0,
|
||||
'debit': 0.0,
|
||||
'amount_currency': 0.0,
|
||||
'account_id': lambda self, cr, uid, c: c.get('account_id', False),
|
||||
'period_id': lambda self, cr, uid, c: c.get('period_id', False),
|
||||
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.move.line', context=c)
|
||||
|
@ -1193,12 +1194,12 @@ class account_move_line(osv.osv):
|
|||
jour_period_obj = self.pool.get('account.journal.period')
|
||||
cr.execute('SELECT state FROM account_journal_period WHERE journal_id = %s AND period_id = %s', (journal_id, period_id))
|
||||
result = cr.fetchall()
|
||||
journal = journal_obj.browse(cr, uid, journal_id, context=context)
|
||||
period = period_obj.browse(cr, uid, period_id, context=context)
|
||||
for (state,) in result:
|
||||
if state == 'done':
|
||||
raise osv.except_osv(_('Error!'), _('You cannot add/modify entries in a closed journal.'))
|
||||
raise osv.except_osv(_('Error !'), _('You can not add/modify entries in a closed period %s of journal %s.' % (period.name,journal.name)))
|
||||
if not result:
|
||||
journal = journal_obj.browse(cr, uid, journal_id, context=context)
|
||||
period = period_obj.browse(cr, uid, period_id, context=context)
|
||||
jour_period_obj.create(cr, uid, {
|
||||
'name': (journal.code or journal.name)+':'+(period.name or ''),
|
||||
'journal_id': journal.id,
|
||||
|
|
|
@ -1305,16 +1305,6 @@
|
|||
Account.Entry Edition
|
||||
-->
|
||||
|
||||
<record id="account_move_graph" model="ir.ui.view">
|
||||
<field name="name">account.move.graph</field>
|
||||
<field name="model">account.move</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Account Statistics" type="bar">
|
||||
<field name="period_id"/>
|
||||
<field name="amount" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_move_tree" model="ir.ui.view">
|
||||
<field name="name">account.move.tree</field>
|
||||
<field name="model">account.move</field>
|
||||
|
@ -1338,8 +1328,8 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Account Entry" version="7.0">
|
||||
<header>
|
||||
<button name="button_validate" states="draft" string="Post" type="object" class="oe_highlight"/>
|
||||
<button name="button_cancel" states="posted" string="Cancel" type="object"/>
|
||||
<button name="button_validate" states="draft" string="Post" type="object" class="oe_highlight" groups="account.group_account_invoice"/>
|
||||
<button name="button_cancel" states="posted" string="Cancel" type="object" groups="account.group_account_invoice"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet string="Journal Entries" >
|
||||
|
@ -1488,7 +1478,7 @@
|
|||
<field name="name">Journal Entries</field>
|
||||
<field name="res_model">account.move</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,graph</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_move_tree"/>
|
||||
<field name="search_view_id" ref="view_account_move_filter"/>
|
||||
<field name="help" type="html">
|
||||
|
@ -2037,7 +2027,7 @@
|
|||
src_model="account.journal"/>
|
||||
|
||||
<act_window
|
||||
context="{'search_default_reconcile_id':False, 'search_default_partner_id':[active_id], 'default_partner_id': active_id}"
|
||||
context="{'search_default_unreconciled':True, 'search_default_partner_id':[active_id], 'default_partner_id': active_id}"
|
||||
domain="[('account_id.reconcile', '=', True),('account_id.type', 'in', ['receivable', 'payable'])]"
|
||||
id="act_account_partner_account_move_all"
|
||||
name="Receivables & Payables"
|
||||
|
@ -2073,7 +2063,7 @@
|
|||
id="account_template_folder"
|
||||
name="Templates"
|
||||
parent="menu_finance_accounting"
|
||||
groups="base.group_multi_company"/>
|
||||
groups="account.group_account_manager"/>
|
||||
<menuitem
|
||||
id="account_template_taxes"
|
||||
name="Taxes"
|
||||
|
|
|
@ -44,17 +44,17 @@ class account_fiscal_position(osv.osv):
|
|||
return []
|
||||
if not fposition_id:
|
||||
return map(lambda x: x.id, taxes)
|
||||
result = []
|
||||
result = set()
|
||||
for t in taxes:
|
||||
ok = False
|
||||
for tax in fposition_id.tax_ids:
|
||||
if tax.tax_src_id.id == t.id:
|
||||
if tax.tax_dest_id:
|
||||
result.append(tax.tax_dest_id.id)
|
||||
result.add(tax.tax_dest_id.id)
|
||||
ok=True
|
||||
if not ok:
|
||||
result.append(t.id)
|
||||
return result
|
||||
result.add(t.id)
|
||||
return list(result)
|
||||
|
||||
def map_account(self, cr, uid, fposition_id, account_id, context=None):
|
||||
if not fposition_id:
|
||||
|
@ -77,6 +77,12 @@ class account_fiscal_position_tax(osv.osv):
|
|||
'tax_dest_id': fields.many2one('account.tax', 'Replacement Tax')
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('tax_src_dest_uniq',
|
||||
'unique (position_id,tax_src_id,tax_dest_id)',
|
||||
'A tax fiscal position could be defined only once time on same taxes.')
|
||||
]
|
||||
|
||||
account_fiscal_position_tax()
|
||||
|
||||
class account_fiscal_position_account(osv.osv):
|
||||
|
@ -89,6 +95,12 @@ class account_fiscal_position_account(osv.osv):
|
|||
'account_dest_id': fields.many2one('account.account', 'Account Destination', domain=[('type','<>','view')], required=True)
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('account_src_dest_uniq',
|
||||
'unique (position_id,account_src_id,account_dest_id)',
|
||||
'An account fiscal position could be defined only once time on same accounts.')
|
||||
]
|
||||
|
||||
account_fiscal_position_account()
|
||||
|
||||
class res_partner(osv.osv):
|
||||
|
|
|
@ -92,34 +92,7 @@
|
|||
<field name="debit"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="bank_ids">
|
||||
<form string="Bank account" version="7.0">
|
||||
<group col="4">
|
||||
<field name="state"/>
|
||||
<field name="acc_number"/>
|
||||
</group>
|
||||
<group>
|
||||
<group name="owner" string="Bank Account Owner">
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
|
||||
<field name="owner_name"/>
|
||||
<label for="street" string="Address"/>
|
||||
<div>
|
||||
<field name="street" placeholder="Street..."/>
|
||||
<div>
|
||||
<field name="zip" class="oe_inline" placeholder="ZIP"/>
|
||||
<field name="city" class="oe_inline" placeholder="City"/>
|
||||
</div>
|
||||
<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">
|
||||
<field name="bank" on_change="onchange_bank_id(bank)"/>
|
||||
<field name="bank_name"/>
|
||||
<field name="bank_bic" placeholder="e.g. GEBABEBB"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
<field name="bank_ids" context="{'default_partner_id': active_id, 'form_view_ref': 'base.view_partner_bank_form'}">
|
||||
<tree string="Bank Details">
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="acc_number"/>
|
||||
|
@ -141,7 +114,7 @@
|
|||
context="{'search_default_partner_id':[active_id], 'default_partner_id': active_id}"
|
||||
src_model="res.partner"
|
||||
view_type="form"
|
||||
view_mode="tree,form,graph,calendar"/>
|
||||
view_mode="tree,form,calendar"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,graph,form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_analytic_account_tree"/>
|
||||
<field name="search_view_id" ref="account.view_account_analytic_account_search"/>
|
||||
</record>
|
||||
|
@ -114,9 +114,6 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem groups="analytic.group_analytic_accounting" id="next_id_40"
|
||||
name="Analytic" parent="account.menu_finance_generic_reporting"
|
||||
sequence="4"/>
|
||||
|
||||
<record id="view_account_analytic_line_form" model="ir.ui.view">
|
||||
<field name="name">account.analytic.line.form</field>
|
||||
|
@ -351,15 +348,6 @@
|
|||
# Reporting
|
||||
#
|
||||
|
||||
<record id="action_account_analytic_journal_tree" model="ir.actions.act_window">
|
||||
<field name="name">Print Analytic Journals</field>
|
||||
<field name="res_model">account.analytic.journal</field>
|
||||
<field name="view_type">tree</field>
|
||||
<field name="help">To print an analytics (or costs) journal for a given period. The report give code, move name, account number, general amount and analytic amount.</field>
|
||||
</record>
|
||||
<menuitem groups="analytic.group_analytic_accounting"
|
||||
action="action_account_analytic_journal_tree"
|
||||
id="account_analytic_journal_print" parent="account.next_id_40"/>
|
||||
|
||||
<record id="view_account_journal_1" model="ir.ui.view">
|
||||
<field name="name">account.journal.form.1</field>
|
||||
|
@ -372,16 +360,5 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="analytic_accounts_graph" model="ir.ui.view">
|
||||
<field name="name">analytic.accounts.graph</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Analytic Account Statistics" type="bar">
|
||||
<field name="complete_name"/>
|
||||
<field name="balance" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -29,6 +29,7 @@ class account_analytic_journal_report(osv.osv_memory):
|
|||
_columns = {
|
||||
'date1': fields.date('Start of period', required=True),
|
||||
'date2': fields.date('End of period', required=True),
|
||||
'analytic_account_journal_id': fields.many2many('account.analytic.journal', 'account_analytic_journal_name', 'journal_line_id', 'journal_print_id', 'Analytic Journals', required=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
|
@ -40,8 +41,15 @@ class account_analytic_journal_report(osv.osv_memory):
|
|||
if context is None:
|
||||
context = {}
|
||||
data = self.read(cr, uid, ids)[0]
|
||||
ids_list = []
|
||||
if context.get('active_id',False):
|
||||
ids_list.append(context.get('active_id',False))
|
||||
else:
|
||||
record = self.browse(cr,uid,ids[0],context=context)
|
||||
for analytic_record in record.analytic_account_journal_id:
|
||||
ids_list.append(analytic_record.id)
|
||||
datas = {
|
||||
'ids': context.get('active_ids',[]),
|
||||
'ids': ids_list,
|
||||
'model': 'account.analytic.journal',
|
||||
'form': data
|
||||
}
|
||||
|
@ -50,6 +58,14 @@ class account_analytic_journal_report(osv.osv_memory):
|
|||
'report_name': 'account.analytic.journal',
|
||||
'datas': datas,
|
||||
}
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
res = super(account_analytic_journal_report, self).default_get(cr, uid, fields, context=context)
|
||||
if 'analytic_account_journal_id' in fields:
|
||||
res.update({'analytic_account_journal_id': context.get('active_ids',[])})
|
||||
return res
|
||||
|
||||
account_analytic_journal_report()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -7,15 +7,16 @@
|
|||
<field name="model">account.analytic.journal.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Select Period" version="7.0">
|
||||
<header>
|
||||
<button name="check_report" string="Print" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</header>
|
||||
<group col="4">
|
||||
<field name="date1"/>
|
||||
<field name="date2"/>
|
||||
<field name="analytic_account_journal_id" widget="many2many_tags" class="oe_inline" required="1"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="check_report" string="Print" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -38,6 +39,13 @@
|
|||
<field name="key">action</field>
|
||||
<field name="model">account.analytic.journal</field>
|
||||
</record>
|
||||
|
||||
<menuitem groups="analytic.group_analytic_accounting" id="next_id_40"
|
||||
name="Analytic" parent="account.menu_finance_generic_reporting"
|
||||
sequence="4"/>
|
||||
<menuitem groups="analytic.group_analytic_accounting"
|
||||
action="account.action_account_analytic_journal"
|
||||
id="account_analytic_journal_print" parent="account.next_id_40"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -32,11 +32,11 @@ class account_invoice_refund(osv.osv_memory):
|
|||
_name = "account.invoice.refund"
|
||||
_description = "Invoice Refund"
|
||||
_columns = {
|
||||
'date': fields.date('Operation Date', help='This date will be used as the invoice date for credit note and period will be chosen accordingly!'),
|
||||
'date': fields.date('Date', help='This date will be used as the invoice date for credit note and period will be chosen accordingly!'),
|
||||
'period': fields.many2one('account.period', 'Force period'),
|
||||
'journal_id': fields.many2one('account.journal', 'Refund Journal', help='You can select here the journal to use for the credit note that will be created. If you leave that field empty, it will use the same journal as the current invoice.'),
|
||||
'description': fields.char('Description', size=128, required=True),
|
||||
'filter_refund': fields.selection([('refund', 'Create a draft refund'), ('cancel', 'Cancel: create credit note and reconcile'),('modify', 'Modify: create credit note, reconcile and create a new draft invoice')], "Refund Method", required=True, help='Credit note base on this type. You can not Modify and Cancel if the invoice is already reconciled'),
|
||||
'description': fields.char('Reason', size=128, required=True),
|
||||
'filter_refund': fields.selection([('refund', 'Create a draft credit note'), ('cancel', 'Cancel: create credit note and reconcile'),('modify', 'Modify: create credit note, reconcile and create a new draft invoice')], "Refund Method", required=True, help='Credit note base on this type. You can not Modify and Cancel if the invoice is already reconciled'),
|
||||
}
|
||||
|
||||
def _get_journal(self, cr, uid, context=None):
|
||||
|
|
|
@ -7,19 +7,40 @@
|
|||
<field name="model">account.invoice.refund</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Credit Note" version="7.0">
|
||||
<separator string="Credit Note Options"/>
|
||||
<group col="4">
|
||||
<field name="description"/>
|
||||
<field name="journal_id" widget='selection'/>
|
||||
<field name="date"/>
|
||||
<field name="period"/>
|
||||
<field name="filter_refund"/>
|
||||
<group>
|
||||
<group colspan="2">
|
||||
<label for="filter_refund"/>
|
||||
<div>
|
||||
<field name="filter_refund" class="oe_inline"/>
|
||||
<p attrs="{'invisible':[('filter_refund','<>','refund')]}" class="oe_grey">
|
||||
You will be able to edit and validate this
|
||||
credit note directly or keep it draft,
|
||||
waiting for the document to be issued by
|
||||
your supplier/customer.
|
||||
</p>
|
||||
<p attrs="{'invisible':[('filter_refund','<>','cancel')]}" class="oe_grey">
|
||||
Use this option if you want to cancel an invoice you should not
|
||||
have issued. The credit note will be created, validated and reconciled
|
||||
with the invoice. You will not be able to modify the credit note.
|
||||
</p>
|
||||
<p attrs="{'invisible':[('filter_refund','<>','modify')]}" class="oe_grey">
|
||||
Use this option if you want to cancel an invoice and create a new
|
||||
one. The credit note will be created, validated and reconciled
|
||||
with the current invoice. A new, draft, invoice will be created
|
||||
so that you can edit it.
|
||||
</p>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="description"/>
|
||||
<field name="journal_id" widget='selection'/>
|
||||
</group><group>
|
||||
<field name="date"/>
|
||||
<field name="period"/>
|
||||
</group>
|
||||
</group>
|
||||
<label string="Modify Invoice: Cancels the current invoice and creates a new copy of it ready for editing."/>
|
||||
<label string="Credit Note: Creates the credit note, ready for editing."/>
|
||||
<label string="Cancel Invoice: Creates the credit note, validate and reconcile it to cancel the current invoice."/>
|
||||
<footer>
|
||||
<button string='Refund' name="invoice_refund" type="object" class="oe_highlight"/>
|
||||
<button string='Create Credit Note' name="invoice_refund" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
|
@ -28,7 +49,7 @@
|
|||
</record>
|
||||
|
||||
<record id="action_account_invoice_refund" model="ir.actions.act_window">
|
||||
<field name="name">Refund</field>
|
||||
<field name="name">Refund Invoice</field>
|
||||
<field name="res_model">account.invoice.refund</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
|
|
|
@ -23,6 +23,7 @@ import time
|
|||
|
||||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
import decimal_precision as dp
|
||||
|
||||
class account_move_line_reconcile(osv.osv_memory):
|
||||
"""
|
||||
|
@ -32,9 +33,9 @@ class account_move_line_reconcile(osv.osv_memory):
|
|||
_description = 'Account move line reconcile'
|
||||
_columns = {
|
||||
'trans_nbr': fields.integer('# of Transaction', readonly=True),
|
||||
'credit': fields.float('Credit amount', readonly=True),
|
||||
'debit': fields.float('Debit amount', readonly=True),
|
||||
'writeoff': fields.float('Write-Off amount', readonly=True),
|
||||
'credit': fields.float('Credit amount', readonly=True, digits_compute=dp.get_precision('Account')),
|
||||
'debit': fields.float('Debit amount', readonly=True, digits_compute=dp.get_precision('Account')),
|
||||
'writeoff': fields.float('Write-Off amount', readonly=True, digits_compute=dp.get_precision('Account')),
|
||||
}
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<field name="name">Contracts to Renew</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,graph</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'search_default_user_id':uid, 'search_default_draft':1, 'search_default_pending':1, 'search_default_open':1, 'search_default_renew':1}</field>
|
||||
<field name="domain">[('type','=','contract')]</field>
|
||||
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
|
||||
|
@ -72,7 +72,7 @@
|
|||
<field name="name">Contracts</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,graph</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'default_type':'contract', 'search_default_open':1, 'search_default_pending':1}</field>
|
||||
<field name="domain">[('type','=','contract')]</field>
|
||||
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
|
||||
|
|
|
@ -350,7 +350,7 @@ class account_asset_depreciation_line(osv.osv):
|
|||
'amount': fields.float('Depreciation Amount', required=True),
|
||||
'remaining_value': fields.float('Amount to Depreciate', required=True),
|
||||
'depreciated_value': fields.float('Amount Already Depreciated', required=True),
|
||||
'depreciation_date': fields.char('Depreciation Date', size=64, select=1),
|
||||
'depreciation_date': fields.date('Depreciation Date', select=1),
|
||||
'move_id': fields.many2one('account.move', 'Depreciation Entry'),
|
||||
'move_check': fields.function(_get_move_check, method=True, type='boolean', string='Posted', store=True)
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ class account_asset_depreciation_line(osv.osv):
|
|||
for line in self.browse(cr, uid, ids, context=context):
|
||||
if currency_obj.is_zero(cr, uid, line.asset_id.currency_id, line.remaining_value):
|
||||
can_close = True
|
||||
depreciation_date = line.asset_id.prorata and line.asset_id.purchase_date or time.strftime('%Y-%m-%d')
|
||||
depreciation_date = time.strftime('%Y-%m-%d')
|
||||
period_ids = period_obj.find(cr, uid, depreciation_date, context=context)
|
||||
company_currency = line.asset_id.company_id.currency_id.id
|
||||
current_currency = line.asset_id.currency_id.id
|
||||
|
|
|
@ -57,6 +57,7 @@ class account_invoice_line(osv.osv):
|
|||
'partner_id': line.invoice_id.partner_id.id,
|
||||
'company_id': line.invoice_id.company_id.id,
|
||||
'currency_id': line.invoice_id.currency_id.id,
|
||||
'purchase_date' : line.invoice_id.date_invoice,
|
||||
}
|
||||
changed_vals = asset_obj.onchange_category_id(cr, uid, [], vals['category_id'], context=context)
|
||||
vals.update(changed_vals['value'])
|
||||
|
|
|
@ -50,7 +50,7 @@ class asset_asset_report(osv.osv):
|
|||
select
|
||||
min(dl.id) as id,
|
||||
dl.name as name,
|
||||
to_date(dl.depreciation_date, 'YYYY-MM-DD') as depreciation_date,
|
||||
dl.depreciation_date as depreciation_date,
|
||||
a.purchase_date as purchase_date,
|
||||
(CASE WHEN (select min(d.id) from account_asset_depreciation_line as d
|
||||
left join account_asset_asset as ac ON (ac.id=d.asset_id)
|
||||
|
@ -77,7 +77,7 @@ class asset_asset_report(osv.osv):
|
|||
from account_asset_depreciation_line dl
|
||||
left join account_asset_asset a on (dl.asset_id=a.id)
|
||||
group by
|
||||
dl.amount,dl.asset_id,to_date(dl.depreciation_date, 'YYYY-MM-DD'),dl.name,
|
||||
dl.amount,dl.asset_id,dl.depreciation_date,dl.name,
|
||||
a.purchase_date, dl.move_check, a.state, a.category_id, a.partner_id, a.company_id,
|
||||
a.purchase_value, a.id, a.salvage_value
|
||||
)""")
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
<field name="ref" readonly="1"/>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
|
||||
<field name="type" on_change="onchange_type(partner_id, type)"/>
|
||||
<field name="account_id" domain="[('journal_id','=',parent.journal_id)]"/>
|
||||
<field name="account_id" domain="[('journal_id','=',journal_id)]"/>
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '<>', 'view')]"/>
|
||||
<field name="amount" readonly="1" sum="Total Amount"/>
|
||||
<field name="globalisation_id" string="Glob. Id"/>
|
||||
|
@ -100,7 +100,7 @@
|
|||
<field name="ref" readonly="0"/>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
|
||||
<field name="type" on_change="onchange_type(partner_id, type)"/>
|
||||
<field domain="[('journal_id', '=', parent.journal_id), ('type', '<>', 'view')]" name="account_id"/>
|
||||
<field domain="[('journal_id', '=', journal_id), ('type', '<>', 'view')]" name="account_id"/>
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '<>', 'view')]"/>
|
||||
<field name="amount"/>
|
||||
<field name="globalisation_id"/>
|
||||
|
|
|
@ -88,7 +88,7 @@ class payment_order_create(osv.osv_memory):
|
|||
'partner_id': line.partner_id and line.partner_id.id or False,
|
||||
'communication': line.ref or '/',
|
||||
'date': date_to_pay,
|
||||
'currency': line.invoice and line.invoice.currency_id.id or False,
|
||||
'currency': (line.invoice and line.invoice.currency_id.id) or line.journal_id.currency.id or line.journal_id.company_id.currency_id.id,
|
||||
}, context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
|
@ -120,4 +120,4 @@ class payment_order_create(osv.osv_memory):
|
|||
|
||||
payment_order_create()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -32,11 +32,11 @@ class res_company(osv.osv):
|
|||
_columns = {
|
||||
'income_currency_exchange_account_id': fields.many2one(
|
||||
'account.account',
|
||||
string="Income Currency Rate",
|
||||
string="Gain Exchange Rate Account",
|
||||
domain="[('type', '=', 'other')]",),
|
||||
'expense_currency_exchange_account_id': fields.many2one(
|
||||
'account.account',
|
||||
string="Expense Currency Rate",
|
||||
string="Loss Exchange Rate Account",
|
||||
domain="[('type', '=', 'other')]",),
|
||||
}
|
||||
|
||||
|
@ -957,11 +957,11 @@ class account_voucher(osv.osv):
|
|||
if amount_residual > 0:
|
||||
account_id = line.voucher_id.company_id.expense_currency_exchange_account_id
|
||||
if not account_id:
|
||||
raise osv.except_osv(_('Warning!'),_("First you have to configure the 'Income Currency Rate' on the company, then create accounting entry for currency rate difference."))
|
||||
raise osv.except_osv(_('Warning!'),_("First you have to configure the 'Expense Currency Rate' on the company, then create accounting entry for currency rate difference."))
|
||||
else:
|
||||
account_id = line.voucher_id.company_id.income_currency_exchange_account_id
|
||||
if not account_id:
|
||||
raise osv.except_osv(_('Warning!'),_("First you have to configure the 'Expense Currency Rate' on the company, then create accounting entry for currency rate difference."))
|
||||
raise osv.except_osv(_('Warning!'),_("First you have to configure the 'Income Currency Rate' on the company, then create accounting entry for currency rate difference."))
|
||||
# Even if the amount_currency is never filled, we need to pass the foreign currency because otherwise
|
||||
# the receivable/payable account may have a secondary currency, which render this field mandatory
|
||||
account_currency_id = company_currency <> current_currency and current_currency or False
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -243,6 +243,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
@ -518,6 +519,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -146,6 +146,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
@ -301,6 +302,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -442,11 +442,13 @@ class audittrail_objects_proxy(object_proxy):
|
|||
|
||||
# if at least one modification has been found
|
||||
for model_id, resource_id in lines:
|
||||
name = pool.get(model.model).name_get(cr, uid, [resource_id])[0][1]
|
||||
vals = {
|
||||
'method': method,
|
||||
'object_id': model_id,
|
||||
'user_id': uid,
|
||||
'res_id': resource_id,
|
||||
'name': name,
|
||||
}
|
||||
if (model_id, resource_id) not in old_values and method not in ('copy', 'read'):
|
||||
# the resource was not existing so we are forcing the method to 'create'
|
||||
|
@ -484,7 +486,7 @@ class audittrail_objects_proxy(object_proxy):
|
|||
if len(rule['user_id']) == 0 or uid in rule['user_id']:
|
||||
if rule.get('log_'+method,0):
|
||||
return True
|
||||
elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'):
|
||||
elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create', 'read_group', 'import_data'):
|
||||
if rule['log_action']:
|
||||
return True
|
||||
|
||||
|
|
|
@ -180,8 +180,8 @@ class CompanyLDAP(osv.osv):
|
|||
"""
|
||||
|
||||
user_id = False
|
||||
login = tools.ustr(login)
|
||||
cr.execute("SELECT id, active FROM res_users WHERE login=%s", (login,))
|
||||
login = tools.ustr(login.lower())
|
||||
cr.execute("SELECT id, active FROM res_users WHERE lower(login)=%s", (login,))
|
||||
res = cr.fetchone()
|
||||
if res:
|
||||
if res[1]:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<field name="ldap_server"/>
|
||||
<field name="ldap_server_port"/>
|
||||
<field name="ldap_binddn"/>
|
||||
<field name="ldap_password"/>
|
||||
<field name="ldap_password" password="True"/>
|
||||
<field name="ldap_base"/>
|
||||
<field name="ldap_filter"/>
|
||||
<field name="create_user"/>
|
||||
|
|
|
@ -971,8 +971,8 @@ class calendar_event(osv.osv):
|
|||
event = datas['id']
|
||||
if datas.get('interval', 0) < 0:
|
||||
raise osv.except_osv(_('Warning!'), _('Interval cannot be negative.'))
|
||||
if datas.get('count', 0) < 0:
|
||||
raise osv.except_osv(_('Warning!'), _('Count cannot be negative.'))
|
||||
if datas.get('count', 0) <= 0:
|
||||
raise osv.except_osv(_('Warning!'), _('Count cannot be negative or 0.'))
|
||||
if datas['recurrency']:
|
||||
result[event] = self.compute_rule_string(datas)
|
||||
else:
|
||||
|
@ -1113,6 +1113,16 @@ rule or repeating pattern of time to exclude from the recurring rule."),
|
|||
'user_id': lambda self, cr, uid, ctx: uid,
|
||||
'organizer': default_organizer,
|
||||
}
|
||||
|
||||
def _check_closing_date(self, cr, uid, ids, context=None):
|
||||
for event in self.browse(cr, uid, ids, context=context):
|
||||
if event.date_deadline < event.date:
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_closing_date, 'Error ! End date cannot be set before start date.', ['date_deadline']),
|
||||
]
|
||||
|
||||
def get_recurrent_ids(self, cr, uid, select, domain, limit=100, context=None):
|
||||
"""Gives virtual event ids for recurring events based on value of Recurrence Rule
|
||||
|
|
|
@ -182,13 +182,14 @@
|
|||
<button name="do_tentative"
|
||||
states="needs-action,declined,accepted"
|
||||
string="Uncertain" type="object"
|
||||
icon="terp-crm"
|
||||
/>
|
||||
<button name="do_accept" string="Accept"
|
||||
states="needs-action,tentative,declined"
|
||||
type="object" />
|
||||
type="object" icon="gtk-apply"/>
|
||||
<button name="do_decline" string="Decline"
|
||||
states="needs-action,tentative,accepted"
|
||||
type="object" />
|
||||
type="object" icon="gtk-cancel"/>
|
||||
</tree>
|
||||
<form string="Invitation details" version="7.0">
|
||||
<header>
|
||||
|
@ -222,6 +223,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
<p class="oe_view_nocontent_create">
|
||||
Click to create an unqualified lead.
|
||||
</p><p>
|
||||
A lead is usually the first step in your sales cycle. It can be
|
||||
a contact with a new prospect, a company you target, a contact form
|
||||
filled in your website, etc.
|
||||
Use leads if you need a qualification step before creating an
|
||||
opportunity or a customer. It can be a business card you received,
|
||||
a contact form filled in your website, or a file of unqualified
|
||||
prospects you import, etc.
|
||||
</p><p>
|
||||
Once qualified, the lead can be converted into a business
|
||||
opportunity and a new customer in your address book.
|
||||
opportunity and/or a new customer in your address book.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -223,6 +223,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
@ -525,6 +526,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
id="crm_case_categ_phone_create_partner"
|
||||
name="Schedule a Call"
|
||||
res_model="crm.phonecall"
|
||||
view_mode="calendar,tree,form"
|
||||
context="{'search_default_partner_id': [active_id], 'default_duration': 1.0, 'default_partner_id': active_id}"
|
||||
view_mode="tree,form,calendar"
|
||||
context="{'search_default_partner_id': active_id, 'default_duration': 1.0, 'default_partner_id': active_id}"
|
||||
groups="base.group_sale_salesman"
|
||||
/>
|
||||
|
||||
|
|
|
@ -146,10 +146,10 @@
|
|||
<field name="priority"/>
|
||||
<field name="opportunity_id"/>
|
||||
</group>
|
||||
|
||||
<field name="description" placeholder="Description..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -26,12 +26,16 @@ class res_partner(osv.osv):
|
|||
_inherit = 'res.partner'
|
||||
|
||||
def _opportunity_meeting_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
for partner in self.browse(cr, uid, ids, context):
|
||||
res[partner.id] = {
|
||||
'opportunity_count': len(partner.opportunity_ids),
|
||||
'meeting_count': len(partner.meeting_ids),
|
||||
}
|
||||
res = dict(map(lambda x: (x,{'opportunity_count': 0, 'meeting_count': 0}), ids))
|
||||
# the user may not have access rights for opportunities or meetings
|
||||
try:
|
||||
for partner in self.browse(cr, uid, ids, context):
|
||||
res[partner.id] = {
|
||||
'opportunity_count': len(partner.opportunity_ids),
|
||||
'meeting_count': len(partner.meeting_ids),
|
||||
}
|
||||
except:
|
||||
pass
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
<field name="src_model">res.partner</field>
|
||||
<field name="res_model">crm.meeting</field>
|
||||
<field name="view_mode">calendar,tree,form,gantt</field>
|
||||
<field name="context">{'search_default_partner_ids': active_id}</field>
|
||||
<field name="context">{'default_partner_ids': [active_id]}</field>
|
||||
</record>
|
||||
|
||||
<!-- open opportunities related to given partner -->
|
||||
|
|
|
@ -181,6 +181,7 @@
|
|||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
@ -241,7 +242,7 @@
|
|||
<attribute name="invisible">False</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='page_history']" position="inside">
|
||||
<group name="grp_claim" string="Claim">
|
||||
<group name="grp_claim" string="Claims">
|
||||
<field name="claims_ids" colspan="4" nolabel="1">
|
||||
<tree string="Partners Claim" editable="bottom">
|
||||
<field name="name"/>
|
||||
|
|
|
@ -61,10 +61,6 @@
|
|||
on_change="onchange_partner_id(partner_id, email_from)"
|
||||
/>
|
||||
<field name="email_from"/>
|
||||
<button name="remind_partner"
|
||||
states="open,pending"
|
||||
string="Send Reminder" type="object"
|
||||
icon="gtk-go-forward" />
|
||||
</group>
|
||||
<group string="Categorization">
|
||||
<field name="priority"/>
|
||||
|
@ -99,6 +95,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -124,7 +124,7 @@
|
|||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="inside">
|
||||
<page string="Profiling">
|
||||
<page string="Profiling" groups="base.group_user">
|
||||
<button string="Use a questionnaire"
|
||||
name="%(action_open_questionnaire)d" type="action" colspan="1"
|
||||
icon="gtk-justify-fill" />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_crm_profiling_answer_salesman,crm_profiling.answer.salesman,model_crm_profiling_answer,base.group_sale_salesman,1,1,1,0
|
||||
access_crm_profiling_answer_manager,crm_profiling.answer.manager,model_crm_profiling_answer,base.group_sale_manager,1,1,1,1
|
||||
access_crm_profiling_answer_user,crm_profiling.answer.user,model_crm_profiling_answer,base.group_user,1,0,0,0
|
||||
access_crm_profiling_question_salesman,crm_profiling.question.salesman,model_crm_profiling_question,base.group_sale_salesman,1,1,1,0
|
||||
access_crm_profiling_question_manager,crm_profiling.question.manager,model_crm_profiling_question,base.group_sale_manager,1,1,1,1
|
||||
access_crm_profiling_questionnarie_salesman,crm_profiling.questionnarie.salesman,model_crm_profiling_questionnaire,base.group_sale_salesman,1,1,1,0
|
||||
|
|
|
|
@ -230,6 +230,10 @@
|
|||
<field name="carrier_tracking_ref"/>
|
||||
<field name="number_of_packages"/>
|
||||
</field>
|
||||
<field name="company_id" position="before">
|
||||
<field name="weight"/>
|
||||
<field name="weight_net" groups="base.group_no_one"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
@ -307,13 +311,26 @@
|
|||
<record id="view_delivery_order_inherit_stock" model="ir.ui.view">
|
||||
<field name="name">stock.picking.out.form</field>
|
||||
<field name="model">stock.picking.out</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_out_form"/>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/header//button[@string='Create Invoice/Refund']" position="after">
|
||||
<button name="%(report_shipping)d" string="Delivery Order" states="done" type="action" icon="gtk-print"/>
|
||||
<xpath expr="/form/header//button[@name='action_process']" position="after">
|
||||
<button name="%(report_shipping)d" string="Print Delivery Order" states="confirmed,assigned" type="action"/>
|
||||
<button name="%(report_shipping)d" string="Print Delivery Order" states="done" type="action" class="oe_highlight"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="view_picking_withcarrier_in_form" model="ir.ui.view">
|
||||
<field name="name">delivery.stock.picking_withcarrier.in.form.view</field>
|
||||
<field name="type">form</field>
|
||||
<field name="model">stock.picking.in</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_id" position="before">
|
||||
<field name="weight"/>
|
||||
<field name="weight_net" groups="base.group_no_one"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -202,5 +202,30 @@ class stock_picking_out(osv.osv):
|
|||
'carrier_tracking_ref': fields.char('Carrier Tracking Ref', size=32),
|
||||
'number_of_packages': fields.integer('Number of Packages'),
|
||||
}
|
||||
stock_picking_out()
|
||||
|
||||
class stock_picking_in(osv.osv):
|
||||
_inherit = 'stock.picking.in'
|
||||
|
||||
def _cal_weight(self, cr, uid, ids, name, args, context=None):
|
||||
return self.pool.get('stock.picking')._cal_weight(cr, uid, ids, name, args, context=context)
|
||||
|
||||
def _get_picking_line(self, cr, uid, ids, context=None):
|
||||
return self.pool.get('stock.picking')._get_picking_line(cr, uid, ids, context=context)
|
||||
|
||||
_columns = {
|
||||
'weight': fields.function(_cal_weight, type='float', string='Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_weight',
|
||||
store={
|
||||
'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['move_lines'], 20),
|
||||
'stock.move': (_get_picking_line, ['product_id','product_qty','product_uom','product_uos_qty'], 20),
|
||||
}),
|
||||
'weight_net': fields.function(_cal_weight, type='float', string='Net Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_weight',
|
||||
store={
|
||||
'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['move_lines'], 20),
|
||||
'stock.move': (_get_picking_line, ['product_id','product_qty','product_uom','product_uos_qty'], 20),
|
||||
}),
|
||||
}
|
||||
stock_picking_in()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class document_ftp_browse(osv.osv_memory):
|
|||
data_pool = self.pool.get('ir.model.data')
|
||||
aid = data_pool._get_id(cr, uid, 'document_ftp', 'action_document_browse')
|
||||
aid = data_pool.browse(cr, uid, aid, context=context).res_id
|
||||
ftp_url = self.pool.get('ir.actions.url').browse(cr, uid, aid, context=context)
|
||||
ftp_url = self.pool.get('ir.actions.act_url').browse(cr, uid, aid, context=context)
|
||||
url = ftp_url.url and ftp_url.url.split('ftp://') or []
|
||||
if url:
|
||||
url = url[1]
|
||||
|
|
|
@ -44,7 +44,7 @@ class document_ftp_configuration(osv.osv_memory):
|
|||
# Update the action for FTP browse.
|
||||
aid = data_pool._get_id(cr, uid, 'document_ftp', 'action_document_browse')
|
||||
aid = data_pool.browse(cr, uid, aid, context=context).res_id
|
||||
self.pool.get('ir.actions.url').write(cr, uid, [aid],
|
||||
self.pool.get('ir.actions.act_url').write(cr, uid, [aid],
|
||||
{'url': 'ftp://'+(conf.host or 'localhost:8021')+'/' + cr.dbname+'/'})
|
||||
|
||||
document_ftp_configuration()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.actions.url" id="action_document_browse">
|
||||
<record model="ir.actions.act_url" id="action_document_browse">
|
||||
<field name="name">Browse Files</field>
|
||||
<field name="url">ftp://localhost:8021/</field>
|
||||
</record>
|
||||
|
|
|
@ -196,6 +196,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
@ -246,12 +247,12 @@
|
|||
<t t-name="kanban-box">
|
||||
<div class="oe_module_vignette">
|
||||
<a type="open" class="oe_module_icon">
|
||||
<div class="oe_event_date "><t t-esc="record.date_begin.raw_value.getDate()"/></div>
|
||||
<div class="oe_event_month_year">
|
||||
<t t-esc="record.date_begin.raw_value.toString('MMM')"/>
|
||||
<t t-esc="record.date_begin.raw_value.getFullYear()"/>
|
||||
</div>
|
||||
<div class="oe_event_time"><t t-esc="record.date_begin.raw_value.toString('hh:mm tt')"/></div>
|
||||
<div class="oe_event_date "><t t-esc="record.date_begin.raw_value.getDate()"/></div>
|
||||
<div class="oe_event_month_year">
|
||||
<t t-esc="record.date_begin.raw_value.toString('MMM')"/>
|
||||
<t t-esc="record.date_begin.raw_value.getFullYear()"/>
|
||||
</div>
|
||||
<div class="oe_event_time"><t t-esc="record.date_begin.raw_value.toString('hh:mm tt')"/></div>
|
||||
</a>
|
||||
<div class="oe_module_desc">
|
||||
<h4><a type="open"><field name="name"/></a></h4>
|
||||
|
@ -271,10 +272,10 @@
|
|||
</p>
|
||||
<t t-if="record.register_avail.raw_value != 0">
|
||||
<t t-if="!record.is_subscribed.raw_value">
|
||||
<input t-att-id="record.id.raw_value" type="text" name="subscribe" class="no_of_seats" value="1" onchange="document.getElementById('btn_sub' +this.id).setAttribute('data-context',JSON.stringify({'ticket':this.value}))"/>
|
||||
<button t-att-id="'btn_sub'+record.id.raw_value" type="object" name="subscribe_to_event" class="oe_mail_button_follow">
|
||||
<span >Subscribe</span>
|
||||
</button>
|
||||
<input t-att-id="record.id.raw_value" type="text" name="subscribe" class="no_of_seats" value="1" onchange="document.getElementById('btn_sub' +this.id).setAttribute('data-context',JSON.stringify({'ticket':this.value}))"/>
|
||||
<button t-att-id="'btn_sub'+record.id.raw_value" type="object" name="subscribe_to_event" class="oe_mail_button_follow">
|
||||
<span >Subscribe</span>
|
||||
</button>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="record.is_subscribed.raw_value">
|
||||
|
@ -478,6 +479,7 @@
|
|||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<attribute name="invisible">False</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='page_history']" position="inside">
|
||||
<group name="grp_event" string="Event">
|
||||
<group name="grp_event" string="Events">
|
||||
<field name="event_ids" colspan="4" nolabel="1">
|
||||
<tree string="Events">
|
||||
<field name="name" string="Event"/>
|
||||
|
@ -24,7 +24,7 @@
|
|||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
<group name="grp_registration" string="Registration">
|
||||
<group name="grp_registration" string="Registrations">
|
||||
<field name="event_registration_ids" colspan="4" nolabel="1">
|
||||
<tree string="Events Registration">
|
||||
<field name="event_begin_date" string="Date"/>
|
||||
|
|
|
@ -195,7 +195,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS
|
|||
strip_attachments=(not server.attach),
|
||||
context=context)
|
||||
if res_id and server.action_id:
|
||||
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]})
|
||||
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id], 'active_model': context.get("thread_model", False)})
|
||||
imap_server.store(num, '+FLAGS', '\\Seen')
|
||||
cr.commit()
|
||||
count += 1
|
||||
|
@ -220,7 +220,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS
|
|||
strip_attachments=(not server.attach),
|
||||
context=context)
|
||||
if res_id and server.action_id:
|
||||
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]})
|
||||
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id], 'active_model': context.get("thread_model", False)})
|
||||
pop_server.dele(num)
|
||||
cr.commit()
|
||||
_logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name)
|
||||
|
|
|
@ -205,25 +205,6 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="open_view_employee_list_my_kanban" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
<field name="view_mode">kanban</field>
|
||||
<field name="act_window_id" ref="open_view_employee_list_my"/>
|
||||
</record>
|
||||
<record id="open_view_employee_list_my_tree2" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="view_employee_tree"/>
|
||||
<field name="act_window_id" ref="open_view_employee_list_my"/>
|
||||
</record>
|
||||
|
||||
<record id="open_view_employee_list_my_form2" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="view_employee_form"/>
|
||||
<field name="act_window_id" ref="open_view_employee_list_my"/>
|
||||
</record>
|
||||
|
||||
<menuitem action="open_view_employee_list_my" id="menu_open_view_employee_list_my" sequence="3" parent="menu_hr_main"/>
|
||||
|
||||
<record id="ir_ui_view_sc_employee" model="ir.ui.view_sc">
|
||||
|
@ -372,14 +353,14 @@
|
|||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Description">
|
||||
<label for="description"/>
|
||||
<field name="description"/>
|
||||
<label for="requirements"/>
|
||||
<field name="requirements"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<div>
|
||||
<label for="description"/>
|
||||
<field name="description"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="requirements"/>
|
||||
<field name="requirements"/>
|
||||
</div>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
<field nolabel="1" name="survey_request_ids">
|
||||
<form string="Interview Appraisal" version="7.0">
|
||||
<div class="oe_right oe_button_box">
|
||||
<button name="%(survey.action_view_survey_question_message)d" string="Answer Survey" type="action" states="waiting_answer,done,cancel" icon="gtk-execute" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0, 'active' : response,'request' : True, 'object' : 'hr.evaluation.interview', 'cur_id' : active_id}" attrs="{'readonly':[('survey_id','=',False)]}"/>
|
||||
<button name="%(survey.action_view_survey_question_message)d" string="Answer Survey" type="action" states="waiting_answer" icon="gtk-execute" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0, 'active' : response,'request' : True, 'object' : 'hr.evaluation.interview', 'cur_id' : active_id}" attrs="{'readonly':[('survey_id','=',False)]}"/>
|
||||
<button name="%(survey.survey_browse_response)d" string="Print Interview" type="action" states="done" icon="gtk-print" context="{'survey_id': survey_id, 'response_id' : [response], 'response_no':0,}" attrs="{'readonly':[('response','=',False)]}" />
|
||||
</div>
|
||||
<group>
|
||||
|
@ -333,7 +333,7 @@
|
|||
<field name="user_id" string="Interviewer"/>
|
||||
<field name="user_to_review_id"/>
|
||||
<field name="response" readonly="1" invisible="True"/>
|
||||
<button name="%(survey.action_view_survey_question_message)d" string="Answer Survey" type="action" states="waiting_answer,done,cancel" icon="gtk-execute" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0, 'active' : response, 'request' : True, 'object' : 'hr.evaluation.interview', 'cur_id' : active_id}" attrs="{'readonly':[('survey_id','=',False)]}"/>
|
||||
<button name="%(survey.action_view_survey_question_message)d" string="Answer Survey" type="action" states="waiting_answer" icon="gtk-execute" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0, 'active' : response, 'request' : True, 'object' : 'hr.evaluation.interview', 'cur_id' : active_id}" attrs="{'readonly':[('survey_id','=',False)]}"/>
|
||||
<button name="action_print_survey" string="Print Survey" type="object" icon="gtk-print" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0}" attrs="{'readonly':[('survey_id','=',False)]}"/>
|
||||
<button name="%(mail.action_email_compose_message_wizard)d" string="Send Reminder Email" icon="terp-mail-message-new" type="action" states="waiting_answer"/>
|
||||
<field name="state"/>
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -121,6 +121,7 @@
|
|||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
@ -158,6 +159,7 @@
|
|||
<field name="notes" nolabel="1" colspan="4" placeholder="Add a reason..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -317,7 +317,10 @@ class hr_payslip(osv.osv):
|
|||
'company_id': company_id,
|
||||
'period_id': False,
|
||||
'basic_before_leaves': 0.0,
|
||||
'basic_amount': 0.0
|
||||
'basic_amount': 0.0,
|
||||
'number': '',
|
||||
'payslip_run_id': False,
|
||||
'paid': False,
|
||||
})
|
||||
return super(hr_payslip, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@
|
|||
</h2>
|
||||
</div>
|
||||
<group col="4">
|
||||
<field name="contract_id" domain="[('employee_id','=',employee_id)]" on_change="onchange_contract_id(date_from, date_to, employee_id, contract_id)" context="{'default_employee_id': employee_id}"/>
|
||||
<field name="contract_id" domain="[('employee_id','=',employee_id),('date_start','<=',date_to),'|',('date_end','>=',date_from),('date_end','=',False)]" on_change="onchange_contract_id(date_from, date_to, employee_id, contract_id)" context="{'default_employee_id': employee_id}"/>
|
||||
<field name="number"/>
|
||||
<field name="struct_id" attrs="{'required':[('contract_id','<>',False)]}"/>
|
||||
<field name="name"/>
|
||||
|
|
|
@ -183,6 +183,7 @@
|
|||
<field name="description" placeholder="Feedback of interviews..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -8,5 +8,5 @@ access_survey_hr_user,survey.hr.user,survey.model_survey,base.group_hr_user,1,1,
|
|||
access_crm_meeting_hruser,crm.meeting.hruser,base_calendar.model_crm_meeting,base.group_hr_user,1,1,1,1
|
||||
access_hr_recruitment_source_hr_officer,hr.recruitment.source,model_hr_recruitment_source,base.group_hr_user,1,1,1,1
|
||||
access_hr_recruitment_source_all,hr.recruitment.source,model_hr_recruitment_source,,1,0,0,0
|
||||
access_hr_applicant_category,hr.applicant_category,model_hr_applicant_category,,1,0,0,0
|
||||
access_hr_applicant_category,hr.applicant_category,model_hr_applicant_category,,1,1,1,0
|
||||
access_hr_applicant_category_manager,hr.applicant_category,model_hr_applicant_category,base.group_hr_manager,1,1,1,1
|
||||
|
|
|
|
@ -116,10 +116,12 @@
|
|||
<field name="search_view_id" ref="hr_timesheet_line_search"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to your timesheets.
|
||||
Click to record your timesheets.
|
||||
</p><p>
|
||||
Through this menu you can register and follow your workings
|
||||
hours by project every day.
|
||||
You can register and track your workings hours by project every
|
||||
day. Every time spent on a project will become a cost in the
|
||||
analytic accounting and can be re-invoiced to customers if
|
||||
required.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_hr_analytic_timesheet,hr.analytic.timesheet,model_hr_analytic_timesheet,base.group_hr_user,1,1,1,1
|
||||
access_hr_analytic_timesheet_employee,hr.analytic.timesheet,model_hr_analytic_timesheet,base.group_user,1,1,1,0
|
||||
access_hr_analytic_timesheet_employee,hr.analytic.timesheet,model_hr_analytic_timesheet,base.group_user,1,1,1,1
|
||||
access_hr_account_analytic_line,account.account.analytic.line,account.model_account_analytic_line,base.group_hr_user,1,1,1,1
|
||||
access_hr_account_analytic_line_employee,account.account.analytic.line employee,account.model_account_analytic_line,base.group_user,1,1,1,0
|
||||
access_hr_account_analytic_line_employee,account.account.analytic.line employee,account.model_account_analytic_line,base.group_user,1,1,1,1
|
||||
access_account_analytic_journal,account.account.analytic.journal,account.model_account_analytic_journal,base.group_hr_user,1,1,1,1
|
||||
access_product_product_user,product.product user,product.model_product_product,base.group_hr_user,1,1,1,1
|
||||
access_product_template_hr_timesheet,product.template.hr.timesheet,product.model_product_template,base.group_hr_user,1,1,1,1
|
||||
|
|
|
|
@ -31,7 +31,7 @@ class report_timesheet_line(osv.osv):
|
|||
'user_id': fields.many2one('res.users', 'User', readonly=True),
|
||||
'date': fields.date('Date', readonly=True),
|
||||
'day': fields.char('Day', size=128, readonly=True),
|
||||
'quantity': fields.float('Quantity', readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'cost': fields.float('Cost', readonly=True),
|
||||
'product_id': fields.many2one('product.product', 'Product',readonly=True),
|
||||
'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
|
||||
|
@ -83,7 +83,7 @@ class report_timesheet_user(osv.osv):
|
|||
_columns = {
|
||||
'name': fields.char('Year',size=64,required=False, readonly=True),
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'quantity': fields.float('Quantity', readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'cost': fields.float('Cost', readonly=True),
|
||||
'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),
|
||||
|
@ -117,7 +117,7 @@ class report_timesheet_account(osv.osv):
|
|||
'name': fields.char('Year',size=64,required=False, readonly=True),
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'account_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
|
||||
'quantity': fields.float('Quantity', readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'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),
|
||||
|
||||
|
@ -151,7 +151,7 @@ class report_timesheet_account_date(osv.osv):
|
|||
'name': fields.char('Year',size=64,required=False, readonly=True),
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'account_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
|
||||
'quantity': fields.float('Quantity', readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'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),
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ class report_timesheet_invoice(osv.osv):
|
|||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'account_id':fields.many2one('account.analytic.account', 'Project', readonly=True),
|
||||
'manager_id':fields.many2one('res.users', 'Manager', readonly=True),
|
||||
'quantity': fields.float('Quantity', readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'amount_invoice': fields.float('To invoice', readonly=True)
|
||||
}
|
||||
_rec_name = 'user_id'
|
||||
|
|
|
@ -79,17 +79,24 @@ class account_analytic_line(osv.osv):
|
|||
curr_invoice = {
|
||||
'name': time.strftime('%d/%m/%Y')+' - '+account.name,
|
||||
'partner_id': account.partner_id.id,
|
||||
'company_id': account.company_id.id,
|
||||
'payment_term': partner.property_payment_term.id or False,
|
||||
'account_id': partner.property_account_receivable.id,
|
||||
'currency_id': account.pricelist_id.currency_id.id,
|
||||
'date_due': date_due,
|
||||
'fiscal_position': account.partner_id.property_account_position.id
|
||||
}
|
||||
last_invoice = invoice_obj.create(cr, uid, curr_invoice, context=context)
|
||||
invoices.append(last_invoice)
|
||||
|
||||
|
||||
context2 = context.copy()
|
||||
context2['lang'] = partner.lang
|
||||
# set company_id in context, so the correct default journal will be selected
|
||||
context2['force_company'] = curr_invoice['company_id']
|
||||
# set force_company in context so the correct product properties are selected (eg. income account)
|
||||
context2['company_id'] = curr_invoice['company_id']
|
||||
|
||||
last_invoice = invoice_obj.create(cr, uid, curr_invoice, context=context2)
|
||||
invoices.append(last_invoice)
|
||||
|
||||
cr.execute("SELECT product_id, to_invoice, sum(unit_amount), product_uom_id, name " \
|
||||
"FROM account_analytic_line as line " \
|
||||
"WHERE account_id = %s " \
|
||||
|
@ -115,11 +122,11 @@ class account_analytic_line(osv.osv):
|
|||
else:
|
||||
price = 0.0
|
||||
|
||||
general_account = product.product_tmpl_id.property_account_income or product.categ_id.property_account_income_categ
|
||||
if not general_account:
|
||||
raise osv.except_osv(_("Configuration Error!"), _("Please define income account for product '%s'.") % product.name)
|
||||
taxes = product.taxes_id
|
||||
tax = fiscal_pos_obj.map_tax(cr, uid, account.partner_id.property_account_position, taxes)
|
||||
account_id = product.product_tmpl_id.property_account_income.id or product.categ_id.property_account_income_categ.id
|
||||
if not account_id:
|
||||
raise osv.except_osv(_("Configuration Error!"), _("Please define income account for product '%s'.") % product.name)
|
||||
curr_line = {
|
||||
'price_unit': price,
|
||||
'quantity': qty,
|
||||
|
@ -130,7 +137,7 @@ class account_analytic_line(osv.osv):
|
|||
'product_id': product_id,
|
||||
'invoice_line_tax_id': [(6,0,tax)],
|
||||
'uos_id': uom,
|
||||
'account_id': account_id,
|
||||
'account_id': general_account.id,
|
||||
'account_analytic_id': account.id,
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class hr_timesheet_report(osv.osv):
|
|||
'account_id': fields.many2one('account.analytic.account', 'Analytic Account',readonly=True),
|
||||
'company_id': fields.many2one('res.company', 'Company',readonly=True),
|
||||
'cost': fields.float('Cost',readonly=True, digits_compute=dp.get_precision('Account')),
|
||||
'quantity': fields.float('Quantity',readonly=True),
|
||||
'quantity': fields.float('Time',readonly=True),
|
||||
}
|
||||
|
||||
def init(self, cr):
|
||||
|
|
|
@ -52,7 +52,7 @@ class timesheet_report(osv.osv):
|
|||
('draft','Draft'),
|
||||
('confirm','Confirmed'),
|
||||
('done','Done')], 'Status', readonly=True),
|
||||
'quantity': fields.float('#Quantity',readonly=True),
|
||||
'quantity': fields.float('Time',readonly=True),
|
||||
'cost': fields.float('#Cost',readonly=True),
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
<field name="description"/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<group>
|
||||
<field name='name'/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Close" class="oe_highlight" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -27,6 +27,7 @@ from dateutil import *
|
|||
from pytz import timezone
|
||||
from datetime import datetime
|
||||
import time
|
||||
import base64
|
||||
from osv import *
|
||||
from tools.translate import _
|
||||
|
||||
|
@ -282,7 +283,7 @@ class google_import(import_framework):
|
|||
self.contact = self.gd_client.GetContactsFeed()
|
||||
while self.contact:
|
||||
for entry in self.contact.entry:
|
||||
data = {}
|
||||
data = {}
|
||||
data['id'] = entry.id.text
|
||||
name = tools.ustr(entry.title.text)
|
||||
if name == "None":
|
||||
|
@ -290,6 +291,8 @@ class google_import(import_framework):
|
|||
data['name'] = name or _('Unknown')
|
||||
emails = ','.join(email.address for email in entry.email)
|
||||
data['email'] = emails
|
||||
if self.gd_client.GetPhoto(entry):
|
||||
data['image'] = base64.encodestring(self.gd_client.GetPhoto(entry))
|
||||
if table == 'Contact':
|
||||
data.update({'customer': str(self.context.get('customer')),
|
||||
'supplier': str(self.context.get('supplier'))})
|
||||
|
@ -322,6 +325,12 @@ class google_import(import_framework):
|
|||
'name': value('company', fallback='name'),
|
||||
'customer': 'customer',
|
||||
'supplier': 'supplier',
|
||||
'city': 'city',
|
||||
'phone': 'phone',
|
||||
'mobile': 'mobile',
|
||||
'email': 'email',
|
||||
'image': 'image',
|
||||
'fax': 'fax',
|
||||
'child_ids/id': ref(self.TABLE_ADDRESS, 'id'),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ class synchronize_google(osv.osv_memory):
|
|||
_columns = {
|
||||
'customer': fields.boolean('Customer', help="Check this box to set newly created partner as Customer."),
|
||||
'supplier': fields.boolean('Supplier', help="Check this box to set newly created partner as Supplier."),
|
||||
'group_name': fields.selection(_get_group, "Group Name",help="Choose which group to import, By default it takes all."),
|
||||
'group_name': fields.selection(_get_group, "Group Name", help="Choose which group to import, By default it takes all."),
|
||||
'calendar_name': fields.selection(_get_calendars, "Calendar Name"),
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Import contacts from a google account" version="7.0">
|
||||
<group colspan="4" col="4" width="430">
|
||||
<field name="group_name" colspan="4"/>
|
||||
<field name="group_name" colspan="4" required="1"/>
|
||||
<newline/>
|
||||
<group colspan="4" col="4">
|
||||
<separator string="Partner Status for this Group:" colspan="4"/>
|
||||
|
@ -32,7 +32,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Import Google Calendar Events" version="7.0">
|
||||
<group colspan="4" col="4" width="320">
|
||||
<field name="calendar_name" />
|
||||
<field name="calendar_name" required="1"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="import_google" string="_Import Events" type="object" class="oe_highlight" />
|
||||
|
|
|
@ -70,7 +70,7 @@ class partner_vat(osv.osv_memory):
|
|||
FROM account_move_line l
|
||||
LEFT JOIN res_partner p ON l.partner_id = p.id
|
||||
LEFT JOIN account_tax_code c ON l.tax_code_id = c.id
|
||||
WHERE c.code IN ('01','02','03','45','49')
|
||||
WHERE c.code IN ('00','01','02','03','45','49')
|
||||
AND l.partner_id IN %s
|
||||
AND l.period_id IN %s
|
||||
GROUP BY l.partner_id, p.name, p.vat) AS sub1
|
||||
|
|
|
@ -36,8 +36,9 @@ class WizardMultiChartsAccounts(osv.osv_memory):
|
|||
def execute(self, cr, uid, ids, context=None):
|
||||
"""Override of code in order to be able to link journal with account in XML"""
|
||||
res = super(WizardMultiChartsAccounts, self).execute(cr, uid, ids, context)
|
||||
path = addons.get_module_resource(os.path.join('l10n_ch','sterchi_chart','account_journal_rel.xml'))
|
||||
path = addons.get_module_resource('l10n_ch','sterchi_chart','account_journal_rel.xml')
|
||||
tools.convert_xml_import(cr, 'l10n_ch', path, idref=None, mode='init', noupdate=True, report=None)
|
||||
res.update({'type': 'ir.actions.act_window_close'})
|
||||
return res
|
||||
|
||||
WizardMultiChartsAccounts()
|
||||
|
|
|
@ -48,7 +48,7 @@ class ResPartnerBank(osv.osv):
|
|||
'dta_code': fields.char('DTA code', size=5),
|
||||
'print_bank': fields.boolean('Print Bank on BVR'),
|
||||
'print_account': fields.boolean('Print Account Number on BVR'),
|
||||
'acc_number': fields.char('Account/IBAN Number', size=64),
|
||||
'acc_number': fields.char('Account Number', size=64),
|
||||
'my_bank': fields.boolean('Use my account to print BVR ?', help="Check to print BVR invoices"),
|
||||
}
|
||||
|
||||
|
|
|
@ -28,34 +28,6 @@
|
|||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- res.partner.bank in res partner form-->
|
||||
<!-- Partner -> Bank Details -->
|
||||
|
||||
<record model="ir.ui.view" id="l10nch_view_res_partner_bank_add_groups">
|
||||
<field name="name">res.partner_bank.form.hide.f2</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="account.view_partner_property_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="after">
|
||||
<newline/>
|
||||
<separator colspan="4" string="Account Infos"/>
|
||||
<group string="Bank account info" colspan="4" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}" >
|
||||
<field name="acc_number" string="Account/IBAN Number" attrs="{'required': [('state','not in',['bvpost','bvrpost'])]}"/>
|
||||
<field name="dta_code"/>
|
||||
<newline/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group string="Postal account info" colspan="4" attrs="{'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}" >
|
||||
<field name="post_number" attrs="{'required': [('state','in',['bvpost','bvrpost','bvrbank'])]}"/>
|
||||
<newline/>
|
||||
</group>
|
||||
<separator colspan="4" string="Financial Institute Infos"/>
|
||||
<field name="bank" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- res.partner.bank base form-->
|
||||
<!-- Sales -> Configuration -> Address Book -> Bank accounts -->
|
||||
|
@ -66,35 +38,21 @@
|
|||
<field name="model">res.partner.bank</field>
|
||||
<field name="inherit_id" ref="base.view_partner_bank_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="after">
|
||||
<newline/>
|
||||
|
||||
<separator colspan="4" string="Account Infos"/>
|
||||
<newline/>
|
||||
<group string="Bank account info" colspan="4" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}" >
|
||||
<field name="acc_number" string="Account/IBAN Number" attrs="{'required': [('state','not in',['bvpost','bvrpost'])]}"/>
|
||||
<field name="dta_code"/>
|
||||
<newline/>
|
||||
<xpath expr="//field[@name='acc_number']" position="attributes">
|
||||
<attribute name="attrs">{'required': [('state','not in',['bvpost','bvrpost'])]}</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='acc_number']" position="after">
|
||||
<field name="post_number" attrs="{'required': [('state','in',['bvpost','bvrpost','bvrbank'])], 'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}"/>
|
||||
<field name="dta_code" attrs="{'invisible': [('state','in', ['bvpost','bvrpost'])]}"/>
|
||||
<field name="my_bank" attrs="{'invisible': ['|', ('state', 'not in', ['bvrpost','bvrbank']), ('company_id', '=', False)]}" />
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='bank']" position="after">
|
||||
<group string="BVR print options" attrs="{'invisible': [('my_bank', '!=', True)]}" >
|
||||
<field name="bvr_adherent_num" attrs="{'invisible': [('state','!=','bvrbank')]}"/>
|
||||
<field name="print_bank"/>
|
||||
<field name="print_account"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group string="Postal account info" colspan="4" attrs="{'invisible': [('state','not in', ['bvpost','bvrpost','bvbank','bvrbank'])]}" >
|
||||
<field name="post_number" attrs="{'required': [('state','in',['bvpost','bvrpost','bvrbank'])]}"/>
|
||||
<newline/>
|
||||
</group>
|
||||
<separator colspan="4" string="Financial Institute Infos"/>
|
||||
<newline/>
|
||||
<group attrs="{'invisible': ['|', ('state', 'not in', ['bvrpost','bvrbank']), ('company_id', '=', False)]}" colspan="4">
|
||||
<field name="my_bank" attrs="{'invisible': [('company_id', '=', False)]}" />
|
||||
<group string="BVR print options" colspan="4" attrs="{'invisible': [('my_bank', '!=', True)]}" >
|
||||
<field name="bvr_adherent_num" attrs="{'invisible': [('state','!=','bvrbank')]}"/>
|
||||
<field name="print_bank"/>
|
||||
<field name="print_account"/>
|
||||
<newline/>
|
||||
</group>
|
||||
</group>
|
||||
<newline/>
|
||||
<field name="bank" />
|
||||
</field>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@
|
|||
<field name="type">view</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="parent_id" ref="a1"/>
|
||||
<field name="parent_id" ref="a20"/>
|
||||
</record>
|
||||
|
||||
<!-- <record model="account.account.template" id="290">
|
||||
|
|
|
@ -3955,11 +3955,13 @@
|
|||
<field name="code">4a</field>
|
||||
<field name="parent_id" ref="btw_code_vanuit_buitenland"/>
|
||||
<field name="name">Leveringen uit landen buiten de EU (invoer) (BTW)</field>
|
||||
<field name="sign" eval="-1" />
|
||||
</record>
|
||||
<record id="btw_code_4b" model="account.tax.code.template">
|
||||
<field name="code">4b</field>
|
||||
<field name="parent_id" ref="btw_code_vanuit_buitenland"/>
|
||||
<field name="name">Verwerving van goederen uit landen binnen de EU (BTW)</field>
|
||||
<field name="sign" eval="-1" />
|
||||
</record>
|
||||
<!-- 5. Voorbelasting, kleineondernemersregeling, schatting en eindtotaal -->
|
||||
<record id="btw_code_voorbelasting" model="account.tax.code.template">
|
||||
|
@ -4100,6 +4102,7 @@
|
|||
<field name="property_account_payable" ref="a_pay"/> <!-- crediteuren -->
|
||||
<field name="property_account_expense_categ" ref="a_expense"/><!-- aankoop grondstoffen -->
|
||||
<field name="property_account_income_categ" ref="a_sale"/> <!-- verkoop rekening -->
|
||||
<field name="property_reserve_and_surplus_account" ref="a_9999"/>
|
||||
</record>
|
||||
|
||||
<!-- BTW Template
|
||||
|
@ -4325,7 +4328,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_I_6_1" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import binnen EU laag(1)</field>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_I_6"/>
|
||||
<field name="account_collected_id" ref="vat_payable6"/>
|
||||
|
@ -4337,7 +4340,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_I_6_2" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import binnen EU laag(2)</field>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_I_6"/>
|
||||
<field name="account_collected_id" ref="vat_refund6"/>
|
||||
|
@ -4360,7 +4363,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_I_19_1" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import binnen EU hoog(1)</field>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_I_19"/>
|
||||
<field name="account_collected_id" ref="vat_payable19"/>
|
||||
|
@ -4372,7 +4375,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_I_19_2" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import binnen EU hoog(2)</field>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_I_19"/>
|
||||
<field name="account_collected_id" ref="vat_refund19"/>
|
||||
|
@ -4395,7 +4398,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_I_overig_1" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import binnen EU overig(1)</field>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_I_overig"/>
|
||||
<field name="account_collected_id" ref="vat_payable19"/>
|
||||
|
@ -4407,7 +4410,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_I_overig_2" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import binnen EU overig(2)</field>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_I_overig"/>
|
||||
<field name="account_collected_id" ref="vat_refund19"/>
|
||||
|
@ -4458,7 +4461,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_E1_1" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import buiten EU laag(1)</field>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_E1"/>
|
||||
<field name="account_collected_id" ref="vat_payable6"/>
|
||||
|
@ -4470,7 +4473,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_E1_2" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import buiten EU laag(2)</field>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_E1"/>
|
||||
<field name="account_collected_id" ref="vat_refund6"/>
|
||||
|
@ -4493,7 +4496,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_E2_1" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import buiten EU hoog(1)</field>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_E2"/>
|
||||
<field name="account_collected_id" ref="vat_payable19"/>
|
||||
|
@ -4505,7 +4508,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_E2_2" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import buiten EU hoog(2)</field>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_E2"/>
|
||||
<field name="account_collected_id" ref="vat_refund19"/>
|
||||
|
@ -4528,7 +4531,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_E_overig_1" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import buiten EU overig(1)</field>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_E_overig"/>
|
||||
<field name="account_collected_id" ref="vat_payable19"/>
|
||||
|
@ -4540,7 +4543,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
|
|||
<record id="btw_E_overig_2" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="l10nnl_chart_template"/>
|
||||
<field name="name">Inkopen import buiten EU overig(2)</field>
|
||||
<field eval="-1.00" name="amount"/>
|
||||
<field eval="1.00" name="amount"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="parent_id" ref="btw_E_overig"/>
|
||||
<field name="account_collected_id" ref="vat_refund19"/>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from osv import osv
|
||||
from osv import fields
|
||||
import tools
|
||||
|
@ -91,7 +92,7 @@ class mail_notification(osv.Model):
|
|||
:param browse_record message: mail.message to notify
|
||||
"""
|
||||
notify_pids = []
|
||||
for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context):
|
||||
for partner in self.pool.get('res.partner').browse(cr, SUPERUSER_ID, partner_ids, context=context):
|
||||
# Do not send an email to the writer
|
||||
if partner.user_ids and partner.user_ids[0].id == uid:
|
||||
continue
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from osv import osv
|
||||
from osv import fields
|
||||
from tools.translate import _
|
||||
|
||||
|
||||
class ir_ui_menu(osv.osv):
|
||||
""" Override of ir.ui.menu class. When adding mail_thread module, each
|
||||
|
@ -38,13 +39,14 @@ class ir_ui_menu(osv.osv):
|
|||
|
||||
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
|
||||
""" Override to take off menu entries (mail.group) the user is not
|
||||
following. """
|
||||
following. Access are done using SUPERUSER_ID to avoid access
|
||||
rights issues for an internal back-end algorithm. """
|
||||
ids = super(ir_ui_menu, self).search(cr, uid, args, offset=0, limit=None, order=order, context=context, count=False)
|
||||
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
||||
follower_obj = self.pool.get('mail.followers')
|
||||
for menu in self.browse(cr, uid, ids, context=context):
|
||||
if menu.mail_group_id:
|
||||
sub_ids = follower_obj.search(cr, uid, [
|
||||
sub_ids = follower_obj.search(cr, SUPERUSER_ID, [
|
||||
('partner_id', '=', partner_id), ('res_model', '=', 'mail.group'),
|
||||
('res_id', '=', menu.mail_group_id.id)
|
||||
], context=context)
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"
|
||||
options='{"thread_level": 1}'/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
|
|
|
@ -19,13 +19,12 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
# import ast
|
||||
import base64
|
||||
import logging
|
||||
import tools
|
||||
|
||||
from osv import osv
|
||||
from osv import fields
|
||||
from openerp import SUPERUSER_ID
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
@ -134,7 +133,8 @@ class mail_mail(osv.Model):
|
|||
:return: True
|
||||
"""
|
||||
if mail.auto_delete:
|
||||
mail.unlink()
|
||||
# done with SUPERUSER_ID to avoid giving large unlink access rights
|
||||
self.unlink(cr, SUPERUSER_ID, [mail.id], context=context)
|
||||
return True
|
||||
|
||||
def send_get_mail_subject(self, cr, uid, mail, force=False, partner=None, context=None):
|
||||
|
|
|
@ -24,8 +24,9 @@ import openerp
|
|||
import tools
|
||||
|
||||
from email.header import decode_header
|
||||
from openerp import SUPERUSER_ID
|
||||
from operator import itemgetter
|
||||
from osv import osv, fields
|
||||
from osv import osv, orm, fields
|
||||
from tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
@ -62,14 +63,14 @@ class mail_message(osv.Model):
|
|||
continue
|
||||
try:
|
||||
result[message.id] = self._shorten_name(self.pool.get(message.model).name_get(cr, uid, [message.res_id], context=context)[0][1])
|
||||
except openerp.exceptions.AccessDenied, e:
|
||||
except (orm.except_orm, osv.except_osv):
|
||||
pass
|
||||
return result
|
||||
|
||||
def _get_unread(self, cr, uid, ids, name, arg, context=None):
|
||||
""" Compute if the message is unread by the current user. """
|
||||
res = dict((id, {'unread': False}) for id in ids)
|
||||
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
||||
notif_obj = self.pool.get('mail.notification')
|
||||
notif_ids = notif_obj.search(cr, uid, [
|
||||
('partner_id', 'in', [partner_id]),
|
||||
|
@ -87,7 +88,7 @@ class mail_message(osv.Model):
|
|||
read_cond = '(read = false or read is null)'
|
||||
else:
|
||||
read_cond = 'read = true'
|
||||
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
||||
cr.execute("SELECT message_id FROM mail_notification "\
|
||||
"WHERE partner_id = %%s AND %s" % read_cond,
|
||||
(partner_id,))
|
||||
|
@ -140,7 +141,8 @@ class mail_message(osv.Model):
|
|||
return []
|
||||
|
||||
def _get_default_author(self, cr, uid, context=None):
|
||||
return self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||
# remove context to avoid possible hack in browse with superadmin using context keys that could trigger a specific behavior
|
||||
return self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id
|
||||
|
||||
_defaults = {
|
||||
'type': 'email',
|
||||
|
@ -154,16 +156,17 @@ class mail_message(osv.Model):
|
|||
#------------------------------------------------------
|
||||
|
||||
def vote_toggle(self, cr, uid, ids, user_ids=None, context=None):
|
||||
''' Toggles voting '''
|
||||
''' Toggles voting. Done as SUPERUSER_ID because of write access on
|
||||
mail.message not always granted. '''
|
||||
if not user_ids:
|
||||
user_ids = [uid]
|
||||
for message in self.read(cr, uid, ids, ['vote_user_ids'], context=context):
|
||||
for user_id in user_ids:
|
||||
has_voted = user_id in message.get('vote_user_ids')
|
||||
if not has_voted:
|
||||
self.write(cr, uid, message.get('id'), {'vote_user_ids': [(4, user_id)]}, context=context)
|
||||
self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(4, user_id)]}, context=context)
|
||||
else:
|
||||
self.write(cr, uid, message.get('id'), {'vote_user_ids': [(3, user_id)]}, context=context)
|
||||
self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(3, user_id)]}, context=context)
|
||||
return True
|
||||
|
||||
#------------------------------------------------------
|
||||
|
@ -171,17 +174,31 @@ class mail_message(osv.Model):
|
|||
#------------------------------------------------------
|
||||
|
||||
def _message_dict_get(self, cr, uid, msg, context=None):
|
||||
""" Return a dict representation of the message browse record. """
|
||||
""" Return a dict representation of the message browse record. A read
|
||||
is performed to because of access rights issues (reading many2one
|
||||
fields allow to have the foreign record name without having
|
||||
to check external access rights).
|
||||
"""
|
||||
has_voted = False
|
||||
vote_ids = self.pool.get('res.users').name_get(cr, uid, [user.id for user in msg.vote_user_ids], context=context)
|
||||
vote_ids = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [user.id for user in msg.vote_user_ids], context=context)
|
||||
for vote in vote_ids:
|
||||
if vote[0] == uid:
|
||||
has_voted = True
|
||||
break
|
||||
attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)]
|
||||
author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0]
|
||||
author_user_id = self.pool.get('res.users').name_get(cr, uid, [msg.author_id.user_ids[0].id], context=context)[0]
|
||||
partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context)
|
||||
try:
|
||||
attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)]
|
||||
except (orm.except_orm, osv.except_osv):
|
||||
attachment_ids = []
|
||||
try:
|
||||
author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0]
|
||||
is_author = uid in msg.author_id.user_ids
|
||||
except (orm.except_orm, osv.except_osv):
|
||||
author_id = False
|
||||
is_author = False
|
||||
try:
|
||||
partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context)
|
||||
except (orm.except_orm, osv.except_osv):
|
||||
partner_ids = []
|
||||
return {
|
||||
'id': msg.id,
|
||||
'type': msg.type,
|
||||
|
@ -193,7 +210,7 @@ class mail_message(osv.Model):
|
|||
'subject': msg.subject,
|
||||
'date': msg.date,
|
||||
'author_id': author_id,
|
||||
'author_user_id': author_user_id,
|
||||
'is_author': is_author,
|
||||
'partner_ids': partner_ids,
|
||||
'child_ids': [],
|
||||
'vote_user_ids': vote_ids,
|
||||
|
@ -246,7 +263,7 @@ class mail_message(osv.Model):
|
|||
limit = limit or self._message_read_limit
|
||||
context = context or {}
|
||||
if not ids:
|
||||
ids = self.search(cr, uid, domain, context=context, limit=limit)
|
||||
ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit)
|
||||
messages = self.browse(cr, uid, ids, context=context)
|
||||
|
||||
result = []
|
||||
|
@ -294,41 +311,99 @@ class mail_message(osv.Model):
|
|||
cr.execute("""CREATE INDEX mail_message_model_res_id_idx ON mail_message (model, res_id)""")
|
||||
|
||||
def check_access_rule(self, cr, uid, ids, operation, context=None):
|
||||
""" mail.message access rule check
|
||||
- message received (a notification exists) -> ok
|
||||
- check rules of related document if exists
|
||||
- fallback on normal mail.message check """
|
||||
""" Access rules of mail.message:
|
||||
- read: if
|
||||
- notification exist (I receive pushed message) OR
|
||||
- author_id = pid (I am the author) OR
|
||||
- I can read the related document if res_model, res_id
|
||||
- Otherwise: raise
|
||||
- create: if
|
||||
- I am in the document message_follower_ids OR
|
||||
- I can write on the related document if res_model, res_id
|
||||
- Otherwise: raise
|
||||
- write: if
|
||||
- I can write on the related document if res_model, res_id
|
||||
- Otherwise: raise
|
||||
- unlink: if
|
||||
- I can write on the related document if res_model, res_id
|
||||
- Otherwise: raise
|
||||
"""
|
||||
if uid == SUPERUSER_ID:
|
||||
return
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
|
||||
|
||||
# check messages for which you have a notification
|
||||
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||
not_obj = self.pool.get('mail.notification')
|
||||
not_ids = not_obj.search(cr, uid, [
|
||||
('partner_id', '=', partner_id),
|
||||
('message_id', 'in', ids),
|
||||
], context=context)
|
||||
notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, uid, not_ids, context=context)
|
||||
if notification.message_id.id in ids]
|
||||
|
||||
# check messages linked to an existing document
|
||||
# Read mail_message.ids to have their values
|
||||
model_record_ids = {}
|
||||
document_ids = []
|
||||
cr.execute('SELECT DISTINCT id, model, res_id FROM mail_message WHERE id = ANY (%s)', (ids,))
|
||||
for id, rmod, rid in cr.fetchall():
|
||||
if not (rmod and rid):
|
||||
continue
|
||||
document_ids.append(id)
|
||||
model_record_ids.setdefault(rmod, set()).add(rid)
|
||||
message_values = dict.fromkeys(ids)
|
||||
cr.execute('SELECT DISTINCT id, model, res_id, author_id FROM "%s" WHERE id = ANY (%%s)' % self._table, (ids,))
|
||||
for id, rmod, rid, author_id in cr.fetchall():
|
||||
message_values[id] = {'res_model': rmod, 'res_id': rid, 'author_id': author_id}
|
||||
if rmod:
|
||||
model_record_ids.setdefault(rmod, set()).add(rid)
|
||||
|
||||
# Read: Check for received notifications -> could become an ir.rule, but not till we do not have a many2one variable field
|
||||
if operation == 'read':
|
||||
not_obj = self.pool.get('mail.notification')
|
||||
not_ids = not_obj.search(cr, SUPERUSER_ID, [
|
||||
('partner_id', '=', partner_id),
|
||||
('message_id', 'in', ids),
|
||||
], context=context)
|
||||
notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, SUPERUSER_ID, not_ids, context=context)]
|
||||
else:
|
||||
notified_ids = []
|
||||
# Read: Check messages you are author -> could become an ir.rule, but not till we do not have a many2one variable field
|
||||
if operation == 'read':
|
||||
author_ids = [mid for mid, message in message_values.iteritems()
|
||||
if message.get('author_id') and message.get('author_id') == partner_id]
|
||||
else:
|
||||
author_ids = []
|
||||
|
||||
# Create: Check message_follower_ids
|
||||
if operation == 'create':
|
||||
doc_follower_ids = []
|
||||
for model, mids in model_record_ids.items():
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [
|
||||
('res_model', '=', model),
|
||||
('res_id', 'in', list(mids)),
|
||||
('partner_id', '=', partner_id),
|
||||
], context=context)
|
||||
fol_mids = [follower.res_id for follower in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)]
|
||||
doc_follower_ids += [mid for mid, message in message_values.iteritems()
|
||||
if message.get('res_model') == model and message.get('res_id') in fol_mids]
|
||||
else:
|
||||
doc_follower_ids = []
|
||||
|
||||
# Calculate remaining ids, and related model/res_ids
|
||||
model_record_ids = {}
|
||||
other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids))
|
||||
for id in other_ids:
|
||||
if message_values[id]['res_model']:
|
||||
model_record_ids.setdefault(message_values[id]['res_model'], set()).add(message_values[id]['res_id'])
|
||||
|
||||
# CRUD: Access rights related to the document
|
||||
document_related_ids = []
|
||||
for model, mids in model_record_ids.items():
|
||||
model_obj = self.pool.get(model)
|
||||
mids = model_obj.exists(cr, uid, mids)
|
||||
model_obj.check_access_rights(cr, uid, operation)
|
||||
model_obj.check_access_rule(cr, uid, mids, operation, context=context)
|
||||
if operation in ['create', 'write', 'unlink']:
|
||||
model_obj.check_access_rights(cr, uid, 'write')
|
||||
model_obj.check_access_rule(cr, uid, mids, 'write', context=context)
|
||||
else:
|
||||
model_obj.check_access_rights(cr, uid, operation)
|
||||
model_obj.check_access_rule(cr, uid, mids, operation, context=context)
|
||||
document_related_ids += [mid for mid, message in message_values.iteritems()
|
||||
if message.get('res_model') == model and message.get('res_id') in mids]
|
||||
|
||||
# fall back on classic operation for other ids
|
||||
other_ids = set(ids).difference(set(notified_ids), set(document_ids))
|
||||
super(mail_message, self).check_access_rule(cr, uid, other_ids, operation, context=None)
|
||||
# Calculate remaining ids: if not void, raise an error
|
||||
other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids), set(document_related_ids))
|
||||
if not other_ids:
|
||||
return
|
||||
raise orm.except_orm(_('Access Denied'),
|
||||
_('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \
|
||||
(self._description, operation))
|
||||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
if not values.get('message_id') and values.get('res_id') and values.get('model'):
|
||||
|
@ -337,6 +412,13 @@ class mail_message(osv.Model):
|
|||
self.notify(cr, uid, newid, context=context)
|
||||
return newid
|
||||
|
||||
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
|
||||
""" Override to explicitely call check_access_rule, that is not called
|
||||
by the ORM. It instead directly fetches ir.rules and apply them. """
|
||||
res = super(mail_message, self).read(cr, uid, ids, fields=fields, context=context, load=load)
|
||||
self.check_access_rule(cr, uid, ids, 'read', context=context)
|
||||
return res
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# cascade-delete attachments that are directly attached to the message (should only happen
|
||||
# for mail.messages that act as parent for a standalone mail.mail record).
|
||||
|
@ -360,12 +442,14 @@ class mail_message(osv.Model):
|
|||
partners_to_notify |= set(partner.id for partner in message.partner_ids)
|
||||
# add all followers and set add them in partner_ids
|
||||
if message.model and message.res_id:
|
||||
record = self.pool.get(message.model).browse(cr, uid, message.res_id, context=context)
|
||||
record = self.pool.get(message.model).browse(cr, SUPERUSER_ID, message.res_id, context=context)
|
||||
extra_notified = set(partner.id for partner in record.message_follower_ids)
|
||||
missing_notified = extra_notified - partners_to_notify
|
||||
if missing_notified:
|
||||
message.write({'partner_ids': [(4, p_id) for p_id in missing_notified]})
|
||||
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context)
|
||||
partners_to_notify |= extra_notified
|
||||
# # remove uid from partners
|
||||
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, uid)]}, context=context)
|
||||
self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
|
|
|
@ -76,13 +76,6 @@
|
|||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_message_search"/>
|
||||
</record>
|
||||
|
||||
<act_window domain="[('partner_id', '=', active_id), ('email_from', '!=', False)]"
|
||||
context="{'default_partner_id': active_id}"
|
||||
id="act_res_partner_emails" name="Emails"
|
||||
res_model="mail.message"
|
||||
src_model="res.partner"
|
||||
view_id="view_message_tree"/>
|
||||
|
||||
<!-- Add menu entry in Settings/Email -->
|
||||
<menuitem name="Messages" id="menu_mail_message" parent="base.menu_email" action="action_view_mail_message"/>
|
||||
|
@ -95,7 +88,7 @@
|
|||
</record>
|
||||
|
||||
<record id="action_mail_my_feeds" model="ir.actions.client">
|
||||
<field name="name">My Feeds</field>
|
||||
<field name="name">My Posts</field>
|
||||
<field name="tag">mail.wall</field>
|
||||
<field name="params" eval=""{'domain': [('author_id.user_ids', 'in', [uid])],
|
||||
'context': {'default_model': 'res.users', 'default_res_id': uid} }""/>
|
||||
|
|
|
@ -30,6 +30,7 @@ import xmlrpclib
|
|||
|
||||
from email.message import Message
|
||||
from mail_message import decode
|
||||
from openerp import SUPERUSER_ID
|
||||
from osv import osv, fields
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
|
||||
|
@ -118,26 +119,27 @@ class mail_thread(osv.AbstractModel):
|
|||
|
||||
def _get_message_data(self, cr, uid, ids, name, args, context=None):
|
||||
res = dict((id, dict(message_unread=False, message_summary='')) for id in ids)
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
||||
|
||||
# search for unread messages, by reading directly mail.notification, as SUPERUSER
|
||||
notif_obj = self.pool.get('mail.notification')
|
||||
notif_ids = notif_obj.search(cr, uid, [
|
||||
notif_ids = notif_obj.search(cr, SUPERUSER_ID, [
|
||||
('partner_id.user_ids', 'in', [uid]),
|
||||
('message_id.res_id', 'in', ids),
|
||||
('message_id.model', '=', self._name),
|
||||
('read', '=', False)
|
||||
], context=context)
|
||||
for notif in notif_obj.browse(cr, uid, notif_ids, context=context):
|
||||
for notif in notif_obj.browse(cr, SUPERUSER_ID, notif_ids, context=context):
|
||||
res[notif.message_id.res_id]['message_unread'] = True
|
||||
|
||||
for thread in self.browse(cr, uid, ids, context=context):
|
||||
cls = res[thread.id]['message_unread'] and ' class="oe_kanban_mail_new"' or ''
|
||||
res[thread.id]['message_summary'] = "<span%s><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (cls, len(thread.message_comment_ids), len(thread.message_follower_ids))
|
||||
res[thread.id]['message_is_follower'] = user.partner_id.id in [follower.id for follower in thread.message_follower_ids]
|
||||
for thread in self.read(cr, uid, ids, ['message_follower_ids', 'message_comment_ids', 'message_ids'], context=context):
|
||||
cls = res[thread['id']]['message_unread'] and ' class="oe_kanban_mail_new"' or ''
|
||||
res[thread['id']]['message_summary'] = "<span%s><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (cls, len(thread['message_comment_ids']), len(thread['message_follower_ids']))
|
||||
res[thread['id']]['message_is_follower'] = partner_id in thread['message_follower_ids']
|
||||
return res
|
||||
|
||||
def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None):
|
||||
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
||||
res = {}
|
||||
notif_obj = self.pool.get('mail.notification')
|
||||
notif_ids = notif_obj.search(cr, uid, [
|
||||
|
@ -196,6 +198,13 @@ class mail_thread(osv.AbstractModel):
|
|||
fol_obj.unlink(cr, uid, fol_ids, context=context)
|
||||
return super(mail_thread, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
default = default or {}
|
||||
default['message_ids'] = []
|
||||
default['message_comment_ids'] = []
|
||||
default['message_follower_ids'] = []
|
||||
return super(mail_thread, self).copy(cr, uid, id, default=default, context=context)
|
||||
|
||||
#------------------------------------------------------
|
||||
# mail.message wrappers and tools
|
||||
#------------------------------------------------------
|
||||
|
@ -620,7 +629,7 @@ class mail_thread(osv.AbstractModel):
|
|||
""" Wrapper on message_subscribe, using users. If user_ids is not
|
||||
provided, subscribe uid instead. """
|
||||
if not user_ids: user_ids = [uid]
|
||||
partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
|
||||
partner_ids = [user['partner_id'][0] for user in self.pool.get('res.users').read(cr, uid, user_ids, ['partner_id'], context=context)]
|
||||
return self.message_subscribe(cr, uid, ids, partner_ids, context=context)
|
||||
|
||||
def message_subscribe(self, cr, uid, ids, partner_ids, context=None):
|
||||
|
@ -631,7 +640,7 @@ class mail_thread(osv.AbstractModel):
|
|||
""" Wrapper on message_subscribe, using users. If user_ids is not
|
||||
provided, unsubscribe uid instead. """
|
||||
if not user_ids: user_ids = [uid]
|
||||
partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
|
||||
partner_ids = [user['partner_id'][0] for user in self.pool.get('res.users').read(cr, uid, user_ids, ['partner_id'], context=context)]
|
||||
return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context)
|
||||
|
||||
def message_unsubscribe(self, cr, uid, ids, partner_ids, context=None):
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="after">
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"
|
||||
options='{"thread_level": 1}'/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_mail_global,mail.mail,model_mail_mail,base.group_system,1,1,1,1
|
||||
access_mail_message_all,mail.message.all,model_mail_message,,1,0,0,0
|
||||
access_mail_message_all,mail.message.all,model_mail_message,,1,0,1,0
|
||||
access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1
|
||||
access_mail_thread,mail.thread,model_mail_thread,base.group_user,1,1,1,0
|
||||
access_mail_followers_all,mail.followers.all,model_mail_followers,,1,1,1,1
|
||||
access_mail_notification_all,mail.notification.all,model_mail_notification,,1,1,1,1
|
||||
access_mail_group,mail.group,model_mail_group,base.group_user,1,1,1,1
|
||||
access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0
|
||||
access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1
|
||||
access_mail_followers_all,mail.followers.all,model_mail_followers,,0,0,0,0
|
||||
access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1
|
||||
access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,0
|
||||
access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
|
||||
access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0
|
||||
access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1
|
||||
access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
|
||||
access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0
|
||||
access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1
|
||||
access_mail_mail_user,mail.mail,model_mail_mail,base.group_user,1,1,1,0
|
||||
access_mail_mail_manager,mail.mail,model_mail_mail,group_mail_manager,1,1,1,1
|
||||
access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1
|
||||
|
|
|
|
@ -2,20 +2,6 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- CATEGORY -->
|
||||
<record model="ir.module.category" id="module_category_social">
|
||||
<field name="name">Home</field>
|
||||
<field name="parent_id" ref="base.module_category_tools"/>
|
||||
<field name="sequence">26</field>
|
||||
</record>
|
||||
|
||||
<!-- GROUPS -->
|
||||
<record id="group_mail_manager" model="res.groups">
|
||||
<field name="name">Mail manager</field>
|
||||
<field name="comment"></field>
|
||||
<field name="category_id" ref="module_category_social"/>
|
||||
</record>
|
||||
|
||||
<!-- RULES -->
|
||||
<record id="group_rule_public_and_joined" model="ir.rule">
|
||||
<field name="name">Mail.group: access only public and joined groups</field>
|
||||
|
@ -24,5 +10,18 @@
|
|||
<field name="domain_force">['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.id]), '&', ('public','=','groups'), ('group_public_id','in', [x.id for x in user.groups_id])]</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
This rule can not be uncommented, because we have a more wide method in mail.message. When we implement a many2one_variable field, we will be able to uncomment this.
|
||||
|
||||
<record id="mail_message_read_partner_or_author" model="ir.rule">
|
||||
<field name="name">mail.message: read if notified or author</field>
|
||||
<field name="model_id" ref="model_mail_message"/>
|
||||
<field name="domain_force">['|', ('partner_ids', 'in', user.partner_id.id), ('author_id', '=', user.partner_id.id)]</field>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
</record>
|
||||
-->
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -124,6 +124,14 @@
|
|||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Followers
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
.openerp div.oe_mail_recthread_aside h4 {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Thread
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -224,7 +232,7 @@
|
|||
clear: both;
|
||||
}
|
||||
|
||||
.openerp .oe_mail_msg_content a {
|
||||
.openerp .oe_chatter a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -258,30 +266,6 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* mail.vote
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
.openerp .oe_mail_msg_content button.oe_mail_msg_vote {
|
||||
height:21px;
|
||||
width: 30px;
|
||||
padding: 1px;
|
||||
background: #8A89BA;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.openerp .oe_mail_msg_content button.oe_mail_msg_vote_true {
|
||||
background:#DC5F59;
|
||||
}
|
||||
|
||||
.openerp .oe_mail_msg_content button.oe_mail_msg_vote span {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openerp .oe_mail_msg_content span.oe_mail_vote_count{
|
||||
color: #807FB4;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* mail.compose.message form view & OpenERP hacks
|
||||
|
|
|
@ -56,11 +56,6 @@ openerp.mail = function(session) {
|
|||
return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id'];
|
||||
},
|
||||
|
||||
/** Check if the current user is the message author */
|
||||
is_author: function (widget, message_user_id) {
|
||||
return (widget.session && widget.session.uid != 0 && widget.session.uid == message_user_id);
|
||||
},
|
||||
|
||||
/** Replaces some expressions
|
||||
* - :name - shortcut to an image
|
||||
*/
|
||||
|
@ -301,6 +296,7 @@ openerp.mail = function(session) {
|
|||
// TDE TODO: check for deferred, not sure it is correct
|
||||
this._super.apply(this, arguments);
|
||||
this.bind_events();
|
||||
this.display_user_avatar();
|
||||
// fetch and display message, using message_ids if set
|
||||
var display_done = $.when(this.message_fetch(true, [], {})).then(this.proxy('do_customize_display'));
|
||||
// add message composition form view
|
||||
|
@ -313,7 +309,6 @@ openerp.mail = function(session) {
|
|||
/** Customize the display
|
||||
* - show_header_compose: show the composition form in the header */
|
||||
do_customize_display: function() {
|
||||
this.display_user_avatar();
|
||||
if (this.options.show_header_compose) {
|
||||
this.$el.find('div.oe_mail_thread_action').eq(0).show();
|
||||
}
|
||||
|
@ -491,8 +486,7 @@ openerp.mail = function(session) {
|
|||
* - record.date: formatting according to the user timezone
|
||||
* - record.timerelative: relative time givein by timeago lib
|
||||
* - record.avatar: image url
|
||||
* - record.attachment_ids[].url: url of each attachment
|
||||
* - record.is_author: is the current user the author of the record */
|
||||
* - record.attachment_ids[].url: url of each attachment */
|
||||
display_record: function (record) {
|
||||
// formatting and additional fields
|
||||
record.date = session.web.format_value(record.date, {type:"datetime"});
|
||||
|
@ -506,7 +500,6 @@ openerp.mail = function(session) {
|
|||
var attach = record.attachment_ids[l];
|
||||
attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach);
|
||||
}
|
||||
record.is_author = mail.ChatterUtils.is_author(this, record.author_user_id[0]);
|
||||
// add to internal storage
|
||||
this.records[record.id] = record;
|
||||
// render, add the expand feature
|
||||
|
@ -649,12 +642,15 @@ openerp.mail = function(session) {
|
|||
// update domain
|
||||
var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]);
|
||||
// create and render Thread widget
|
||||
var show_header_compose = this.view.is_action_enabled('edit') ||
|
||||
(this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
|
||||
this.$el.find('div.oe_mail_recthread_main').empty();
|
||||
var thread = new mail.Thread(self, domain, this.options.context,
|
||||
{ 'thread_level': this.options.thread_level,
|
||||
'use_composer': true,
|
||||
'show_header_compose': show_header_compose,
|
||||
'use_composer': show_header_compose,
|
||||
'show_dd_delete': true,
|
||||
'show_reply_by_email': true });
|
||||
'show_reply_by_email': show_header_compose });
|
||||
return thread.appendTo(this.$el.find('div.oe_mail_recthread_main'));
|
||||
},
|
||||
});
|
||||
|
|
|
@ -45,8 +45,8 @@ openerp_mail_followers = function(session, mail) {
|
|||
},
|
||||
|
||||
reinit: function() {
|
||||
this.$el.find('button.oe_mail_button_follow').hide();
|
||||
this.$el.find('button.oe_mail_button_unfollow').hide();
|
||||
this.message_is_follower == undefined;
|
||||
this.display_buttons();
|
||||
},
|
||||
|
||||
bind_events: function() {
|
||||
|
@ -55,7 +55,7 @@ openerp_mail_followers = function(session, mail) {
|
|||
.mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); })
|
||||
.mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); });
|
||||
this.$el.on('click', 'button.oe_mail_button_follow', function () { self.do_follow(); });
|
||||
this.$el.on('click', 'button.oe_mail_button_invite', function(event) {
|
||||
this.$el.on('click', 'a.oe_mail_invite', function(event) {
|
||||
action = {
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'mail.wizard.invite',
|
||||
|
@ -74,41 +74,65 @@ openerp_mail_followers = function(session, mail) {
|
|||
|
||||
read_value: function() {
|
||||
var self = this;
|
||||
return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) {
|
||||
return results[0].message_follower_ids;
|
||||
}).pipe(this.proxy('set_value'));
|
||||
return this.ds_model.read_ids([this.view.datarecord.id], ['message_is_follower', 'message_follower_ids']).then(function (results) {
|
||||
self.set_value(results[0].message_follower_ids, results[0].message_is_follower);
|
||||
});
|
||||
},
|
||||
|
||||
set_value: function(value_) {
|
||||
set_value: function(value_, message_is_follower) {
|
||||
this.reinit();
|
||||
if (! this.view.datarecord.id ||
|
||||
session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
|
||||
this.$el.find('div.oe_mail_recthread_aside').hide();
|
||||
this.$('div.oe_mail_recthread_aside').hide();
|
||||
return;
|
||||
}
|
||||
return this.fetch_followers(value_ || this.get_value());
|
||||
return this.fetch_followers(value_ || this.get_value(), message_is_follower);
|
||||
},
|
||||
|
||||
fetch_followers: function (value_) {
|
||||
return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers'));
|
||||
fetch_followers: function (value_, message_is_follower) {
|
||||
this.value = value_;
|
||||
this.message_is_follower = message_is_follower || (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
|
||||
return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic'));
|
||||
},
|
||||
|
||||
|
||||
/* Display generic info about follower, for people not having access to res_partner */
|
||||
display_generic: function (error, event) {
|
||||
event.preventDefault();
|
||||
var node_user_list = this.$('ul.oe_mail_followers_display').empty();
|
||||
// format content: Followers (You and 0 other) // Followers (3)
|
||||
var content = this.options.title;
|
||||
if (this.message_is_follower) {
|
||||
content += ' (You and ' + (this.value.length-1) + ' other)';
|
||||
}
|
||||
else {
|
||||
content += ' (' + this.value.length + ')'
|
||||
}
|
||||
this.$('div.oe_mail_recthread_followers h4').html(content);
|
||||
this.display_buttons();
|
||||
return $.when();
|
||||
},
|
||||
|
||||
/** Display the followers, evaluate is_follower directly */
|
||||
display_followers: function (records) {
|
||||
var self = this;
|
||||
this.message_is_follower = _.indexOf(_.flatten(_.pluck(records, 'user_ids')), this.session.uid) != -1;
|
||||
var node_user_list = this.$el.find('ul.oe_mail_followers_display').empty();
|
||||
this.$el.find('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + records.length + ')');
|
||||
var node_user_list = this.$('ul.oe_mail_followers_display').empty();
|
||||
this.$('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + records.length + ')');
|
||||
_(records).each(function (record) {
|
||||
record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
|
||||
$(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list);
|
||||
});
|
||||
if (this.message_is_follower) {
|
||||
this.$el.find('button.oe_mail_button_follow').hide();
|
||||
this.$el.find('button.oe_mail_button_unfollow').show(); }
|
||||
else {
|
||||
this.$el.find('button.oe_mail_button_follow').show();
|
||||
this.$el.find('button.oe_mail_button_unfollow').hide(); }
|
||||
this.display_buttons();
|
||||
},
|
||||
|
||||
display_buttons: function () {
|
||||
this.$('button.oe_mail_button_follow').hide();
|
||||
this.$('button.oe_mail_button_unfollow').hide();
|
||||
this.$('span.oe_mail_invite_wrapper').hide();
|
||||
if (! this.view.is_action_enabled('edit')) return;
|
||||
this.$('span.oe_mail_invite_wrapper').show();
|
||||
if (this.message_is_follower) { this.$('button.oe_mail_button_unfollow').show(); }
|
||||
else if (this.message_is_follower == false) { this.$('button.oe_mail_button_follow').show(); }
|
||||
},
|
||||
|
||||
do_follow: function () {
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
<li t-if="options.show_record_name and record.record_name and record.subject and options.thread_level > 0">
|
||||
<a t-attf-href="#model=#{record.model}&id=#{record.res_id}"><t t-raw="record.record_name"/></a>
|
||||
</li>
|
||||
<li><a t-attf-href="#model=res.partner&id=#{record.author_id[0]}"><t t-raw="record.author_id[1]"/></a></li>
|
||||
<li t-if="record.author_id"><a t-attf-href="#model=res.partner&id=#{record.author_id[0]}"><t t-raw="record.author_id[1]"/></a></li>
|
||||
<li><span t-att-title="record.date"><t t-raw="record.timerelative"/></span></li>
|
||||
<t t-call="mail.thread.message.vote"/>
|
||||
<li t-if="options.show_reply"><a class="oe_mail_msg_reply">Reply</a></li>
|
||||
|
@ -185,7 +185,7 @@
|
|||
<t t-if='record.vote_user_ids.length > 0'>
|
||||
<span class="oe_left oe_mail_vote_count"><t t-esc="record.vote_user_ids.length"/> votes</span>
|
||||
</t>
|
||||
<button t-attf-class="oe_mail_msg_vote oe_mail_msg_vote_#{record.has_voted}" t-attf-data-msg_id="{record.id}">
|
||||
<button t-attf-class="oe_mail_msg_vote oe_tag" t-attf-data-msg_id="{record.id}">
|
||||
<t t-if="! record.has_voted"><span>+1</span></t>
|
||||
<t t-if="record.has_voted"><span>-1</span></t>
|
||||
</button>
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
-->
|
||||
<div t-name="mail.followers" class="oe_mail_recthread_aside oe_semantic_html_override">
|
||||
<div class="oe_mail_recthread_actions">
|
||||
<button type="button" class="oe_mail_button_invite">Invite</button>
|
||||
<button type="button" class="oe_mail_button_follow">Follow</button>
|
||||
<button type="button" class="oe_mail_button_unfollow oe_mail_button_mouseout">Following</button>
|
||||
</div>
|
||||
|
@ -18,7 +17,7 @@
|
|||
</div>
|
||||
<div class="oe_mail_recthread_followers">
|
||||
<t t-if="widget.options.title">
|
||||
<h4><t t-raw="widget.options.title"/></h4>
|
||||
<h4><t t-raw="widget.options.title"/></h4><span class="oe_mail_invite_wrapper"> · <a class="oe_mail_invite" >Invite partners</a></span>
|
||||
</t>
|
||||
<ul class="oe_mail_followers_display"></ul>
|
||||
</div>
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from . import test_mail
|
||||
from . import test_mail, test_mail_access_rights
|
||||
|
||||
checks = [
|
||||
test_mail,
|
||||
test_mail_access_rights,
|
||||
]
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2012-TODAY 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
|
||||
# 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 openerp.addons.mail.tests import test_mail
|
||||
from osv.orm import except_orm
|
||||
|
||||
|
||||
class test_mail_access_rights(test_mail.TestMailMockups):
|
||||
|
||||
def setUp(self):
|
||||
super(test_mail_access_rights, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
self.mail_group = self.registry('mail.group')
|
||||
self.mail_message = self.registry('mail.message')
|
||||
self.mail_notification = self.registry('mail.notification')
|
||||
self.res_users = self.registry('res.users')
|
||||
self.res_groups = self.registry('res.groups')
|
||||
self.res_partner = self.registry('res.partner')
|
||||
|
||||
# create a 'pigs' group that will be used through the various tests
|
||||
self.group_pigs_id = self.mail_group.create(self.cr, self.uid,
|
||||
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !'})
|
||||
|
||||
# Find Employee group
|
||||
group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
|
||||
self.group_employee_id = group_employee_ref and group_employee_ref[1] or False
|
||||
|
||||
# Create Bert (without groups) and Raoul( employee)
|
||||
self.user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert Tartopoils', 'login': 'bert', 'groups_id': [(6, 0, [])]})
|
||||
self.user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [self.group_employee_id])]})
|
||||
self.user_bert = self.res_users.browse(cr, uid, self.user_bert_id)
|
||||
self.partner_bert_id = self.user_bert.partner_id.id
|
||||
self.user_raoul = self.res_users.browse(cr, uid, self.user_raoul_id)
|
||||
self.partner_raoul_id = self.user_raoul.partner_id.id
|
||||
|
||||
def test_00_mail_message_read_access_rights(self):
|
||||
""" Test basic mail_message read access rights. """
|
||||
cr, uid = self.cr, self.uid
|
||||
partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id
|
||||
user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id
|
||||
|
||||
# Prepare groups: Pigs (employee), Jobs (public)
|
||||
self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
|
||||
self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'})
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE1: Bert, basic mail.message read access
|
||||
# ----------------------------------------
|
||||
|
||||
# Do: create a new mail.message
|
||||
message_id = self.mail_message.create(cr, uid, {'body': 'My Body'})
|
||||
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
|
||||
self.assertRaises(except_orm, self.mail_message.read,
|
||||
cr, user_bert_id, message_id)
|
||||
# Do: message is pushed to Bert
|
||||
notif_id = self.mail_notification.create(cr, uid, {'message_id': message_id, 'partner_id': partner_bert_id})
|
||||
# Test: Bert reads the message, ok because notification pushed
|
||||
self.mail_message.read(cr, user_bert_id, message_id)
|
||||
# Do: remove notification
|
||||
self.mail_notification.unlink(cr, uid, notif_id)
|
||||
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
|
||||
self.assertRaises(except_orm, self.mail_message.read,
|
||||
cr, self.user_bert_id, message_id)
|
||||
# Do: Bert is now the author
|
||||
self.mail_message.write(cr, uid, [message_id], {'author_id': partner_bert_id})
|
||||
# Test: Bert reads the message, ok because Bert is the author
|
||||
self.mail_message.read(cr, user_bert_id, message_id)
|
||||
# Do: Bert is not the author anymore
|
||||
self.mail_message.write(cr, uid, [message_id], {'author_id': partner_raoul_id})
|
||||
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
|
||||
self.assertRaises(except_orm, self.mail_message.read,
|
||||
cr, user_bert_id, message_id)
|
||||
# Do: message is attached to a document Bert can read, Jobs
|
||||
self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_jobs_id})
|
||||
# Test: Bert reads the message, ok because linked to a doc he is allowed to read
|
||||
self.mail_message.read(cr, user_bert_id, message_id)
|
||||
# Do: message is attached to a document Bert cannot read, Pigs
|
||||
self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_pigs_id})
|
||||
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
|
||||
self.assertRaises(except_orm, self.mail_message.read,
|
||||
cr, user_bert_id, message_id)
|
||||
|
||||
def test_05_mail_message_search_access_rights(self):
|
||||
""" Test mail_message search override about access rights. """
|
||||
self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True')
|
||||
|
||||
def test_10_mail_flow_access_rights(self):
|
||||
""" Test a Chatter-looks alike flow. """
|
||||
cr, uid = self.cr, self.uid
|
||||
partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id
|
||||
user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id
|
||||
|
||||
# Prepare groups: Pigs (employee), Jobs (public)
|
||||
self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
|
||||
self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'})
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE1: Bert, without groups
|
||||
# ----------------------------------------
|
||||
# Do: Bert creates a group, should crash because perm_create only for employees
|
||||
self.assertRaises(except_orm,
|
||||
self.mail_group.create,
|
||||
cr, user_bert_id, {'name': 'Bert\'s Group'})
|
||||
# Do: Bert reads Jobs basic fields, ok because public = read access on the group
|
||||
self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description'])
|
||||
# Do: Bert browse Pigs, ok (no direct browse of partners)
|
||||
self.mail_group.browse(cr, user_bert_id, self.group_jobs_id)
|
||||
# Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages
|
||||
jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids']
|
||||
self.mail_message.read(cr, user_bert_id, jobs_message_ids)
|
||||
# Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager
|
||||
jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids']
|
||||
self.assertRaises(except_orm,
|
||||
self.res_partner.read,
|
||||
cr, user_bert_id, jobs_followers_ids)
|
||||
# Do: Bert comments Jobs, ko because no write access on the group and not in the followers
|
||||
self.assertRaises(except_orm,
|
||||
self.mail_group.message_post,
|
||||
cr, user_bert_id, self.group_jobs_id, body='I love Pigs')
|
||||
# Do: add Bert to jobs followers
|
||||
self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [partner_bert_id])
|
||||
# Do: Bert comments Jobs, ok because he is now in the followers
|
||||
self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs')
|
||||
|
||||
# Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group
|
||||
self.assertRaises(except_orm,
|
||||
self.mail_group.read,
|
||||
cr, user_bert_id, self.group_pigs_id)
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE1: Raoul, employee
|
||||
# ----------------------------------------
|
||||
# Do: Bert read Pigs, ok because public
|
||||
self.mail_group.read(cr, user_raoul_id, self.group_pigs_id)
|
||||
# Do: Bert read Jobs, ok because group_public_id = employee
|
||||
self.mail_group.read(cr, user_raoul_id, self.group_jobs_id)
|
|
@ -29,7 +29,13 @@ class res_partner(osv.osv):
|
|||
'partner_id', 'Workitems',
|
||||
readonly=True),
|
||||
}
|
||||
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context=None):
|
||||
default.update({
|
||||
'workitem_ids': [],
|
||||
})
|
||||
return super(res_partner, self).copy(cr, uid, id, default=default, context=context)
|
||||
|
||||
res_partner()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<attribute name="invisible">False</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='page_history']" position="inside">
|
||||
<group name="grp_campaign" string="Campaign">
|
||||
<group name="grp_campaign" string="Campaigns">
|
||||
<field name="workitem_ids" colspan="4" nolabel="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
|
|
|
@ -338,7 +338,7 @@ class Partner(osv.osv):
|
|||
-Paid Member: A member who has paid the membership amount."""),
|
||||
'membership_start': fields.function(
|
||||
_membership_date, multi = 'membeship_start',
|
||||
string = 'Start Membership Date', type = 'date',
|
||||
string = 'Membership Start Date', type = 'date',
|
||||
store = {
|
||||
'account.invoice': (_get_invoice_partner, ['state'], 10),
|
||||
'membership.membership_line': (_get_partner_id, ['state'], 10, ),
|
||||
|
@ -346,7 +346,7 @@ class Partner(osv.osv):
|
|||
}, help="Date from which membership becomes active."),
|
||||
'membership_stop': fields.function(
|
||||
_membership_date,
|
||||
string = 'Stop Membership Date', type='date', multi='membership_stop',
|
||||
string = 'Membership End Date', type='date', multi='membership_stop',
|
||||
store = {
|
||||
'account.invoice': (_get_invoice_partner, ['state'], 10),
|
||||
'membership.membership_line': (_get_partner_id, ['state'], 10),
|
||||
|
|
|
@ -106,6 +106,7 @@ class mrp_routing_workcenter(osv.osv):
|
|||
"""
|
||||
_name = 'mrp.routing.workcenter'
|
||||
_description = 'Work Center Usage'
|
||||
_order = 'sequence'
|
||||
_columns = {
|
||||
'workcenter_id': fields.many2one('mrp.workcenter', 'Work Center', required=True),
|
||||
'name': fields.char('Name', size=64, required=True),
|
||||
|
@ -226,6 +227,7 @@ class mrp_bom(osv.osv):
|
|||
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.bom', context=c),
|
||||
}
|
||||
_order = "sequence"
|
||||
_parent_name = "bom_id"
|
||||
_sql_constraints = [
|
||||
('bom_qty_zero', 'CHECK (product_qty>0)', 'All product quantities must be greater than 0.\n' \
|
||||
'You should install the mrp_subproduct module if you want to manage extra products on BoMs !'),
|
||||
|
@ -671,7 +673,7 @@ class mrp_production(osv.osv):
|
|||
|
||||
for (production_id,name) in self.name_get(cr, uid, ids):
|
||||
production = self.browse(cr, uid, production_id)
|
||||
if production.move_prod_id:
|
||||
if production.move_prod_id and production.move_prod_id.location_id.id != production.location_dest_id.id:
|
||||
move_obj.write(cr, uid, [production.move_prod_id.id],
|
||||
{'location_id': production.location_dest_id.id})
|
||||
self.action_ready_send_note(cr, uid, [production_id], context)
|
||||
|
@ -829,7 +831,8 @@ class mrp_production(osv.osv):
|
|||
'ref': wc.code,
|
||||
'product_id': wc.product_id.id,
|
||||
'unit_amount': wc_line.hour,
|
||||
'product_uom_id': wc.product_id.uom_id.id
|
||||
'product_uom_id': wc.product_id.id and wc.product_id.uom_id.id or False
|
||||
|
||||
} )
|
||||
if wc.costs_journal_id and wc.costs_general_account_id:
|
||||
value = wc_line.cycle * wc.costs_cycle
|
||||
|
@ -845,7 +848,8 @@ class mrp_production(osv.osv):
|
|||
'ref': wc.code,
|
||||
'product_id': wc.product_id.id,
|
||||
'unit_amount': wc_line.cycle,
|
||||
'product_uom_id': wc.product_id.uom_id.id
|
||||
'product_uom_id': wc.product_id.id and wc.product_id.uom_id.id or False
|
||||
|
||||
} )
|
||||
return amount
|
||||
|
||||
|
|
|
@ -409,8 +409,9 @@
|
|||
</page>
|
||||
</notebook>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -544,9 +545,7 @@
|
|||
<field name="name">Bill of Materials Structure</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">mrp.bom</field>
|
||||
<field name="domain">[('id','in',active_ids)]</field>
|
||||
<field name="view_type">tree</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="domain">[('bom_id', '=',active_ids)]</field>
|
||||
<field name="view_id" ref="mrp_bom_tree_view"/>
|
||||
</record>
|
||||
<record id="ir_BOM_structure" model="ir.values">
|
||||
|
@ -675,7 +674,7 @@
|
|||
<field name="product_id"/>
|
||||
<field name="product_qty" string="Quantity"/>
|
||||
<field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>
|
||||
<field name="prodlot_id" groups="stock.group_production_lot"/>
|
||||
<field name="prodlot_id" groups="stock.group_production_lot" context="{'product_id': product_id}"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<button name="%(stock.move_consume)d"
|
||||
string="Consume Products" type="action"
|
||||
|
@ -799,6 +798,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -189,6 +189,7 @@
|
|||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
|
|
@ -117,8 +117,11 @@
|
|||
<field name="stage_id" domain="[('user_id','=',uid)]" widget="statusbar" clickable="1"/>
|
||||
</header>
|
||||
<field name="memo" widget="html"/><!-- editor_width="100%%" editor_height="60%%" -->
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field class="oe_chatter" name="message_ids" widget="mail_thread"/>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<!-- Mail group for the company's news -->
|
||||
<record id="company_news_feed" model="mail.group">
|
||||
<field name="name">Company's news</field>
|
||||
<field name="public">public</field>
|
||||
</record>
|
||||
|
||||
<record id="action_news" model="ir.actions.act_window">
|
||||
|
@ -17,6 +18,7 @@
|
|||
<!-- Mail group for the company's jobs -->
|
||||
<record id="company_jobs" model="mail.group">
|
||||
<field name="name">Company's jobs</field>
|
||||
<field name="public">public</field>
|
||||
</record>
|
||||
|
||||
<record id="action_jobs" model="ir.actions.act_window">
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<field name="password">portal</field>
|
||||
<!-- Avoid auto-including this user in any default group -->
|
||||
<field name="groups_id" eval="[(5,)]"/>
|
||||
<field name="partner_id" eval="ref('base.res_partner_1')"/>
|
||||
<field name="supplier" eval="False"/>
|
||||
<field name="customer" eval="True"/>
|
||||
<field name="email">demo@portal.wrong.address</field>
|
||||
</record>
|
||||
|
||||
<!-- Add the demo user to the portal (and therefore to the portal member group) -->
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue