[MERGE] Merged lp:openobject-addons.

bzr revid: psa@tinyerp.com-20130409053450-8pb9vy1z478kxvsb
This commit is contained in:
Paramjit Singh Sahota 2013-04-09 11:04:50 +05:30
commit 8e9556a2fb
120 changed files with 2125 additions and 963 deletions

View File

@ -1027,6 +1027,9 @@ class account_period(osv.osv):
def action_draft(self, cr, uid, ids, *args):
mode = 'draft'
for period in self.browse(cr, uid, ids):
if period.fiscalyear_id.state == 'done':
raise osv.except_osv(_('Warning !'), _('You can not re-open a period which belongs to closed fiscal year'))
cr.execute('update account_journal_period set state=%s where period_id in %s', (mode, tuple(ids),))
cr.execute('update account_period set state=%s where id in %s', (mode, tuple(ids),))
return True

View File

@ -453,10 +453,11 @@
<filter name="invoices" string="Invoices" domain="[('state','not in',['draft','cancel'])]" help="Proforma/Open/Paid Invoices"/>
<filter name="unpaid" string="Unpaid" domain="[('state','=','open')]" help="Unpaid Invoices"/>
<separator/>
<filter domain="[('user_id','=',uid)]" help="My Invoices" icon="terp-personal"/>
<field name="partner_id"/>
<field name="user_id" string="Salesperson"/>
<field name="period_id" string="Period"/>
<separator/>
<filter domain="[('user_id','=',uid)]" help="My Invoices"/>
<group expand="0" string="Group By...">
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>

View File

@ -742,7 +742,7 @@ class account_move_line(osv.osv):
def list_partners_to_reconcile(self, cr, uid, context=None):
cr.execute(
"""SELECT partner_id FROM (
SELECT l.partner_id, p.last_reconciliation_date, SUM(l.debit) AS debit, SUM(l.credit) AS credit, MAX(l.date) AS max_date
SELECT l.partner_id, p.last_reconciliation_date, SUM(l.debit) AS debit, SUM(l.credit) AS credit, MAX(l.create_date) AS max_date
FROM account_move_line l
RIGHT JOIN account_account a ON (a.id = l.account_id)
RIGHT JOIN res_partner p ON (l.partner_id = p.id)
@ -753,9 +753,14 @@ class account_move_line(osv.osv):
) AS s
WHERE debit > 0 AND credit > 0 AND (last_reconciliation_date IS NULL OR max_date > last_reconciliation_date)
ORDER BY last_reconciliation_date""")
ids = cr.fetchall()
ids = len(ids) and [x[0] for x in ids] or []
return self.pool.get('res.partner').name_get(cr, uid, ids, context=context)
ids = [x[0] for x in cr.fetchall()]
if not ids:
return []
# To apply the ir_rules
partner_obj = self.pool.get('res.partner')
ids = partner_obj.search(cr, uid, [('id', 'in', ids)], context=context)
return partner_obj.name_get(cr, uid, ids, context=context)
def reconcile_partial(self, cr, uid, ids, type='auto', context=None, writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False):
move_rec_obj = self.pool.get('account.move.reconcile')

View File

@ -210,8 +210,8 @@ class account_invoice_report(osv.osv):
cr.id IN (SELECT id
FROM res_currency_rate cr2
WHERE (cr2.currency_id = sub.currency_id)
AND ((sub.date IS NOT NULL AND cr.name <= sub.date)
OR (sub.date IS NULL AND cr.name <= NOW()))
AND ((sub.date IS NOT NULL AND cr2.name <= sub.date)
OR (sub.date IS NULL AND cr2.name <= NOW()))
ORDER BY name DESC LIMIT 1)
)""" % (
self._table,

View File

@ -168,7 +168,7 @@
</para>
<para style="terp_default_8">Tel. : [[ (o.partner_id.phone) or removeParentNode('para') ]]</para>
<para style="terp_default_8">Fax : [[ (o.partner_id.fax) or removeParentNode('para') ]]</para>
<para style="terp_default_8">VAT : [[ (o.partner_id.vat) or removeParentNode('para') ]]</para>
<para style="terp_default_8">TIN : [[ (o.partner_id.vat) or removeParentNode('para') ]]</para>
</td>
</tr>
</blockTable>

View File

@ -181,9 +181,9 @@ class account_invoice_refund(osv.osv_memory):
invoice = invoice[0]
del invoice['id']
invoice_lines = inv_line_obj.browse(cr, uid, invoice['invoice_line'], context=context)
invoice_lines = inv_obj._refund_cleanup_lines(cr, uid, invoice_lines)
invoice_lines = inv_obj._refund_cleanup_lines(cr, uid, invoice_lines, context=context)
tax_lines = inv_tax_obj.browse(cr, uid, invoice['tax_line'], context=context)
tax_lines = inv_obj._refund_cleanup_lines(cr, uid, tax_lines)
tax_lines = inv_obj._refund_cleanup_lines(cr, uid, tax_lines, context=context)
invoice.update({
'type': inv.type,
'date_invoice': date,

View File

@ -352,11 +352,10 @@ class account_analytic_account(osv.osv):
res[account.id] = 0.0
sale_ids = sale_obj.search(cr, uid, [('project_id','=', account.id), ('state', '=', 'manual')], context=context)
for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
if not sale.invoiced:
res[account.id] += sale.amount_untaxed
for invoice in sale.invoice_ids:
if invoice.state not in ('draft', 'cancel'):
res[account.id] -= invoice.amount_untaxed
res[account.id] += sale.amount_untaxed
for invoice in sale.invoice_ids:
if invoice.state != 'cancel':
res[account.id] -= invoice.amount_untaxed
return res
def _timesheet_ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None):

View File

@ -267,7 +267,7 @@
</field>
</record>
<menuitem id="base.menu_sales" name="Sales" parent="base.menu_base_partner" sequence="1"/>
<menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="7" parent="base.menu_sales"/>
<menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="8" parent="base.menu_sales"/>
<!-- Action Sales/Invoicing/Time and Material to Invoice -->
<record id="action_hr_tree_invoiced_all" model="ir.actions.act_window">

View File

@ -7,19 +7,19 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2011-01-30 16:46+0000\n"
"Last-Translator: Krisztian Eyssen <krisz@eyssen.hu>\n"
"PO-Revision-Date: 2013-04-04 13:17+0000\n"
"Last-Translator: krnkris <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-03-16 05:42+0000\n"
"X-Generator: Launchpad (build 16532)\n"
"X-Launchpad-Export-Date: 2013-04-05 05:37+0000\n"
"X-Generator: Launchpad (build 16550)\n"
#. module: account_cancel
#: view:account.invoice:0
msgid "Cancel"
msgstr ""
msgstr "Sztornó"
#~ msgid "Account Cancel"
#~ msgstr "Érvénytelenítés"

File diff suppressed because it is too large Load Diff

View File

@ -7,19 +7,19 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
"PO-Revision-Date: 2013-03-26 15:03+0000\n"
"PO-Revision-Date: 2013-04-04 11:34+0000\n"
"Last-Translator: krnkris <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-03-27 04:36+0000\n"
"X-Generator: Launchpad (build 16540)\n"
"X-Launchpad-Export-Date: 2013-04-05 05:37+0000\n"
"X-Generator: Launchpad (build 16550)\n"
#. module: account_voucher
#: field:account.bank.statement.line,voucher_id:0
msgid "Reconciliation"
msgstr ""
msgstr "Párosítás"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_config_settings
@ -51,7 +51,7 @@ msgstr "Nyitott vevő tételek"
#: view:account.voucher:0
#: view:sale.receipt.report:0
msgid "Group By..."
msgstr "Csoportosítás"
msgstr "Csoportosítás ezzel..."
#. module: account_voucher
#: help:account.voucher,writeoff_amount:0
@ -102,7 +102,7 @@ msgstr "Számla kifizetése"
#. module: account_voucher
#: view:account.voucher:0
msgid "Are you sure you want to cancel this receipt?"
msgstr ""
msgstr "Biztos, hogy vissza akarja vonni ezt a bevételi bizonylatot?"
#. module: account_voucher
#: view:account.voucher:0
@ -137,6 +137,8 @@ msgid ""
"You can not change the journal as you already reconciled some statement "
"lines!"
msgstr ""
"Nem tudja a naplót megváltoztatni mivel a kivonatok egyes sorait már "
"párosította!"
#. module: account_voucher
#: view:account.voucher:0
@ -160,6 +162,15 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Kattintson vásárlási bevételi bizonylat rögzítéséhez. \n"
" </p><p>\n"
" Ha a vásárlási bevételi bizonylat igazolva lett, rögzítheti "
"a \n"
" vásárlási bevételi bizonylathoz kapcsolódó beszállítói "
"kifizetést.\n"
" </p>\n"
" "
#. module: account_voucher
#: view:account.voucher:0
@ -169,7 +180,7 @@ msgstr "Nyugták keresése"
#. module: account_voucher
#: field:account.voucher,writeoff_acc_id:0
msgid "Counterpart Account"
msgstr ""
msgstr "Ellenszámla"
#. module: account_voucher
#: field:account.voucher,account_id:0
@ -191,7 +202,7 @@ msgstr "Rendben"
#. module: account_voucher
#: field:account.voucher.line,reconcile:0
msgid "Full Reconcile"
msgstr ""
msgstr "Teljes párosítás"
#. module: account_voucher
#: field:account.voucher,date_due:0
@ -215,7 +226,7 @@ msgstr "Üzenetek"
#: model:ir.actions.act_window,name:account_voucher.action_purchase_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_purchase_receipt
msgid "Purchase Receipts"
msgstr ""
msgstr "Vásárlások bevételi bizonylatai"
#. module: account_voucher
#: field:account.voucher.line,move_line_id:0
@ -271,11 +282,18 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Kattintson értékesítési bevételi bizonylat létrehozásához.\n"
" </p><p>\n"
" Ha az értékesítési bizonylat igazolva lett, rögzítheti az \n"
" értékesítéshez tartozó vevői befizetést.\n"
" </p>\n"
" "
#. module: account_voucher
#: help:account.voucher,message_unread:0
msgid "If checked new messages require your attention."
msgstr ""
msgstr "Ha be van jelölve, akkor figyelje az új üzeneteket."
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_bank_statement_line
@ -298,17 +316,17 @@ msgstr "ÁFA"
#: code:addons/account_voucher/account_voucher.py:879
#, python-format
msgid "Invalid Action!"
msgstr ""
msgstr "Érvénytelen lépés!"
#. module: account_voucher
#: field:account.voucher,comment:0
msgid "Counterpart Comment"
msgstr ""
msgstr "Ellenoldali meglyegyzés"
#. module: account_voucher
#: field:account.voucher.line,account_analytic_id:0
msgid "Analytic Account"
msgstr "Gyűjtőkód"
msgstr "Gyűjtő/elemző könyvelés"
#. module: account_voucher
#: help:account.voucher,message_summary:0
@ -316,11 +334,13 @@ msgid ""
"Holds the Chatter summary (number of messages, ...). This summary is "
"directly in html format in order to be inserted in kanban views."
msgstr ""
"A chettelés összegzést megállítja (üzenetek száma,...). Ez az összegzés "
"direkt HTML formátumú ahhoz hogy beilleszthető legyen a kanban nézetekbe."
#. module: account_voucher
#: view:account.voucher:0
msgid "Total Allocation"
msgstr ""
msgstr "Összes kiosztás"
#. module: account_voucher
#: view:account.voucher:0
@ -330,7 +350,7 @@ msgstr "Fizetési információ"
#. module: account_voucher
#: view:account.voucher:0
msgid "(update)"
msgstr ""
msgstr "(frissítés)"
#. module: account_voucher
#: view:account.voucher:0
@ -349,20 +369,20 @@ msgstr "Számlák importálása"
#: code:addons/account_voucher/account_voucher.py:1112
#, python-format
msgid "Wrong voucher line"
msgstr "Nem megfelelő nyugta sorok"
msgstr "Nem megfelelő nyugta sor"
#. module: account_voucher
#: selection:account.voucher,pay_now:0
#: selection:sale.receipt.report,pay_now:0
msgid "Pay Later or Group Funds"
msgstr "Későbbi fizetés"
msgstr "Fizessen később vagy csoportosítsa a pénzeket"
#. module: account_voucher
#: view:account.voucher:0
#: selection:account.voucher,type:0
#: selection:sale.receipt.report,type:0
msgid "Receipt"
msgstr "Befizetés"
msgstr "Bevételi bizonylat"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1018
@ -372,6 +392,9 @@ msgid ""
"settings, to manage automatically the booking of accounting entries related "
"to differences between exchange rates."
msgstr ""
"Be kell állítani a 'Átváltási arány nyereség számlája' a könyvelés "
"beállításainál, ahhoz, hogy kezelni tudja az automatikus könyvelését azoknak "
"a számla tételeknek, melyek az átváltási arányok különbségéből adódhatnak."
#. module: account_voucher
#: view:account.voucher:0
@ -399,7 +422,7 @@ msgstr "Szállítói nyugta"
#. module: account_voucher
#: field:account.voucher,message_follower_ids:0
msgid "Followers"
msgstr ""
msgstr "Követők"
#. module: account_voucher
#: selection:account.voucher.line,type:0
@ -410,13 +433,13 @@ msgstr "Tartozik"
#: code:addons/account_voucher/account_voucher.py:1547
#, python-format
msgid "Unable to change journal !"
msgstr ""
msgstr "Naplót nem lehet megváltoztatni !"
#. module: account_voucher
#: view:sale.receipt.report:0
#: field:sale.receipt.report,nbr:0
msgid "# of Voucher Lines"
msgstr "Nyugtasorok száma"
msgstr "# nyugta sor száma"
#. module: account_voucher
#: view:sale.receipt.report:0
@ -446,6 +469,13 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Kattintson új beszállítói fizetés létrehozásához.\n"
" </p><p>\n"
" OpenERP segít a kifizetéseinek, valamint a beszállítók "
"részére még fizetendő mérleg könnyű nyomon követéséhez.\n"
" </p>\n"
" "
#. module: account_voucher
#: view:account.voucher:0
@ -460,12 +490,12 @@ msgstr "Nyugta tételek"
#. module: account_voucher
#: field:account.voucher,name:0
msgid "Memo"
msgstr "Megnevezés"
msgstr "Emlékeztető"
#. module: account_voucher
#: view:account.voucher:0
msgid "Are you sure to unreconcile and cancel this record ?"
msgstr ""
msgstr "Biztosan visszavonja a bejegyzés párosítását?"
#. module: account_voucher
#: field:account.voucher,is_multi_currency:0
@ -494,17 +524,25 @@ msgid ""
"\n"
"* The 'Cancelled' status is used when user cancel voucher."
msgstr ""
" * A 'Tervezet' állapotot használja amint egy felhasználó létrehoz egy új és "
"még le nem igazolt nyugtát. \n"
"* 'Pro-forma' lesz, ha a nyugta Pro-forma állapotú, a nyugtának még nincs "
"nyugta száma. \n"
"* 'Elküldött' állapotú, ha egy felhasználó létrehozta a nyugtát, egy nyugta "
"számot generált hozzá, és a könyvelésben egy nyugta bevitel létre lett hozva "
" \n"
"* A 'Visszavonva' állapot lesz, ha egy felhasználó visszavonta a nyugtát."
#. module: account_voucher
#: field:account.voucher,writeoff_amount:0
msgid "Difference Amount"
msgstr ""
msgstr "Különbség számla"
#. module: account_voucher
#: view:sale.receipt.report:0
#: field:sale.receipt.report,due_delay:0
msgid "Avg. Due Delay"
msgstr "Álagos fizetési határidő"
msgstr "Álagos fizetési késedelem"
#. module: account_voucher
#: code:addons/account_voucher/invoice.py:34
@ -543,12 +581,24 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Kattintson új kifizetés rögzítéséhez. \n"
" </p><p>\n"
" Vigye be a vásárlót és a fizetési módot és utána, vagy "
"hozzon\n"
" létre kézzel egy fizetési rekordot, vagy az OpenERP fel fog "
"ajánlani\n"
" automatikusan a fizetéshez tartozó összeegyeztetést a\n"
" nyitott számlákkal vagy értékesítési bevételi "
"bizonylatokkal.\n"
" </p>\n"
" "
#. module: account_voucher
#: field:account.config.settings,expense_currency_exchange_account_id:0
#: field:res.company,expense_currency_exchange_account_id:0
msgid "Loss Exchange Rate Account"
msgstr ""
msgstr "Árfolyamveszteség számla"
#. module: account_voucher
#: view:account.voucher:0
@ -572,7 +622,7 @@ msgstr "Ellenőrizendő"
#: code:addons/account_voucher/account_voucher.py:1194
#, python-format
msgid "change"
msgstr ""
msgstr "módosítás"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1014
@ -582,6 +632,9 @@ msgid ""
"settings, to manage automatically the booking of accounting entries related "
"to differences between exchange rates."
msgstr ""
"Be kell állítani a 'Árfolyamveszteség számla' a könyvelés beállításoknál, "
"ahhoz, hogy kezelni tudja automatikusan a könyvelési tételek rögzítését, "
"melyek az átváltási árfolyam különbségekkel összefüggenek."
#. module: account_voucher
#: view:account.voucher:0
@ -599,11 +652,13 @@ msgid ""
"Fields with internal purpose only that depicts if the voucher is a multi "
"currency one or not"
msgstr ""
"Belső használatú mezők, melyek azt ábrázolják, hogy a nyugták több "
"pénzneműek vagy nem"
#. module: account_voucher
#: view:account.invoice:0
msgid "Register Payment"
msgstr "Kifizetés"
msgstr "Kifizetés rögzítés"
#. module: account_voucher
#: field:account.statement.from.invoice.lines,line_ids:0
@ -618,7 +673,7 @@ msgstr "December"
#. module: account_voucher
#: view:sale.receipt.report:0
msgid "Group by month of Invoice Date"
msgstr ""
msgstr "Csoportosítás számla dátuma alapján"
#. module: account_voucher
#: view:sale.receipt.report:0
@ -636,7 +691,7 @@ msgstr "Pénznem"
#. module: account_voucher
#: view:account.statement.from.invoice.lines:0
msgid "Payable and Receivables"
msgstr "Vevők és szállítók"
msgstr "Fizetendők & Bevételek"
#. module: account_voucher
#: view:account.voucher:0
@ -651,7 +706,7 @@ msgstr "Nyugta állapota"
#. module: account_voucher
#: view:account.voucher:0
msgid "Are you sure to unreconcile this record?"
msgstr ""
msgstr "Biztosan törölni szeretné ennek a rekordnak a párosítását?"
#. module: account_voucher
#: field:account.voucher,company_id:0
@ -664,18 +719,18 @@ msgstr "Vállalat"
#. module: account_voucher
#: help:account.voucher,paid:0
msgid "The Voucher has been totally paid."
msgstr "A nyugta ki lett egyenlítve"
msgstr "A nyugta teljesen ki lett egyenlítve"
#. module: account_voucher
#: selection:account.voucher,payment_option:0
msgid "Reconcile Payment Balance"
msgstr ""
msgstr "Fizetési egyenleg párosítás"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:975
#, python-format
msgid "Configuration Error !"
msgstr ""
msgstr "Beállítási hiba!"
#. module: account_voucher
#: view:account.voucher:0
@ -687,7 +742,7 @@ msgstr "Nyugta tervezetek"
#: view:sale.receipt.report:0
#: field:sale.receipt.report,price_total_tax:0
msgid "Total With Tax"
msgstr "Bruttó érték"
msgstr "Bruttó érték adóval"
#. module: account_voucher
#: view:account.voucher:0
@ -699,18 +754,18 @@ msgstr "Beszerzési nyugta"
#: field:account.voucher,state:0
#: view:sale.receipt.report:0
msgid "Status"
msgstr ""
msgstr "Állapot"
#. module: account_voucher
#: view:account.voucher:0
msgid "Allocation"
msgstr ""
msgstr "Kiosztás"
#. module: account_voucher
#: view:account.statement.from.invoice.lines:0
#: view:account.voucher:0
msgid "or"
msgstr ""
msgstr "vagy"
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@ -720,7 +775,7 @@ msgstr "Augusztus"
#. module: account_voucher
#: view:account.voucher:0
msgid "Validate Payment"
msgstr ""
msgstr "Fizetés jóváhagyása"
#. module: account_voucher
#: help:account.voucher,audit:0
@ -728,6 +783,8 @@ msgid ""
"Check this box if you are unsure of that journal entry and if you want to "
"note it as 'to be reviewed' by an accounting expert."
msgstr ""
"Jelölje be, ha bizonytalan a napló tétel kontírozásában. Ennek hatására "
"könyvelő szekértő által 'ellenőrizendő'-ként jelölődik meg."
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@ -738,7 +795,7 @@ msgstr "Október"
#: code:addons/account_voucher/account_voucher.py:976
#, python-format
msgid "Please activate the sequence of selected journal !"
msgstr ""
msgstr "Kérem a sorozat aktiválását a kiválasztott naplóra !"
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@ -748,23 +805,23 @@ msgstr "Június"
#. module: account_voucher
#: field:account.voucher,payment_rate_currency_id:0
msgid "Payment Rate Currency"
msgstr ""
msgstr "Fizetési pénznem aránya"
#. module: account_voucher
#: field:account.voucher,paid:0
msgid "Paid"
msgstr ""
msgstr "Rendezett"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_sale_receipt
msgid "Sales Receipts"
msgstr ""
msgstr "Értékesítési bevételi bizonylatok"
#. module: account_voucher
#: field:account.voucher,message_is_follower:0
msgid "Is a Follower"
msgstr ""
msgstr "Ez egy követő"
#. module: account_voucher
#: field:account.voucher,analytic_id:0
@ -791,7 +848,7 @@ msgstr "Kiterjesztett szűrők"
#. module: account_voucher
#: field:account.voucher,paid_amount_in_company_currency:0
msgid "Paid Amount in Company Currency"
msgstr ""
msgstr "Kifizetett összeg a vállalat pénznemében"
#. module: account_voucher
#: field:account.bank.statement.line,amount_reconciled:0
@ -807,7 +864,7 @@ msgstr "Azonnali kifizetés"
#. module: account_voucher
#: field:account.voucher.line,type:0
msgid "Dr/Cr"
msgstr ""
msgstr "T/K"
#. module: account_voucher
#: field:account.voucher,pre_line:0
@ -818,7 +875,7 @@ msgstr "Előző kifizetések ?"
#: code:addons/account_voucher/account_voucher.py:1112
#, python-format
msgid "The invoice you are willing to pay is not valid anymore."
msgstr ""
msgstr "A kifizetni kívánt számla már nem érvényes."
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@ -829,52 +886,52 @@ msgstr "Január"
#: model:ir.actions.act_window,name:account_voucher.action_voucher_list
#: model:ir.ui.menu,name:account_voucher.menu_encode_entries_by_voucher
msgid "Journal Vouchers"
msgstr "Nyugták"
msgstr "Nyugták naplói"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_res_company
msgid "Companies"
msgstr ""
msgstr "Vállalatok"
#. module: account_voucher
#: field:account.voucher,message_summary:0
msgid "Summary"
msgstr ""
msgstr "Összegzés"
#. module: account_voucher
#: field:account.voucher,active:0
msgid "Active"
msgstr ""
msgstr "Aktív"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:982
#, python-format
msgid "Please define a sequence on the journal."
msgstr ""
msgstr "Kérem egy sorozat meghatározását a naplón."
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.act_pay_voucher
#: model:ir.actions.act_window,name:account_voucher.action_vendor_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_vendor_receipt
msgid "Customer Payments"
msgstr ""
msgstr "Vevői befizetések"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt_report_all
#: model:ir.ui.menu,name:account_voucher.menu_action_sale_receipt_report_all
#: view:sale.receipt.report:0
msgid "Sales Receipts Analysis"
msgstr ""
msgstr "Értékesítési bevételi bizonylatok elemzései"
#. module: account_voucher
#: view:sale.receipt.report:0
msgid "Group by Invoice Date"
msgstr ""
msgstr "Számla dátuma szerinti csoportosítása"
#. module: account_voucher
#: view:account.voucher:0
msgid "Post"
msgstr "Könyvelés"
msgstr "Elküld"
#. module: account_voucher
#: view:account.voucher:0
@ -885,7 +942,7 @@ msgstr "Számlák és kifizetetlen tételek"
#: view:sale.receipt.report:0
#: field:sale.receipt.report,price_total:0
msgid "Total Without Tax"
msgstr "Nettó érték"
msgstr "Nettó, adó nélküli érték"
#. module: account_voucher
#: view:account.voucher:0
@ -921,7 +978,7 @@ msgstr "Bankkivonat"
#. module: account_voucher
#: view:account.bank.statement:0
msgid "onchange_amount(amount)"
msgstr ""
msgstr "onchange_amount(amount)"
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@ -954,19 +1011,19 @@ msgstr "Nyugta tételsorok"
#: view:account.statement.from.invoice.lines:0
#: view:account.voucher:0
msgid "Cancel"
msgstr "Mégsem"
msgstr "Visszavonás"
#. module: account_voucher
#: model:ir.actions.client,name:account_voucher.action_client_invoice_menu
msgid "Open Invoicing Menu"
msgstr ""
msgstr "Számlázási menü megnyitása"
#. module: account_voucher
#: selection:account.voucher,state:0
#: view:sale.receipt.report:0
#: selection:sale.receipt.report,state:0
msgid "Pro-forma"
msgstr "Pro forma"
msgstr "Pro-forma"
#. module: account_voucher
#: view:account.voucher:0
@ -979,6 +1036,8 @@ msgstr "Könyvelési tételsorok"
#, python-format
msgid "Please define default credit/debit accounts on the journal \"%s\"."
msgstr ""
"Kérem meghatározni az alapértelmezett követelés/tartozás könyvelést a naplón "
"\"%s\"."
#. module: account_voucher
#: selection:account.voucher,type:0
@ -995,7 +1054,7 @@ msgstr "Fizetés"
#. module: account_voucher
#: view:account.voucher:0
msgid "Currency Options"
msgstr ""
msgstr "Pénznem lehetőségek"
#. module: account_voucher
#: help:account.voucher,payment_option:0
@ -1005,6 +1064,10 @@ msgid ""
"either choose to keep open this difference on the partner's account, or "
"reconcile it with the payment(s)"
msgstr ""
"Ez a mező megkönnyíti a választást ahhoz, hogy mit szeretne tenni a "
"kifizetett összeg és a kiosztott összeg közti különbségekkel. Hagyhatja "
"nyitottan ezt a különbséget a partner számláján, vagy párosíthatja a "
"fizetés(ek)el."
#. module: account_voucher
#: model:ir.actions.act_window,help:account_voucher.action_sale_receipt_report_all
@ -1018,16 +1081,24 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p>\n"
" Erről a jelentésről, a vevőnek elküldött számlákról és fizetési\n"
" határidőkről és késve fizetésről áttekintést kaphat. A \n"
" keresési eszköz használható a számla beszámolók személyre\n"
" szabásához és így, az elemzést az igényének megfelelően "
"alakíthatja.\n"
" </p>\n"
" "
#. module: account_voucher
#: view:account.voucher:0
msgid "Posted Vouchers"
msgstr ""
msgstr "Elküldött nyugták"
#. module: account_voucher
#: field:account.voucher,payment_rate:0
msgid "Exchange Rate"
msgstr ""
msgstr "Árfolyam arány"
#. module: account_voucher
#: view:account.voucher:0
@ -1047,7 +1118,7 @@ msgstr "Május"
#. module: account_voucher
#: view:account.voucher:0
msgid "Sale Receipt"
msgstr ""
msgstr "Értékesítési bevételi bizonylat"
#. module: account_voucher
#: view:account.voucher:0
@ -1066,7 +1137,7 @@ msgstr "Belső megjegyzések"
#: view:account.voucher:0
#: field:account.voucher,line_cr_ids:0
msgid "Credits"
msgstr "Követel"
msgstr "Követelések"
#. module: account_voucher
#: field:account.voucher.line,amount_original:0
@ -1076,7 +1147,7 @@ msgstr "Eredeti összeg"
#. module: account_voucher
#: view:account.voucher:0
msgid "Purchase Receipt"
msgstr ""
msgstr "Vásárlási bevételi bizonylatok"
#. module: account_voucher
#: help:account.voucher,payment_rate:0
@ -1084,6 +1155,8 @@ msgid ""
"The specific rate that will be used, in this voucher, between the selected "
"currency (in 'Payment Rate Currency' field) and the voucher currency."
msgstr ""
"Az arány, mely ezen nyugtán lesz használva, a kiválasztott pénznem (a "
"'Fizetési pénznem aránya' mezőben) és a nyugta pénzneme közt."
#. module: account_voucher
#: view:account.voucher:0
@ -1115,12 +1188,12 @@ msgstr "Február"
#. module: account_voucher
#: view:account.voucher:0
msgid "Supplier Invoices and Outstanding transactions"
msgstr "Bejövő számlák és kifizetetlen tételek"
msgstr "Beszállítók bejövő számlái és kifizetetlen tételek"
#. module: account_voucher
#: field:account.voucher,reference:0
msgid "Ref #"
msgstr "Hiv. szám"
msgstr "Hiv. szám #"
#. module: account_voucher
#: view:sale.receipt.report:0
@ -1132,7 +1205,7 @@ msgstr "Év"
#: field:account.config.settings,income_currency_exchange_account_id:0
#: field:res.company,income_currency_exchange_account_id:0
msgid "Gain Exchange Rate Account"
msgstr ""
msgstr "Árfolyamnyereség számla"
#. module: account_voucher
#: selection:account.voucher,type:0
@ -1148,7 +1221,7 @@ msgstr "Április"
#. module: account_voucher
#: help:account.voucher,tax_id:0
msgid "Only for tax excluded from price"
msgstr ""
msgstr "Csak az árakból kihagyott adók"
#. module: account_voucher
#: field:account.voucher,type:0
@ -1158,7 +1231,7 @@ msgstr "Alapértelmezett típus"
#. module: account_voucher
#: help:account.voucher,message_ids:0
msgid "Messages and communication history"
msgstr ""
msgstr "Üzenetek és kommunikációs történet"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_statement_from_invoice_lines
@ -1182,12 +1255,16 @@ msgid ""
"The amount of the voucher must be the same amount as the one on the "
"statement line."
msgstr ""
"A nyugtán lévő összegnek ugyanannak kell lennie mint ami a kivonat sorában "
"szerepel."
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:879
#, python-format
msgid "Cannot delete voucher(s) which are already opened or paid."
msgstr ""
"Nem lehet olyan nyugtá(ka)t törölni, melyek meg lettek nyitva vagy ki lettek "
"fozetve."
#. module: account_voucher
#: help:account.voucher,date:0
@ -1197,7 +1274,7 @@ msgstr "Könyvelési tételek teljesítési dátuma"
#. module: account_voucher
#: model:mail.message.subtype,name:account_voucher.mt_voucher_state_change
msgid "Status Change"
msgstr ""
msgstr "Állapotváltozás"
#. module: account_voucher
#: selection:account.voucher,payment_option:0
@ -1225,7 +1302,7 @@ msgstr "Nettó érték"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_sale_receipt_report
msgid "Sales Receipt Statistics"
msgstr "Értékesítési nyugta statisztika"
msgstr "Értékesítési bevételi bizonylatok statisztikái"
#. module: account_voucher
#: view:account.voucher:0
@ -1244,14 +1321,14 @@ msgstr "Nyitott egyenleg"
#. module: account_voucher
#: model:mail.message.subtype,description:account_voucher.mt_voucher_state_change
msgid "Status <b>changed</b>"
msgstr ""
msgstr "Állapot <b>megváltozott</b>"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1014
#: code:addons/account_voucher/account_voucher.py:1018
#, python-format
msgid "Insufficient Configuration!"
msgstr ""
msgstr "Nem megfelelő beállítás!"
#. module: account_voucher
#: help:account.voucher,active:0
@ -1260,6 +1337,9 @@ msgid ""
"inactive, which allow to hide the customer/supplier payment while the bank "
"statement isn't confirmed."
msgstr ""
"Alapértelmezetten, a tervezet bank kivonathoz párosított nyugták nem lesznek "
"aktívak, így el lehet tüntetni a vevő/beszállító fizetéseket amíg a banki "
"kivonatok nem kerülnek jóváhagyásra."
#~ msgid "Particulars"
#~ msgstr "Adatok"
@ -1310,9 +1390,6 @@ msgstr ""
#~ msgid "Want to remove accounting entries too ?"
#~ msgstr "A könyvelési tételeket is törölni szeretné?"
#~ msgid "Sales Receipt"
#~ msgstr "Nyugta"
#~ msgid "Unreconciliation"
#~ msgstr "Párosítás visszavonása"
@ -1485,3 +1562,6 @@ msgstr ""
#~ msgid "Canceled"
#~ msgstr "Érvénytelenített"
#~ msgid "Sales Receipt"
#~ msgstr "Értékesítési bevételi bizonylat"

View File

@ -5,6 +5,7 @@ openerp.auth_oauth = function(instance) {
start: function(parent, params) {
var self = this;
var d = this._super.apply(this, arguments);
this.$el.hide();
this.$el.on('click', 'a.zocial', this.on_oauth_sign_in);
this.oauth_providers = [];
if(this.params.oauth_error === 1) {
@ -24,6 +25,8 @@ openerp.auth_oauth = function(instance) {
var db = this.$("form [name=db]").val();
if (db) {
this.rpc("/auth_oauth/list_providers", { dbname: db }).done(this.on_oauth_loaded);
} else {
this.$el.show();
}
},
on_oauth_loaded: function(result) {
@ -32,6 +35,7 @@ openerp.auth_oauth = function(instance) {
if (this.oauth_providers.length === 1 && params.type === 'signup') {
this.do_oauth_sign_in(this.oauth_providers[0]);
} else {
this.$el.show();
this.$('.oe_oauth_provider_login_button').remove();
var buttons = QWeb.render("auth_oauth.Login.button",{"widget":this});
this.$(".oe_login_pane form ul").after(buttons);
@ -57,7 +61,7 @@ openerp.auth_oauth = function(instance) {
state: JSON.stringify(state),
};
var url = provider.auth_endpoint + '?' + $.param(params);
window.location = url;
instance.web.redirect(url);
},
_oauth_state: function(provider) {
// return the state object sent back with the redirected uri

View File

@ -419,8 +419,10 @@ instance.board.AddToDashboard = instance.web.search.Input.extend({
instance.web.SearchView.include({
add_common_inputs: function() {
this._super();
(new instance.board.AddToDashboard(this));
var vm = this.getParent().getParent();
if (vm.inner_action && vm.inner_action.views) {
(new instance.board.AddToDashboard(this));
}
}
});

View File

@ -81,6 +81,8 @@ Dashboard for CRM will include:
'crm_lead_view.xml',
'crm_lead_menu.xml',
'crm_case_section_view.xml',
'crm_meeting_menu.xml',
'crm_phonecall_view.xml',
@ -103,20 +105,37 @@ Dashboard for CRM will include:
'crm_action_rule_demo.xml',
],
'test': [
'test/process/communication_with_customer.yml',
'test/process/lead2opportunity2win.yml',
'test/process/lead2opportunity_assign_salesmen.yml',
'test/process/merge_opportunity.yml',
'test/process/cancel_lead.yml',
'test/process/segmentation.yml',
'test/process/phonecalls.yml',
'test/ui/crm_demo.yml',
'test/ui/duplicate_lead.yml',
'test/ui/delete_lead.yml',
'test/crm_lead_message.yml',
'test/lead2opportunity2win.yml',
'test/lead2opportunity_assign_salesmen.yml',
'test/crm_lead_merge.yml',
'test/crm_lead_cancel.yml',
'test/segmentation.yml',
'test/phonecalls.yml',
'test/crm_lead_onchange.yml',
'test/crm_lead_copy.yml',
'test/crm_lead_unlink.yml',
],
'css': [
'static/src/css/crm.css'
],
'js': [
'static/src/js/crm.js'
],
'installable': True,
'application': True,
'auto_install': False,
'images': ['images/crm_dashboard.png', 'images/customers.png','images/leads.png','images/opportunities_kanban.png','images/opportunities_form.png','images/opportunities_calendar.png','images/opportunities_graph.png','images/logged_calls.png','images/scheduled_calls.png','images/stages.png'],
'images': [
'images/crm_dashboard.png',
'images/customers.png',
'images/leads.png',
'images/opportunities_kanban.png',
'images/opportunities_form.png',
'images/opportunities_calendar.png',
'images/opportunities_graph.png',
'images/logged_calls.png',
'images/scheduled_calls.png',
'images/stages.png',
],
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -98,6 +98,7 @@ class crm_case_stage(osv.osv):
'case_default': True,
}
class crm_case_section(osv.osv):
""" Model for sales teams. """
_name = "crm.case.section"
@ -107,7 +108,7 @@ class crm_case_section(osv.osv):
_order = "complete_name"
def get_full_name(self, cr, uid, ids, field_name, arg, context=None):
return dict(self.name_get(cr, uid, ids, context=context))
return dict(self.name_get(cr, uid, ids, context=context))
_columns = {
'name': fields.char('Sales Team', size=64, required=True, translate=True),
@ -117,27 +118,36 @@ class crm_case_section(osv.osv):
"true, it will allow you to hide the sales team without removing it."),
'change_responsible': fields.boolean('Reassign Escalated', help="When escalating to this team override the salesman with the team leader."),
'user_id': fields.many2one('res.users', 'Team Leader'),
'member_ids':fields.many2many('res.users', 'sale_member_rel', 'section_id', 'member_id', 'Team Members'),
'member_ids': fields.many2many('res.users', 'sale_member_rel', 'section_id', 'member_id', 'Team Members'),
'reply_to': fields.char('Reply-To', size=64, help="The email address put in the 'Reply-To' of all emails sent by OpenERP about cases in this sales team"),
'parent_id': fields.many2one('crm.case.section', 'Parent Team'),
'child_ids': fields.one2many('crm.case.section', 'parent_id', 'Child Teams'),
'resource_calendar_id': fields.many2one('resource.calendar', "Working Time", help="Used to compute open days"),
'note': fields.text('Description'),
'working_hours': fields.float('Working Hours', digits=(16,2 )),
'working_hours': fields.float('Working Hours', digits=(16, 2)),
'stage_ids': fields.many2many('crm.case.stage', 'section_stage_rel', 'section_id', 'stage_id', 'Stages'),
'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True,
help="The email address associated with this team. New emails received will automatically "
"create new leads assigned to the team."),
'open_lead_ids': fields.one2many('crm.lead', 'section_id',
string='Open Leads', readonly=True,
domain=['&', ('type', '!=', 'opportunity'), ('state', 'not in', ['done', 'cancel'])]),
'open_opportunity_ids': fields.one2many('crm.lead', 'section_id',
string='Open Opportunities', readonly=True,
domain=['&', '|', ('type', '=', 'opportunity'), ('type', '=', 'both'), ('state', 'not in', ['done', 'cancel'])]),
'color': fields.integer('Color Index'),
'use_leads': fields.boolean('Leads',
help="This enables the management of leads in the sales team. Otherwise the sales team manages only opportunities."),
}
def _get_stage_common(self, cr, uid, context):
ids = self.pool.get('crm.case.stage').search(cr, uid, [('case_default','=',1)], context=context)
ids = self.pool.get('crm.case.stage').search(cr, uid, [('case_default', '=', 1)], context=context)
return ids
_defaults = {
'active': 1,
'stage_ids': _get_stage_common,
'alias_domain': False, # always hide alias during creation
'use_leads': True,
}
_sql_constraints = [
@ -150,7 +160,7 @@ class crm_case_section(osv.osv):
def name_get(self, cr, uid, ids, context=None):
"""Overrides orm name_get method"""
if not isinstance(ids, list) :
if not isinstance(ids, list):
ids = [ids]
res = []
if not ids:
@ -167,20 +177,20 @@ class crm_case_section(osv.osv):
def create(self, cr, uid, vals, context=None):
mail_alias = self.pool.get('mail.alias')
if not vals.get('alias_id'):
vals.pop('alias_name', None) # prevent errors during copy()
alias_name = vals.pop('alias_name', None) or vals.get('name') # prevent errors during copy()
alias_id = mail_alias.create_unique_alias(cr, uid,
{'alias_name': vals['name']},
{'alias_name': alias_name},
model_name="crm.lead",
context=context)
vals['alias_id'] = alias_id
res = super(crm_case_section, self).create(cr, uid, vals, context)
mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'section_id': res, 'type':'lead'}}, context)
mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'section_id': res, 'type': 'lead'}}, context)
return res
def unlink(self, cr, uid, ids, context=None):
# Cascade-delete mail aliases as well, as they should not exist without the sales team.
mail_alias = self.pool.get('mail.alias')
alias_ids = [team.alias_id.id for team in self.browse(cr, uid, ids, context=context) if team.alias_id ]
alias_ids = [team.alias_id.id for team in self.browse(cr, uid, ids, context=context) if team.alias_id]
res = super(crm_case_section, self).unlink(cr, uid, ids, context=context)
mail_alias.unlink(cr, uid, alias_ids, context=context)
return res
@ -230,4 +240,5 @@ class crm_payment_mode(osv.osv):
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,294 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- CRM lead search by Salesteams -->
<record model="ir.actions.act_window" id="crm_case_form_view_salesteams_lead">
<field name="name">Leads</field>
<field name="res_model">crm.lead</field>
<field name="view_mode">tree,form</field>
<field name="domain">['|', ('type','=','lead'), ('type','=',False)]</field>
<field name="view_id" ref="crm_case_tree_view_leads"/>
<field name="search_view_id" ref="crm.view_crm_case_leads_filter"/>
<field name="context">{
'search_default_section_id': [active_id],
'search_default_open': 1,
'default_section_id': active_id,
'default_type': 'lead',
'stage_type': 'lead',
}
</field>
<field name="help" type="html">
<p>
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/or a new customer in your address book.
</p>
</field>
</record>
<!-- CRM opportunity search by Salesteams -->
<record model="ir.actions.act_window" id="crm_case_form_view_salesteams_opportunity">
<field name="name">Opportunities</field>
<field name="res_model">crm.lead</field>
<field name="view_mode">kanban,tree,graph,form,calendar</field>
<field name="domain">[('type','=','opportunity')]</field>
<field name="view_id" ref="crm.crm_case_kanban_view_leads"/>
<field name="search_view_id" ref="crm.view_crm_case_opportunities_filter"/>
<field name="context">{
'search_default_section_id': [active_id],
'search_default_new': 1,
'search_default_open': 1,
'default_section_id': active_id,
'stage_type': 'opportunity',
'default_type': 'opportunity',
'default_user_id': uid,
}
</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new opportunity.
</p><p>
OpenERP helps you keep track of your sales pipeline to follow
up potential sales and better forecast your future revenues.
</p><p>
You will be able to plan meetings and phone calls from
opportunities, convert them into quotations, attach related
documents, track all discussions, and much more.
</p>
</field>
</record>
<!-- Case Sections Salesteams kanban view -->
<record model="ir.ui.view" id="crm_case_section_salesteams_view_kanban">
<field name="name">crm.case.section.kanban</field>
<field name="model">crm.case.section</field>
<field name="arch" type="xml">
<kanban version="7.0" class="oe_background_grey">
<field name="use_leads"/>
<field name="name"/>
<field name="user_id"/>
<field name="member_ids"/>
<field name="note"/>
<field name="alias_id"/>
<field name="color"/>
<field name="open_lead_ids"/>
<field name="open_opportunity_ids"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_project oe_kanban_global_click oe_kanban_crm_salesteams">
<div class="oe_dropdown_toggle oe_dropdown_kanban" groups="base.group_user">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu">
<li t-if="widget.view.is_action_enabled('edit')"><a type="edit">Sales Teams Settings</a></li>
<li t-if="widget.view.is_action_enabled('delete')"><a type="delete">Delete</a></li>
<li t-if="widget.view.is_action_enabled('edit')"><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
<div class="oe_kanban_content">
<h4><field name="name"/></h4>
<div class="oe_kanban_alias" t-if="record.use_leads.raw_value and record.alias_id.value">
<span class="oe_e">%%</span><small><field name="alias_id"/></small>
</div>
<div class="oe_items_list">
<a t-if="record.use_leads.raw_value" name="%(crm_case_form_view_salesteams_lead)d" type="action">
<t t-raw="record.open_lead_ids.raw_value.length"/>
<t t-if="record.open_lead_ids.raw_value.length &gt;= 2">Leads</t>
<t t-if="record.open_lead_ids.raw_value.length &lt; 2">Lead</t></a>
<a name="%(crm_case_form_view_salesteams_opportunity)d" type="action">
<t t-raw="record.open_opportunity_ids.raw_value.length"/>
<t t-if="record.open_opportunity_ids.raw_value.length &gt;= 2">Opportunities</t>
<t t-if="record.open_opportunity_ids.raw_value.length &lt; 2">Opportunity</t></a>
</div>
<div class="oe_avatars">
<img t-if="record.user_id.raw_value" t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-data-member_id="record.user_id.raw_value"/>
<t t-foreach="record.member_ids.raw_value.slice(0,11)" t-as="member">
<img t-att-src="kanban_image('res.users', 'image_small', member)" t-att-data-member_id="member"/>
</t>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<!-- Case Sections Action -->
<record id="crm_case_section_salesteams_act" model="ir.actions.act_window">
<field name="name">Sales Teams</field>
<field name="res_model">crm.case.section</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_id" ref="crm_case_section_salesteams_view_kanban"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click here to define a new sales team.
</p><p>
Use sales team to organize your different salespersons or
departments into separate teams. Each team will work in
its own list of opportunities.
</p>
</field>
</record>
<!-- Case Sections Form View -->
<record id="crm_case_section_view_form" model="ir.ui.view">
<field name="name">crm.case.section.form</field>
<field name="model">crm.case.section</field>
<field name="arch" type="xml">
<form string="Sales Team" version="7.0">
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Project Name"/>
<h1>
<field name="name" string="Project Name"/>
</h1>
<div name="group_alias"
attrs="{'invisible': [('alias_domain', '=', False)]}">
<label for="alias_id" string="Email Alias"/>
<field name="alias_id" class="oe_inline oe_read_only" required="0" nolabel="1"/>
<span name="edit_alias" class="oe_edit_only">
<field name="alias_name" class="oe_inline"
attrs="{'required': [('use_leads', '=', True), ('alias_id', '!=', False)]}"/>
@
<field name="alias_domain" class="oe_inline" readonly="1"/>
</span>
</div>
<div name="options_active">
<field name="use_leads" class="oe_inline"/><label for="use_leads"/>
</div>
</div>
<group>
<group>
<field name="parent_id"/>
<field name="resource_calendar_id"/>
<field name="active"/>
</group>
<group>
<field name="user_id"/>
<field name="code"/>
</group>
<group colspan="4" attrs="{'invisible': [('use_leads', '=', False)]}">
</group>
</group>
<notebook colspan="4">
<page string="Sales Team">
<group>
<field name="change_responsible"/>
</group>
<separator string="Team Members"/>
<field name="member_ids" widget="many2many_kanban">
<kanban quick_create="false" create="true">
<field name="name"/>
<templates>
<t t-name="kanban-box">
<div style="position: relative">
<a t-if="! read_only_mode" type="delete" style="position: absolute; right: 0; padding: 4px; diplay: inline-block">X</a>
<div class="oe_module_vignette">
<div class="oe_module_desc">
<field name="name"/>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</page>
<page string="Stages">
<separator string="Select Stages for this Sales Team"/>
<field name="stage_ids"/>
</page>
<page string="Notes">
<field name="note"/>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" help="Follow this salesteam to automatically track the events associated to users of this team."/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<!-- Case Sections Tree View -->
<record id="crm_case_section_view_tree" model="ir.ui.view">
<field name="name">crm.case.section.tree</field>
<field name="model">crm.case.section</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree string="Sales Team">
<field name="name"/>
<field name="code"/>
<field name="user_id"/>
</tree>
</field>
</record>
<!-- Case Sections Action -->
<record model="ir.actions.act_window.view" id="action_crm_tag_kanban_view_salesteams_oppor11">
<field name="sequence" eval="0"/>
<field name="view_mode">kanban</field>
<field name="view_id" ref="crm_case_kanban_view_leads"/>
<field name="act_window_id" ref="crm_case_form_view_salesteams_opportunity"/>
</record>
<record model="ir.actions.act_window.view" id="action_crm_tag_tree_view_salesteams_oppor11">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="crm_case_tree_view_oppor"/>
<field name="act_window_id" ref="crm_case_form_view_salesteams_opportunity"/>
</record>
<record model="ir.actions.act_window.view" id="action_crm_tag_form_view_salesteams_oppor11">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="crm_case_form_view_oppor"/>
<field name="act_window_id" ref="crm_case_form_view_salesteams_opportunity"/>
</record>
<record id="crm_case_section_act_tree" model="ir.actions.act_window">
<field name="name">Cases by Sales Team</field>
<field name="res_model">crm.case.section</field>
<field name="domain">[('parent_id','=',False)]</field>
<field name="view_type">tree</field>
<field name="view_id" ref="crm_case_section_view_tree"/>
</record>
<record id="crm_case_section_act" model="ir.actions.act_window">
<field name="name">Sales Teams</field>
<field name="res_model">crm.case.section</field>
<field name="view_type">form</field>
<field name="view_id" ref="crm_case_section_view_tree"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click here to define a new sales team.
</p><p>
Use sales team to organize your different salespersons or
departments into separate teams. Each team will work in
its own list of opportunities.
</p>
</field>
</record>
<menuitem id="crm.menu_crm_case_section_act"
action="crm_case_section_salesteams_act"
sequence="1"
parent="base.menu_sales"
groups="base.group_multi_salesteams"/>
</data>
</openerp>

View File

@ -27,8 +27,10 @@
</record>
<record model="crm.case.section" id="section_sales_department">
<field name="name">Sales Department</field>
<field name="name">Sales</field>
<field name="code">Sales</field>
<field name="use_leads">True</field>
<field name="member_ids" eval="[(4, ref('base.user_root'))]"/>
</record>
<!-- Payment Mode -->
@ -64,12 +66,6 @@
<p>To manage quotations and sale orders, install the "Sales Management" application.</p>]]></field>
</record>
<record model="mail.alias" id="default_sales_alias">
<field name="alias_name">sales</field>
<field name="alias_model_id" ref="model_crm_lead"/>
<field name="alias_user_id" ref="base.user_root"/>
<field name="alias_defaults">{'type':'lead'}</field>
</record>
</data>
</openerp>

View File

@ -22,6 +22,7 @@
from openerp.addons.base_status.base_stage import base_stage
import crm
from datetime import datetime
from operator import itemgetter
from openerp.osv import fields, osv
import time
from openerp import tools
@ -84,6 +85,22 @@ class crm_lead(base_stage, format_address, osv.osv):
},
}
def get_empty_list_help(self, cr, uid, help, context=None):
if context.get('default_type') == 'lead':
context['empty_list_help_model'] = 'crm.case.section'
context['empty_list_help_id'] = context.get('default_section_id')
context['empty_list_help_document_name'] = _("leads")
return super(crm_lead, self).get_empty_list_help(cr, uid, help, context=context)
def onchange_user_id(self, cr, uid, ids, section_id, user_id, context=None):
""" When changing the user, also set a section_id or restrict section id
to the ones user_id is member of. """
if user_id:
section_ids = self.pool.get('crm.case.section').search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context)
if len(section_ids) > 0 and section_id not in section_ids:
section_id = section_ids[0]
return {'value': {'section_id': section_id}}
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
@ -628,12 +645,13 @@ class crm_lead(base_stage, format_address, osv.osv):
opportunities = self.browse(cr, uid, ids, context=context)
sequenced_opps = []
for opportunity in opportunities:
sequence = -1
if opportunity.stage_id and opportunity.stage_id.state != 'cancel':
sequenced_opps.append((opportunity.stage_id.sequence, opportunity))
else:
sequenced_opps.append((-1, opportunity))
sequenced_opps.sort(key=lambda tup: tup[0], reverse=True)
opportunities = [opportunity for sequence, opportunity in sequenced_opps]
sequence = opportunity.stage_id.sequence
sequenced_opps.append(((int(sequence != -1 and opportunity.type == 'opportunity'), sequence, -opportunity.id), opportunity))
sequenced_opps.sort(reverse=True)
opportunities = map(itemgetter(1), sequenced_opps)
ids = [opportunity.id for opportunity in opportunities]
highest = opportunities[0]
opportunities_rest = opportunities[1:]
@ -652,11 +670,10 @@ class crm_lead(base_stage, format_address, osv.osv):
opportunities.extend(opportunities_rest)
self._merge_notify(cr, uid, highest, opportunities, context=context)
# Check if the stage is in the stages of the sales team. If not, assign the stage with the lowest sequence
if merged_data.get('type') == 'opportunity' and merged_data.get('section_id'):
section_stages = self.pool.get('crm.case.section').read(cr, uid, merged_data['section_id'], ['stage_ids'], context=context)
if merged_data.get('stage_id') not in section_stages['stage_ids']:
stages_sequences = self.pool.get('crm.case.stage').search(cr, uid, [('id','in',section_stages['stage_ids'])], order='sequence', limit=1, context=context)
merged_data['stage_id'] = stages_sequences and stages_sequences[0] or False
if merged_data.get('section_id'):
section_stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('section_ids', 'in', merged_data['section_id']), ('type', '=', merged_data.get('type'))], order='sequence', context=context)
if merged_data.get('stage_id') not in section_stage_ids:
merged_data['stage_id'] = section_stage_ids and section_stage_ids[0] or False
# Write merged data into first opportunity
self.write(cr, uid, [highest.id], merged_data, context=context)
# Delete tail opportunities

View File

@ -7,68 +7,69 @@
<field name="name">New</field>
<field eval="1" name="case_default"/>
<field name="state">draft</field>
<field eval="'10'" name="probability"/>
<field eval="'10'" name="sequence"/>
<field eval="0" name="probability"/>
<field eval="10" name="sequence"/>
<field name="type">both</field>
</record>
<record model="crm.case.stage" id="stage_lead2">
<field name="name">Opportunity</field>
<field eval="1" name="case_default"/>
<field name="state">open</field>
<field eval="'20'" name="probability"/>
<field eval="'11'" name="sequence"/>
<field eval="20" name="probability"/>
<field eval="20" name="sequence"/>
<field name="type">lead</field>
</record>
<record model="crm.case.stage" id="stage_lead3">
<field name="name">Qualification</field>
<field eval="1" name="case_default"/>
<field name="state">open</field>
<field eval="'20'" name="probability"/>
<field eval="'12'" name="sequence"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead4">
<field name="name">Proposition</field>
<field eval="1" name="case_default"/>
<field name="state">open</field>
<field eval="'40'" name="probability"/>
<field eval="'13'" name="sequence"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead5">
<field name="name">Negotiation</field>
<field eval="1" name="case_default"/>
<field name="state">open</field>
<field eval="'60'" name="probability"/>
<field eval="'14'" name="sequence"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead6">
<field name="name">Won</field>
<field eval="1" name="case_default"/>
<field name="state">done</field>
<field eval="'100'" name="probability"/>
<field eval="'15'" name="sequence"/>
<field eval="1" name="on_change"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead7">
<field name="name">Dead</field>
<field eval="1" name="case_default"/>
<field eval="False" name="fold"/>
<field name="state">cancel</field>
<field eval="'0'" name="probability"/>
<field eval="'16'" name="sequence"/>
<field eval="0" name="probability"/>
<field eval="30" name="sequence"/>
<field name="type">lead</field>
</record>
<record model="crm.case.stage" id="stage_lead3">
<field name="name">Qualification</field>
<field eval="1" name="case_default"/>
<field name="state">open</field>
<field eval="20" name="probability"/>
<field eval="100" name="sequence"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead4">
<field name="name">Proposition</field>
<field eval="1" name="case_default"/>
<field name="state">open</field>
<field eval="40" name="probability"/>
<field eval="110" name="sequence"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead5">
<field name="name">Negotiation</field>
<field eval="1" name="case_default"/>
<field name="state">open</field>
<field eval="60" name="probability"/>
<field eval="120" name="sequence"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead6">
<field name="name">Won</field>
<field eval="True" name="fold"/>
<field eval="1" name="case_default"/>
<field name="state">done</field>
<field eval="100" name="probability"/>
<field eval="130" name="sequence"/>
<field eval="1" name="on_change"/>
<field name="type">opportunity</field>
</record>
<record model="crm.case.stage" id="stage_lead8">
<field name="name">Lost</field>
<field eval="1" name="case_default"/>
<field eval="True" name="fold"/>
<field eval="1" name="on_change"/>
<field name="state">cancel</field>
<field eval="'0'" name="probability"/>
<field eval="'17'" name="sequence"/>
<field eval="0" name="probability"/>
<field eval="140" name="sequence"/>
<field name="type">opportunity</field>
</record>

View File

@ -9,34 +9,23 @@
<field name="domain">['|', ('type','=','lead'), ('type','=',False)]</field>
<field name="view_id" ref="crm_case_tree_view_leads"/>
<field name="search_view_id" ref="crm.view_crm_case_leads_filter"/>
<field name="context">{'default_type':'lead', 'stage_type':'lead'}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create an unqualified lead.
</p><p>
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/or a new customer in your address book.
</p>
<field name="context">{
'default_type':'lead',
'stage_type':'lead',
'search_default_unassigned':1,
}
</field>
<field name="help" type="html">
<p>
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/or a new customer in your address book.
</p>
</field>
</record>
<record model="ir.actions.act_window.view" id="action_crm_tag_tree_view_leads_all">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="crm_case_tree_view_leads"/>
<field name="act_window_id" ref="crm_case_category_act_leads_all"/>
</record>
<record model="ir.actions.act_window.view" id="action_crm_tag_form_view_leads_all">
<field name="sequence" eval="3"/>
<field name="view_mode">form</field>
<field name="view_id" ref="crm_case_form_view_leads"/>
<field name="act_window_id" ref="crm_case_category_act_leads_all"/>
</record>
<record model="ir.actions.act_window" id="crm_case_category_act_oppor11">
@ -44,20 +33,25 @@
<field name="res_model">crm.lead</field>
<field name="view_mode">kanban,tree,graph,form,calendar</field>
<field name="domain">[('type','=','opportunity')]</field>
<field name="context">{'stage_type': 'opportunity', 'default_type': 'opportunity', 'default_user_id': uid}</field>
<field name="context">{
'stage_type': 'opportunity',
'default_type': 'opportunity',
'default_user_id': uid
}
</field>
<field name="view_id" eval="False"/>
<field name="search_view_id" ref="crm.view_crm_case_opportunities_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new opportunity.
</p><p>
OpenERP helps you keep track of your sales pipeline to follow
up potential sales and better forecast your future revenues.
</p><p>
You will be able to plan meetings and phone calls from
opportunities, convert them into quotations, attach related
documents, track all discussions, and much more.
</p>
<p class="oe_view_nocontent_create">
Click to create a new opportunity.
</p><p>
OpenERP helps you keep track of your sales pipeline to follow
up potential sales and better forecast your future revenues.
</p><p>
You will be able to plan meetings and phone calls from
opportunities, convert them into quotations, attach related
documents, track all discussions, and much more.
</p>
</field>
</record>
@ -82,9 +76,13 @@
<field name="act_window_id" ref="crm_case_category_act_oppor11"/>
</record>
<menuitem name="Sales" id="base.menu_sales" parent="base.menu_base_partner" sequence="1" />
<menuitem name="Leads" id="menu_crm_leads" parent="base.menu_sales" action="crm_case_category_act_leads_all" sequence="2" />
<menuitem name="Opportunities" id="menu_crm_opportunities" parent="base.menu_sales" action="crm_case_category_act_oppor11" sequence="3" />
<menuitem name="Sales" id="base.menu_sales" parent="base.menu_base_partner" sequence="1"/>
<menuitem name="Leads" id="menu_crm_leads" parent="base.menu_sales" sequence="3"
action="crm_case_category_act_leads_all"
groups="base.group_mono_salesteams,base.group_sale_manager"/>
<menuitem name="Opportunities" id="menu_crm_opportunities" parent="base.menu_sales" sequence="4"
action="crm_case_category_act_oppor11"
groups="base.group_mono_salesteams,base.group_sale_manager"/>
</data>
</openerp>

View File

@ -100,6 +100,7 @@
<button name="case_cancel" string="Cancel Case" type="object"
states="draft,open,pending"/>
<field name="stage_id" widget="statusbar" clickable="True"
domain="['&amp;', '|', ('case_default', '=', True), ('section_ids', '=', section_id), '|', ('type', '=', type), ('type', '=', 'both')]"
on_change="onchange_stage_id(stage_id)"/>
</header>
<sheet>
@ -151,12 +152,13 @@
-->
</group>
<group>
<field name="user_id"
context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads']}"/>
<label for="section_id"/>
<div>
<field name="user_id" on_change="onchange_user_id(section_id, user_id)"
context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads'] }"/>
<label for="section_id" groups="base.group_multi_salesteams"/>
<div groups="base.group_multi_salesteams">
<field name="section_id"/>
<button name="case_escalate" string="Escalate" type="object" attrs="{'invisible': ['|', ('section_id','=',False), ('state', 'not in', ['draft','open','pending'])]}"/>
<button name="case_escalate" string="Escalate" type="object"
attrs="{'invisible': ['|', ('section_id','=',False), ('state', 'not in', ['draft','open','pending'])]}"/>
</div>
<field name="type" invisible="1"/>
</group>
@ -228,7 +230,7 @@
<field name="stage_id"/>
<field name="user_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
<field name="section_id" invisible="context.get('invisible_section', True)"/>
<field name="section_id" invisible="context.get('invisible_section', True)" groups="base.group_multi_salesteams"/>
<field name="state" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="referred" invisible="1"/>
@ -326,7 +328,7 @@
<search string="Search Leads">
<field name="name" string="Lead / Customer" filter_domain="['|','|',('partner_name','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike',self)]"/>
<field name="section_id" context="{'invisible_section': False, 'default_section_id': self}"/>
<field name="section_id" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
<field name="user_id"/>
<field name="partner_id"/>
<field name="create_date"/>
@ -334,7 +336,7 @@
<separator/>
<filter string="Open" name="open" domain="[('state','!=','cancel')]" help="Open Leads"/>
<filter string="Dead" name="dead" domain="[('state','=','cancel')]"/>
<filter string="Unassigned" domain="[('user_id','=', False)]" help="No salesperson"/>
<filter string="Unassigned" name="unassigned" domain="[('user_id','=', False)]" help="No salesperson"/>
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]" help="Unread messages"/>
<filter string="Assigned to Me"
domain="[('user_id','=',uid)]" context="{'invisible_section': False}"
@ -427,9 +429,9 @@
</group>
<group>
<field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads']}"/>
<label for="section_id"/>
<div>
<field name="user_id" on_change="onchange_user_id(section_id, user_id)" context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads']}"/>
<label for="section_id" groups="base.group_multi_salesteams"/>
<div groups="base.group_multi_salesteams">
<field name="section_id" widget="selection"/>
<button name="case_escalate" string="Escalate" type="object" class="oe_link" attrs="{'invisible': ['|', ('section_id','=',False), ('state', 'not in', ['draft','open','pending'])]}"/>
</div>
@ -525,7 +527,7 @@
<field name="stage_id"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="probability" avg="Avg. of Probability"/>
<field name="section_id" invisible="context.get('invisible_section', True)"/>
<field name="section_id" invisible="context.get('invisible_section', True)" groups="base.group_multi_salesteams"/>
<field name="user_id"/>
<field name="referred" invisible="1"/>
<field name="priority" invisible="1"/>
@ -544,7 +546,7 @@
<search string="Search Opportunities">
<field name="name" string="Opportunity" filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike', self)]"/>
<field name="section_id" context="{'invisible_section': False, 'default_section_id': self}"/>
<field name="section_id" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
<field name="user_id"/>
<field name="partner_id"/>
<separator/>
@ -552,7 +554,7 @@
<filter string="In Progress" name="open" domain="[('state','=','open')]" help="Open Opportunities"/>
<filter string="Won" name="won" domain="[('state','=','done')]"/>
<filter string="Lost" name="lost" domain="[('state','=','cancel')]"/>
<filter string="Unassigned" domain="[('user_id','=', False)]" help="No salesperson"/>
<filter string="Unassigned" name="unassigned" domain="[('user_id','=', False)]" help="No salesperson"/>
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]" help="Unread messages"/>
<filter string="Assigned to Me"
domain="[('user_id','=',uid)]" context="{'invisible_section': False}"

View File

@ -103,7 +103,8 @@
<field name="date"/>
<field name="user_id"/>
<field name="duration" widget="float_time"/>
<field name="section_id" colspan="1" widget="selection"/>
<field name="section_id" colspan="1" widget="selection"
groups="base.group_multi_salesteams"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="email_from" invisible="1"/> <!--not needed because of the chatter, thus invisible, but must be in the view as it's returned by onchange_partner_id()-->
<field name="categ_id" widget="selection"
@ -187,7 +188,8 @@
help="Phone Calls Assigned to the current user or with a team having the current user as team leader"/>
<field name="partner_id"/>
<field name="user_id"/>
<field name="section_id" string="Sales Team"/>
<field name="section_id" string="Sales Team"
groups="base.group_multi_salesteams"/>
<group expand="0" string="Group By...">
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>

View File

@ -12,7 +12,7 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="category2_id"/>
<field name="stage_id"/>
<field name="amount_revenue"/>
@ -33,7 +33,8 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id" widget="selection"/>
<field name="section_id" widget="selection"
groups="base.group_multi_salesteams"/>
<field name="category2_id" />
<field name="stage_id"/>
<field name="amount_revenue"/>
@ -53,7 +54,8 @@
<graph string="Cases by Teams and Type" type="bar" orientation="horizontal">
<field name="category2_id"/>
<field name="amount_revenue" operator="+"/>
<field name="section_id" group="True"/>
<field name="section_id" group="True"
groups="base.group_multi_salesteams"/>
</graph>
</field>
</record>
@ -69,7 +71,7 @@
<field name="month"/>
<field name="nbr"/>
<field name="state"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="category2_id"/>
</search>
</field>
@ -95,7 +97,7 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="stage_id"/>
<field name="amount_revenue"/>
<field name="nbr"/>
@ -115,7 +117,8 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id" widget="selection"/>
<field name="section_id" widget="selection"
groups="base.group_multi_salesteams"/>
<field name="stage_id"/>
<field name="amount_revenue"/>
<field name="nbr" />
@ -134,7 +137,7 @@
<graph string="Cases by Team and Stage" type="bar" orientation="horizontal">
<field name="stage_id"/>
<field name="amount_revenue" operator="+"/>
<field name="section_id" group="True"/>
<field name="section_id" group="True" groups="base.group_multi_salesteams"/>
</graph>
</field>
</record>
@ -150,7 +153,7 @@
<field name="month"/>
<field name="nbr"/>
<field name="state"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</search>
</field>
</record>
@ -175,7 +178,7 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="categ_id"/>
<field name="stage_id"/>
<field name="nbr"/>
@ -195,7 +198,7 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id" widget="selection"/>
<field name="section_id" widget="selection" groups="base.group_multi_salesteams"/>
<field name="categ_id"/>
<field name="stage_id"/>
<field name="nbr" />
@ -216,7 +219,7 @@
<field name="month"/>
<field name="nbr"/>
<field name="state"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</search>
</field>
</record>
@ -230,7 +233,7 @@
<graph string="Cases by Section, Category and Stage" type="bar" orientation="horizontal">
<field name="categ_id"/>
<field name="nbr" operator="+"/>
<field name="section_id" group="True"/>
<field name="section_id" group="True" groups="base.group_multi_salesteams"/>
</graph>
</field>
</record>
@ -255,7 +258,7 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="categ_id"/>
<field name="category2_id"/>
<field name="stage_id"/>
@ -276,7 +279,7 @@
<field name="name"/>
<field name="month"/>
<field name="user_id"/>
<field name="section_id" widget="selection"/>
<field name="section_id" widget="selection" groups="base.group_multi_salesteams"/>
<field name="categ_id"/>
<field name="category2_id"/>
<field name="stage_id"/>
@ -298,7 +301,7 @@
<field name="month"/>
<field name="nbr"/>
<field name="state"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</search>
</field>
</record>
@ -312,7 +315,7 @@
<graph string="Cases by Section, Category and Type" type="bar" orientation="horizontal">
<field name="category2_id"/>
<field name="nbr" operator="+"/>
<field name="section_id" group="True"/>
<field name="section_id" group="True" groups="base.group_multi_salesteams"/>
</graph>
</field>
</record>

View File

@ -70,109 +70,6 @@
<menuitem action="crm_case_channel_action" id="menu_crm_case_channel" parent="base.menu_crm_config_lead" sequence="4" groups="base.group_no_one"/>
<!-- Case Sections Form View -->
<record id="crm_case_section_view_form" model="ir.ui.view">
<field name="name">crm.case.section.form</field>
<field name="model">crm.case.section</field>
<field name="arch" type="xml">
<form string="Sales Team" version="7.0">
<group>
<group>
<field name="name" colspan="2"/>
<field name="parent_id"/>
<field name="code"/>
</group>
<group>
<field name="user_id"/>
<field name="resource_calendar_id"/>
<field name="active"/>
</group>
</group>
<notebook colspan="4">
<page string="Sales Team">
<group>
<field name="alias_id" invisible="1" required="0"/>
<label for="alias_name" attrs="{'invisible': [('alias_domain', '=', False)]}"/>
<div attrs="{'invisible': [('alias_domain', '=', False)]}">
<field name="alias_name" class="oe_inline" attrs="{'required': [('alias_id', '!=', False)]}"/>@<field name="alias_domain" class="oe_inline"/>
</div>
<field name="change_responsible"/>
</group>
<separator string="Team Members"/>
<field name="member_ids" widget="many2many_kanban">
<kanban quick_create="false" create="true">
<field name="name"/>
<templates>
<t t-name="kanban-box">
<div style="position: relative">
<a t-if="! read_only_mode" type="delete" style="position: absolute; right: 0; padding: 4px; diplay: inline-block">X</a>
<div class="oe_module_vignette">
<div class="oe_module_desc">
<field name="name"/>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</page>
<page string="Stages">
<separator string="Select Stages for this Sales Team"/>
<field name="stage_ids"/>
</page>
<page string="Notes">
<field name="note"/>
</page>
</notebook>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" help="Follow this salesteam to automatically track the events associated to users of this team."/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<!-- Case Sections Tree View -->
<record id="crm_case_section_view_tree" model="ir.ui.view">
<field name="name">crm.case.section.tree</field>
<field name="model">crm.case.section</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
<tree string="Sales Team">
<field name="name"/>
<field name="code"/>
<field name="user_id"/>
</tree>
</field>
</record>
<!-- Case Sections Action -->
<record id="crm_case_section_act" model="ir.actions.act_window">
<field name="name">Sales Teams</field>
<field name="res_model">crm.case.section</field>
<field name="view_type">form</field>
<field name="view_id" ref="crm_case_section_view_tree"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new sales team.
</p><p>
Use sales team to organize your different salespersons or
departments into separate teams. Each team will work in
its own list of opportunities.
</p>
</field>
</record>
<menuitem action="crm_case_section_act"
id="menu_crm_case_section_act" sequence="15"
parent="base.menu_base_config" groups="base.group_sale_manager"/>
<!-- CRM Stage Tree View -->
<record model="ir.ui.view" id="crm_case_stage_tree">
@ -233,7 +130,7 @@
<form string="Case Category" version="7.0">
<group>
<field name="name"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="object_id" invisible="1"/>
</group>
</form>
@ -248,7 +145,7 @@
<field name="arch" type="xml">
<tree string="Case Category">
<field name="name"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</tree>
</field>
</record>
@ -261,7 +158,7 @@
<field name="arch" type="xml">
<tree string="Campaign">
<field name="name"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</tree>
</field>
</record>
@ -275,7 +172,7 @@
<form string="Campaign" version="7.0">
<group>
<field name="name"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</group>
</form>
</field>
@ -295,13 +192,6 @@
groups="base.group_no_one"
parent="base.menu_crm_config_lead"/>
<record id="crm_case_section_act_tree" model="ir.actions.act_window">
<field name="name">Cases by Sales Team</field>
<field name="res_model">crm.case.section</field>
<field name="domain">[('parent_id','=',False)]</field>
<field name="view_type">tree</field>
<field name="view_id" ref="crm_case_section_view_tree"/>
</record>
<!-- Segmentation line Tree View -->
@ -434,7 +324,7 @@
<field name="arch" type="xml">
<tree string="Payment Mode">
<field name="name"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</tree>
</field>
</record>
@ -448,7 +338,7 @@
<form string="Payment Mode" version="7.0">
<group>
<field name="name"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</group>
</form>
</field>

View File

@ -19,7 +19,8 @@
<field name="channel_id" invisible="1"/>
<field name="type" invisible="1"/>
<field name="priority" invisible="1"/>
<field name="section_id" invisible="1"/>
<field name="section_id" invisible="1"
groups="base.group_multi_salesteams"/>
<field name="user_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
@ -77,7 +78,8 @@
help="Leads/Opportunities that are assigned to one of the sale teams I manage"/>
<separator/>
<filter icon="terp-personal" string="My Case(s)" help="Leads/Opportunities that are assigned to me" domain="[('user_id','=',uid)]"/>
<field name="section_id" context="{'invisible_section': False}"/>
<field name="section_id" context="{'invisible_section': False}"
groups="base.group_multi_salesteams"/>
<field name="user_id" string="Salesperson"/>
<group expand="0" string="Extended Filters...">
<field name="partner_id"/>
@ -134,7 +136,8 @@
<field name="creation_month" invisible="1"/>
<field name="creation_day" invisible="1"/>
<field name="deadline_month" invisible="1"/>
<field name="section_id" invisible="1"/>
<field name="section_id" invisible="1"
groups="base.group_multi_salesteams"/>
<field name="user_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
<field name="country_id" invisible="1"/>

View File

@ -11,7 +11,8 @@
<tree string="Phone calls" create="false">
<field name="name" invisible="1"/>
<field name="month" invisible="1"/>
<field name="section_id" invisible="1"/>
<field name="section_id" invisible="1"
groups="base.group_multi_salesteams"/>
<field name="priority" invisible="1"/>
<field name="user_id" invisible="1"/>
<field name="company_id" invisible="1"/>
@ -59,7 +60,8 @@
help="Phone calls that are assigned to one of the sale teams I manage"/>
<separator/>
<filter icon="terp-personal" string="My Phone Calls" help="Phone Calls that are assigned to me" domain="[('user_id','=',uid)]" />
<field name="section_id" string="Sales Team" context="{'invisible_section': False}"/>
<field name="section_id" string="Sales Team" context="{'invisible_section': False}"
groups="base.group_multi_salesteams"/>
<field name="user_id" string="Salesperson"/>
<group expand="0" string="Extended Filters...">
<field name="partner_id"/>

View File

@ -2,7 +2,7 @@
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (C) 2004-2012 OpenERP S.A. (<http://openerp.com>).
# Copyright (C) 2004-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
@ -21,24 +21,51 @@
from openerp.osv import fields, osv
class crm_configuration(osv.osv_memory):
class crm_configuration(osv.TransientModel):
_name = 'sale.config.settings'
_inherit = ['sale.config.settings', 'fetchmail.config.settings']
def set_group_multi_salesteams(self, cr, uid, ids, context=None):
""" This method is automatically called by res_config as it begins
with set. It is used to implement the 'one group or another'
behavior. We have to perform some group manipulation by hand
because in res_config.execute(), set_* methods are called
after group_*; therefore writing on an hidden res_config file
could not work.
If group_multi_salesteams is checked: remove group_mono_salesteams
from group_user, remove the users. Otherwise, just add
group_mono_salesteams in group_user.
The inverse logic about group_multi_salesteams is managed by the
normal behavior of 'group_multi_salesteams' field.
"""
def ref(xml_id):
mod, xml = xml_id.split('.', 1)
return self.pool['ir.model.data'].get_object(cr, uid, mod, xml, context)
for obj in self.browse(cr, uid, ids, context=context):
config_group = ref('base.group_mono_salesteams')
base_group = ref('base.group_user')
if obj.group_multi_salesteams:
base_group.write({'implied_ids': [(3, config_group.id)]})
config_group.write({'users': [(3, u.id) for u in base_group.users]})
else:
base_group.write({'implied_ids': [(4, config_group.id)]})
return True
_columns = {
'fetchmail_lead': fields.boolean("Create leads from incoming mails",
fetchmail_model='crm.lead', fetchmail_name='Incoming Leads',
help="""Allows you to configure your incoming mail server, and create leads from incoming emails."""),
'group_fund_raising': fields.boolean("Manage Fund Raising",
implied_group='crm.group_fund_raising',
help="""Allows you to trace and manage your activities for fund raising."""),
'module_crm_claim':fields.boolean("Manage Customer Claims",
'module_crm_claim': fields.boolean("Manage Customer Claims",
help="""Allows you to track your customers/suppliers claims and grievances.
This installs the module crm_claim."""),
'module_crm_helpdesk':fields.boolean("Manage Helpdesk and Support",
help="""Allows you to communicate with Customer, process Customer query, and provide better help and support. This installs the module crm_helpdesk."""),
'module_crm_helpdesk': fields.boolean("Manage Helpdesk and Support",
help="""Allows you to communicate with Customer, process Customer query, and provide better help and support. This installs the module crm_helpdesk."""),
'group_multi_salesteams': fields.boolean("Organize Sales activities into multiple Sales Teams",
implied_group='base.group_multi_salesteams',
help="""Allows you to use Sales Teams to manage your leads and opportunities."""),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -22,20 +22,15 @@
</div>
</div>
</group>
</div>
<group name="On Mail Client" version="7.0" position="after">
<separator string="Sales Teams Configuration"/>
<group>
<label for="id" string="On Mail Server"/>
<label for="id" string="Use Sales Teams"/>
<div>
<div name="fetchmail_lead">
<field name="fetchmail_lead" class="oe_inline"/>
<label for="fetchmail_lead"/>
<button name="configure_fetchmail_lead" type="object" string="Configure" icon="gtk-go-forward"
attrs="{'invisible': [('fetchmail_lead','=',False)]}" class="oe_link"/>
</div>
<field name="group_multi_salesteams" class="oe_inline"/>
<label for="group_multi_salesteams"/>
</div>
</group>
</group>
</div>
</field>
</record>

View File

@ -10,7 +10,7 @@
<field eval="18" name="priority"/>
<field name="arch" type="xml">
<field name="user_id" position="after">
<field name="section_id" completion="1"/>
<field name="section_id" completion="1" groups="base.group_multi_salesteams"/>
</field>
</field>
</record>
@ -30,8 +30,11 @@
<field name="res_model">crm.lead</field>
<field name="view_mode">kanban,tree,form,graph,calendar</field>
<field name="domain">[('type','=','opportunity')]</field>
<field name="context">{'search_default_partner_id': active_id,
'stage_type': 'opportunity', 'default_type': 'opportunity'}</field>
<field name="context">{
'search_default_partner_id': active_id,
'stage_type': 'opportunity',
'default_type': 'opportunity'
}</field>
<field name="view_id" eval="False"/>
<field name="search_view_id" ref="crm.view_crm_case_opportunities_filter"/>
<field name="help" type="html">

View File

@ -22,6 +22,19 @@
<field name="implied_ids" eval="[(4, ref('base.group_sale_salesman_all_leads'))]"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="base.group_mono_salesteams" model="res.groups">
<field name="name">Do Not Use Sales Teams</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="base.group_user" model="res.groups">
<field name="implied_ids" eval="[(4, ref('base.group_mono_salesteams'))]"/>
</record>
<record id="base.group_multi_salesteams" model="res.groups">
<field name="name">Manage Sales Teams</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="group_fund_raising" model="res.groups">
<field name="name">Manage Fund Raising</field>

View File

@ -11,9 +11,7 @@ access_crm_lead_manager,crm.lead.manager,model_crm_lead,base.group_sale_manager,
access_crm_phonecall_manager,crm.phonecall.manager,model_crm_phonecall,base.group_sale_manager,1,1,1,1
access_crm_case_categ,crm.case.categ,model_crm_case_categ,base.group_user,1,0,0,0
access_crm_lead,crm.lead,model_crm_lead,base.group_sale_salesman,1,1,1,0
access_crm_lead_all,crm.lead.all,model_crm_lead,base.group_user,1,0,0,0
access_crm_phonecall,crm.phonecall,model_crm_phonecall,base.group_sale_salesman,1,1,1,0
access_crm_phonecall_all,crm.phonecall.all,model_crm_phonecall,base.group_user,1,0,0,0
access_crm_case_section_user,crm.case.section.user,model_crm_case_section,base.group_sale_salesman,1,1,1,0
access_crm_case_section_manager,crm.case.section.manager,model_crm_case_section,base.group_sale_manager,1,1,1,1
access_crm_case_stage,crm.case.stage,model_crm_case_stage,,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_crm_phonecall_manager crm.phonecall.manager model_crm_phonecall base.group_sale_manager 1 1 1 1
12 access_crm_case_categ crm.case.categ model_crm_case_categ base.group_user 1 0 0 0
13 access_crm_lead crm.lead model_crm_lead base.group_sale_salesman 1 1 1 0
access_crm_lead_all crm.lead.all model_crm_lead base.group_user 1 0 0 0
14 access_crm_phonecall crm.phonecall model_crm_phonecall base.group_sale_salesman 1 1 1 0
access_crm_phonecall_all crm.phonecall.all model_crm_phonecall base.group_user 1 0 0 0
15 access_crm_case_section_user crm.case.section.user model_crm_case_section base.group_sale_salesman 1 1 1 0
16 access_crm_case_section_manager crm.case.section.manager model_crm_case_section base.group_sale_manager 1 1 1 1
17 access_crm_case_stage crm.case.stage model_crm_case_stage 1 0 0 0

View File

@ -0,0 +1,42 @@
.openerp .oe_kanban_view .oe_kanban_crm_salesteams {
width: 345px;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_avatars {
text-align: right;
margin: -5px 0 -10px 0;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_avatars img {
width: 30px;
height: 30px;
padding-left: 0px;
margin-top: 3px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list {
margin: 10px 0;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a {
width: 110px;
display: inline-block;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a:hover {
text-decoration: underline !important;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center {
text-align: center;
margin: 3px 0;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center .oe_sum {
margin: 0;
font-size: 40px;
}
.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center .oe_subsum {
font-size: 10px;
}

View File

@ -0,0 +1,11 @@
openerp.crm = function(openerp) {
openerp.web_kanban.KanbanRecord.include({
on_card_clicked: function() {
if (this.view.dataset.model === 'crm.case.section') {
this.$('.oe_kanban_crm_salesteams_list a').first().click();
} else {
this._super.apply(this, arguments);
}
},
});
};

View File

@ -37,20 +37,19 @@
I check for the resulting merged opp (based on name and partner).
-
!python {model: crm.lead}: |
merge_id = self.search(cr, uid, [('name', '=', 'Test lead 1'), ('partner_id','=', ref("base.res_partner_1"))])
merge_id = self.search(cr, uid, [('name', '=', 'Test opportunity 1'), ('partner_id','=', ref("base.res_partner_5"))])
assert merge_id, 'Fail to create merge opportunity wizard'
merge_result = self.browse(cr, uid, merge_id)[0]
assert merge_result.partner_id.id == ref("base.res_partner_1"), 'Partner mismatch: when merging leads/opps with different m2o values, the first not null value prevails (the other are dropped)'
assert merge_result.description == 'This is the description of the test lead 1.\n\nThis is the description of the test lead 2.\n\nThis is the description of the test opp 1.', 'Description mismatch: when merging leads/opps with different text values, these values should get concatenated and separated with line returns'
assert merge_result.description == 'This is the description of the test opp 1.\n\nThis is the description of the test lead 1.\n\nThis is the description of the test lead 2.', 'Description mismatch: when merging leads/opps with different text values, these values should get concatenated and separated with line returns'
assert merge_result.type == 'opportunity', 'Type mismatch: when at least one opp in involved in the merge, the result should be a new opp (instead of %s)' % merge_result.type
-
The other (tailing) leads/opps shouldn't exist anymore.
-
!python {model: crm.lead}: |
tailing_lead = self.search(cr, uid, [('id', '=', ref('test_crm_lead_02'))])
tailing_lead = self.search(cr, uid, [('id', '=', ref('test_crm_lead_01'))])
assert not tailing_lead, 'This tailing lead (id %s) should not exist anymore' % ref('test_crm_lead_02')
tailing_opp = self.search(cr, uid, [('id', '=', ref('test_crm_opp_01'))])
tailing_opp = self.search(cr, uid, [('id', '=', ref('test_crm_lead_02'))])
assert not tailing_opp, 'This tailing opp (id %s) should not exist anymore' % ref('test_crm_opp_01')
-
I want to test leads merge. Start by creating two leads (with the same partner).

View File

@ -22,7 +22,7 @@
<field name="phone"/>
<field name="stage_id"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</tree>
</field>
</group>
@ -68,13 +68,13 @@
<field name="phone"/>
<field name="stage_id"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</tree>
</field>
</group>
<group string="Assign opportunities to" attrs="{'invisible': [('name', '=', '')]}">
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="user_ids" widget="many2many_tags"/>
</group>

View File

@ -19,7 +19,7 @@
<field name="phone"/>
<field name="stage_id"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</tree>
</field>
<footer>

View File

@ -23,7 +23,7 @@
<field name="partner_id" readonly="True"/>
<field name="phone"/>
<field name="user_id" attrs="{'invisible': [('action','=','log')]}"/>
<field name="section_id" widget="selection" attrs="{'invisible': [('action','=','log')]}"/>
<field name="section_id" widget="selection" attrs="{'invisible': [('action','=','log')]}" groups="base.group_multi_salesteams"/>
</group>
</group>
<field name="note" placeholder="Call Description" />

View File

@ -15,7 +15,7 @@
<field name="date" string="Planned Date" attrs="{'invisible': [('action','=','log')]}"/>
<field name="partner_id" readonly="True"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
</group>
<footer>
<button name="action_schedule" type="object" string="Log Call" attrs="{'invisible' : [('action', '!=', 'log')]}" class="oe_highlight"/>

View File

@ -21,7 +21,6 @@
import crm_claim
import report
import res_config
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -41,7 +41,6 @@ automatically new claims based on incoming emails.
'crm_claim_menu.xml',
'security/ir.model.access.csv',
'report/crm_claim_report_view.xml',
'res_config_view.xml',
'crm_claim_data.xml',
],
'demo': ['crm_claim_demo.xml'],

View File

@ -116,7 +116,7 @@
<group colspan="4" col="4" groups="base.group_user">
<field name="user_id"/>
<field name="priority"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="date_deadline"/>
<field name="state" groups="base.group_no_one"/>
</group>

View File

@ -11,7 +11,8 @@
<tree string="Claims" create="false">
<field name="name" invisible="1"/>
<field name="month" invisible="1"/>
<field name="section_id" invisible="1"/>
<field name="section_id" invisible="1"
groups="base.group_multi_salesteams"/>
<field name="user_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
@ -61,7 +62,8 @@
<filter icon="terp-personal" string="My Case(s)" help="My Case(s)" domain="[('user_id','=',uid)]" />
<field name="company_id" groups="base.group_multi_company"/>
<field name="user_id" string="Salesperson"/>
<field name="section_id" string="Sales Team" context="{'invisible_section': False}"/>
<field name="section_id" string="Sales Team" context="{'invisible_section': False}"
groups="base.group_multi_salesteams"/>
<group expand="0" string="Extended Filters...">
<field name="partner_id"/>
<field name="stage_id" domain="[('section_ids', '=', 'section_id')]"/>

View File

@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (C) 2004-2012 OpenERP S.A. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# 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.osv import fields, osv
class crm_claim_settings(osv.osv_memory):
_name = 'sale.config.settings'
_inherit = ['sale.config.settings', 'fetchmail.config.settings']
_columns = {
'fetchmail_claim': fields.boolean("Create claims from incoming mails",
fetchmail_model='crm.claim', fetchmail_name='Incoming Claims',
help="""Allows you to configure your incoming mail server, and create claims from incoming emails."""),
}

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_project_config_claim" model="ir.ui.view">
<field name="name">crm_claim settings</field>
<field name="model">sale.config.settings</field>
<field name="inherit_id" ref="base_setup.view_sale_config_settings"/>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<div name="fetchmail_lead" position="after">
<div>
<field name="fetchmail_claim" class="oe_inline"/>
<label for="fetchmail_claim"/>
<button type="object" name="configure_fetchmail_claim" string="Configure" icon="gtk-go-forward"
attrs="{'invisible': [('fetchmail_claim','=',False)]}" class="oe_link"/>
</div>
</div>
</field>
</record>
</data>
</openerp>

View File

@ -48,7 +48,7 @@
<sheet string="Helpdesk Support">
<group col="4" class="oe_header">
<field name="name" string="Query"/>
<field name="section_id" widget="selection"/>
<field name="section_id" widget="selection" groups="base.group_multi_salesteams"/>
<field name="user_id"/>
<field name="date"/>
<field name="date_deadline"/>
@ -115,7 +115,7 @@
<field name="date" string="Date"/>
<field name="date_deadline"/>
<field name="user_id"/>
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="priority"/>
<field name="state"/>
</tree>
@ -154,7 +154,7 @@
help="Helpdesk requests that are assigned to me or to one of the sale teams I manage" />
<field name="partner_id" />
<field name="user_id"/>
<field name="section_id" string="Sales Team"/>
<field name="section_id" string="Sales Team" groups="base.group_multi_salesteams"/>
<group expand="0" string="Group By...">
<filter string="Partner" icon="terp-partner" domain="[]" help="Partner" context="{'group_by':'partner_id'}" />
<filter string="Responsible" icon="terp-personal" domain="[]" help="Responsible User" context="{'group_by':'user_id'}" />

View File

@ -11,7 +11,7 @@
<tree string="Helpdesk" create="false">
<field name="name" invisible="1"/>
<field name="month" invisible="1"/>
<field name="section_id" invisible="1"/>
<field name="section_id" invisible="1" groups="base.group_multi_salesteams"/>
<field name="user_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
@ -60,7 +60,7 @@
<separator/>
<filter string="My Company" icon="terp-go-home" context="{'invisible_section': False}" domain="[('section_id.user_id.company_id','=',uid)]" help="My company"/>
<field name="user_id" string="Salesperson"/>
<field name="section_id" string="Sales Team" context="{'invisible_section': False}"/>
<field name="section_id" string="Sales Team" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
<field name="company_id" groups="base.group_multi_company"/>
<group expand="0" string="Extended Filters..." groups="base.group_no_one">
<field name="priority" string="Priority"/>

View File

@ -10,7 +10,7 @@
<search string="Leads Analysis">
<filter icon="terp-check" string="Current" domain="[('state','in',('draft','open'))]"/>
<filter icon="terp-dialog-close" string="Closed" domain="[('state','=','done')]"/>
<field name="section_id" context="{'invisible_section': False}"/>
<field name="section_id" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
<field name="grade_id"/>
<field name="user_id"/>
<field name="partner_assigned_id"/>
@ -69,7 +69,7 @@
<field name="year" invisible="1"/>
<field name="month" invisible="1"/>
<field name="date_assign" invisible="1"/>
<field name="section_id" invisible="1"/>
<field name="section_id" invisible="1" groups="base.group_multi_salesteams"/>
<field name="user_id" invisible="1"/>
<field name="grade_id" invisible="1" widget="selection"/>
<field name="partner_assigned_id" invisible="1"/>

View File

@ -8,7 +8,7 @@
<field name="model">crm.partner.report.assign</field>
<field name="arch" type="xml">
<search string="Partner assigned Analysis">
<field name="section_id"/>
<field name="section_id" groups="base.group_multi_salesteams"/>
<field name="user_id"/>
<field name="grade_id"/>
<field name="activation"/>
@ -49,7 +49,7 @@
<field name="date_review" invisible="1"/>
<field name="date_partnership" invisible="1"/>
<field name="period_id" invisible="1"/>
<field name="section_id" invisible="1"/>
<field name="section_id" invisible="1" groups="base.group_multi_salesteams"/>
<field name="user_id" invisible="1"/>
<field name="opp"/>
<field name="turnover"/>

View File

@ -140,30 +140,31 @@
<field name="type"/>
<field name="stage_id"/>
<button name="stage_previous" string="Previous"
states="open,pending" type="object" icon="gtk-go-back" />
states="open,pending" type="object" icon="gtk-go-back" />
<button name="stage_next" string="Next"
states="open,pending" type="object"
icon="gtk-go-forward" />
states="open,pending" type="object"
icon="gtk-go-forward" />
<field name="section_id"
invisible="context.get('invisible_section', True)" />
invisible="context.get('invisible_section', True)"
groups="base.group_multi_salesteams"/>
<field name="user_id" />
<field name="state" />
<button name="case_cancel" string="Cancel"
states="draft,open,pending" type="object"
icon="gtk-cancel" />
states="draft,open,pending" type="object"
icon="gtk-cancel" />
<button name="case_open" string="Open"
states="draft,pending" type="object"
icon="gtk-go-forward" />
states="draft,pending" type="object"
icon="gtk-go-forward" />
<button name="case_close" string="Close"
states="open,draft,pending" type="object"
icon="gtk-close" />
states="open,draft,pending" type="object"
icon="gtk-close" />
<button string="Convert to Opportunity"
name="convert_opportunity"
states="draft,open,pending" icon="gtk-index"
type="object" attrs="{'invisible':[('type','=','opportunity')]}" />
name="convert_opportunity"
states="draft,open,pending" icon="gtk-index"
type="object" attrs="{'invisible':[('type','=','opportunity')]}" />
<button name="case_escalate" string="Escalate"
states="open,draft,pending" type="object"
icon="gtk-go-up" />
states="open,draft,pending" type="object"
icon="gtk-go-up" />
</tree>
</field>
</page>

View File

@ -52,11 +52,10 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar,gantt,graph,kanban</field>
</record>
<menuitem
id="menu_crm_todo"
parent="base.menu_sales"
action="crm_todo_action"
sequence="6"/>
<menuitem id="menu_crm_todo"
parent="base.menu_sales"
action="crm_todo_action"
sequence="7"/>
</data>

View File

@ -258,7 +258,9 @@
name="Documents"
action="action_document_file_form"
id="menu_document_files"
parent="menu_document_doc"/>
parent="menu_document_doc"
sequence="0"
/>
<record model="ir.actions.act_window" id="action_document_file_directory_form">
<field name="type">ir.actions.act_window</field>

View File

@ -325,7 +325,7 @@ class abstracted_fs(object):
""" Get cr, uid, pool from a node
"""
assert node
db = openerp.registry.(node.context.dbname).db
db = openerp.registry(node.context.dbname).db
return db.cursor(), node.context.uid
def get_node_cr(self, node):

View File

@ -341,7 +341,8 @@
</group>
<group>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
<field name="department_id"/> </group>
<field name="department_id"/>
</group>
</group>
<div>
<label for="description"/>

View File

@ -228,6 +228,8 @@ class hr_expense_expense(osv.osv):
for exp in self.browse(cr, uid, ids, context=context):
if not exp.employee_id.address_home_id:
raise osv.except_osv(_('Error!'), _('The employee must have a home address.'))
if not exp.employee_id.address_home_id.property_account_payable.id:
raise osv.except_osv(_('Error!'), _('The employee must have a payable account set on his home address.'))
company_currency = exp.company_id.currency_id.id
diff_currency_p = exp.currency_id.id <> company_currency
@ -333,6 +335,8 @@ class hr_expense_expense(osv.osv):
acc = line.product_id.property_account_expense
if not acc:
acc = line.product_id.categ_id.property_account_expense_categ
if not acc:
raise osv.except_osv(_('Error!'), _('No purchase account found for the product %s (or for his category), please configure one.') % (line.product_id.name))
else:
acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company.id})
if not acc:

View File

@ -112,7 +112,7 @@
<field name="date_value" string="Expense Date"/>
<field name="name"/>
<field name="ref"/>
<field domain="[('type','in',['normal','contract']), ('parent_id','!=',False)]" name="analytic_account" groups="analytic.group_analytic_accounting"/>
<field domain="[('type','in',['normal','contract'])]" name="analytic_account" groups="analytic.group_analytic_accounting"/>
<field name="uom_id" on_change="onchange_uom(product_id, uom_id, context)"/>
<field name="unit_amount"/>
<field name="unit_quantity"/>

View File

@ -184,6 +184,16 @@ class hr_holidays(osv.osv):
('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be anterior to the end date."),
('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0."),
]
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
if context is None:
context = {}
default = default.copy()
default['date_from'] = False
default['date_to'] = False
return super(hr_holidays, self).copy(cr, uid, id, default, context=context)
def _create_resource_leave(self, cr, uid, leaves, context=None):
'''This method will create entry in resource calendar leave object at the time of holidays validated '''

View File

@ -487,6 +487,12 @@ class hr_applicant(base_stage, osv.Model):
"""
return self.set_priority(cr, uid, ids, '3')
def get_empty_list_help(self, cr, uid, help, context=None):
context['empty_list_help_model'] = 'hr.job'
context['empty_list_help_id'] = context.get('default_job_id', None)
context['empty_list_help_document_name'] = _("job applicants")
return super(hr_applicant, self).get_empty_list_help(cr, uid, help, context=context)
class hr_job(osv.osv):
_inherit = "hr.job"

View File

@ -10,17 +10,13 @@
<field name="view_id" eval="False"/>
<field name="search_view_id" ref="view_crm_case_jobs_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a new job applicant.
</p><p>
<p>
OpenERP helps you track applicants in the recruitment
process and follow up all operations: meetings, interviews, etc.
</p><p>
If you setup the email gateway, applicants and their attached
CV are created automatically when an email is sent to
jobs@yourcompany.com. If you install the document management
modules, all resumes are indexed automatically, so that you can
easily search through their content.
Applicants and their attached CV are created automatically when an email is sent.
If you install the document management modules, all resumes are indexed automatically,
so that you can easily search through their content.
</p>
</field>
</record>

View File

@ -312,11 +312,17 @@
attrs="{'invisible':[('survey_id','=',False)]}"/>
</div>
</field>
<xpath expr="//div[@class='oe_title']" version="7.0" position="after">
<div attrs="{'invisible': [('alias_domain', '=', False)]}">
<field name="alias_id" invisible="1" required="0"/>
<label for="alias_name" class="oe_edit_only"/>
<field name="alias_name" nolabel="1" class="oe_inline" attrs="{'required': [('alias_id', '!=', False)]}"/>@<field name="alias_domain" nolabel="1" class="oe_inline"/>
<xpath expr="//div[@class='oe_title']//h1" position="after">
<div name="group_alias"
attrs="{'invisible': [('alias_domain', '=', False)]}">
<label for="alias_id" string="Email Alias"/>
<field name="alias_id" class="oe_inline oe_read_only" required="0" nolabel="1"/>
<span name="edit_alias" class="oe_edit_only">
<field name="alias_name" class="oe_inline"
attrs="{'required': [('alias_id', '!=', False)]}"/>
@
<field name="alias_domain" class="oe_inline" readonly="1"/>
</span>
</div>
</xpath>
</field>

View File

@ -169,7 +169,7 @@ class lunch_order(osv.Model):
line_ref = self.pool.get("lunch.order.line")
if view_type == 'form':
doc = etree.XML(res['arch'])
pref_ids = line_ref.search(cr, uid, [('user_id', '=', uid)], order='create_date desc', context=context)
pref_ids = line_ref.search(cr, uid, [('user_id', '=', uid)], order='id desc', context=context)
xml_start = etree.Element("div")
#If there are no preference (it's the first time for the user)
if len(pref_ids)==0:
@ -215,63 +215,70 @@ class lunch_order(osv.Model):
currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id
#For each preferences that we get, we will create the XML structure
for key,value in categories.items():
for key, value in categories.items():
xml_pref_1 = etree.Element("div")
xml_pref_1.set('class','oe_lunch_30pc')
xml_pref_1.set('class', 'oe_lunch_30pc')
xml_pref_2 = etree.Element("h2")
xml_pref_2.text = key
xml_pref_1.append(xml_pref_2)
i = 0
value = value.values()
#TODO: sorted_values is used for a quick and dirty hack in order to display the 5 last orders of each categories.
#It would be better to fetch only the 5 items to display instead of fetching everything then sorting them in order to keep only the 5 last.
#NB: The note could also be ignored + we could fetch the preferences on the most ordered products instead of the last ones...
sorted_values = {}
for val in value:
for pref in val.values():
#We only show 5 preferences per category (or it will be too long)
if i==5: break
i+=1
xml_pref_3 = etree.Element("div")
xml_pref_3.set('class','oe_lunch_vignette')
xml_pref_1.append(xml_pref_3)
for elmt in val.values():
sorted_values[elmt.id] = elmt
for key, pref in sorted(sorted_values.iteritems(), key=lambda (k, v): (k, v), reverse=True):
#We only show 5 preferences per category (or it will be too long)
if i == 5:
break
i += 1
xml_pref_3 = etree.Element("div")
xml_pref_3.set('class','oe_lunch_vignette')
xml_pref_1.append(xml_pref_3)
xml_pref_4 = etree.Element("span")
xml_pref_4.set('class','oe_lunch_button')
xml_pref_3.append(xml_pref_4)
xml_pref_4 = etree.Element("span")
xml_pref_4.set('class','oe_lunch_button')
xml_pref_3.append(xml_pref_4)
xml_pref_5 = etree.Element("button")
xml_pref_5.set('name',"add_preference_"+str(pref.id))
xml_pref_5.set('class','oe_link oe_i oe_button_plus')
xml_pref_5.set('type','object')
xml_pref_5.set('string','+')
xml_pref_4.append(xml_pref_5)
xml_pref_5 = etree.Element("button")
xml_pref_5.set('name',"add_preference_"+str(pref.id))
xml_pref_5.set('class','oe_link oe_i oe_button_plus')
xml_pref_5.set('type','object')
xml_pref_5.set('string','+')
xml_pref_4.append(xml_pref_5)
xml_pref_6 = etree.Element("button")
xml_pref_6.set('name',"add_preference_"+str(pref.id))
xml_pref_6.set('class','oe_link oe_button_add')
xml_pref_6.set('type','object')
xml_pref_6.set('string',_("Add"))
xml_pref_4.append(xml_pref_6)
xml_pref_6 = etree.Element("button")
xml_pref_6.set('name',"add_preference_"+str(pref.id))
xml_pref_6.set('class','oe_link oe_button_add')
xml_pref_6.set('type','object')
xml_pref_6.set('string',_("Add"))
xml_pref_4.append(xml_pref_6)
xml_pref_7 = etree.Element("div")
xml_pref_7.set('class','oe_group_text_button')
xml_pref_3.append(xml_pref_7)
xml_pref_7 = etree.Element("div")
xml_pref_7.set('class','oe_group_text_button')
xml_pref_3.append(xml_pref_7)
xml_pref_8 = etree.Element("div")
xml_pref_8.set('class','oe_lunch_text')
xml_pref_8.text = escape(pref.product_id.name)+str(" ")
xml_pref_7.append(xml_pref_8)
xml_pref_8 = etree.Element("div")
xml_pref_8.set('class','oe_lunch_text')
xml_pref_8.text = escape(pref.product_id.name)+str(" ")
xml_pref_7.append(xml_pref_8)
price = pref.product_id.price or 0.0
cur = currency.name or ''
xml_pref_9 = etree.Element("span")
xml_pref_9.set('class','oe_tag')
xml_pref_9.text = str(price)+str(" ")+cur
xml_pref_8.append(xml_pref_9)
price = pref.product_id.price or 0.0
cur = currency.name or ''
xml_pref_9 = etree.Element("span")
xml_pref_9.set('class','oe_tag')
xml_pref_9.text = str(price)+str(" ")+cur
xml_pref_8.append(xml_pref_9)
xml_pref_10 = etree.Element("div")
xml_pref_10.set('class','oe_grey')
xml_pref_10.text = escape(pref.note or '')
xml_pref_3.append(xml_pref_10)
xml_pref_10 = etree.Element("div")
xml_pref_10.set('class','oe_grey')
xml_pref_10.text = escape(pref.note or '')
xml_pref_3.append(xml_pref_10)
xml_start.append(xml_pref_1)
xml_start.append(xml_pref_1)
first_node = doc.xpath("//div[@name='preferences']")
if first_node and len(first_node)>0:

View File

@ -117,8 +117,13 @@ class mail_alias(osv.Model):
mail catchall domain from config.
e.g. `jobs@openerp.my.openerp.com` or `sales@openerp.my.openerp.com`
"""
return [(record['id'], "%s@%s" % (record['alias_name'], record['alias_domain']))
for record in self.read(cr, uid, ids, ['alias_name', 'alias_domain'], context=context)]
res = []
for record in self.browse(cr, uid, ids, context=context):
if record.alias_name and record.alias_domain:
res.append((record['id'], "%s@%s" % (record.alias_name, record.alias_domain)))
else:
res.append((record['id'], False))
return res
def _find_unique(self, cr, uid, name, context=None):
"""Find a unique alias name similar to ``name``. If ``name`` is

View File

@ -144,11 +144,19 @@ class mail_group(osv.Model):
search_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'view_message_search')
params = {
'search_view_id': search_ref and search_ref[1] or False,
'domain': [('model', '=', 'mail.group'), ('res_id', '=', mail_group_id)],
'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id, 'search_default_message_unread': True},
'domain': [
('model', '=', 'mail.group'),
('res_id', '=', mail_group_id),
],
'context': {
'default_model': 'mail.group',
'default_res_id': mail_group_id,
},
'res_model': 'mail.message',
'thread_level': 1,
'header_description': self._generate_header_description(cr, uid, group, context=context)
'header_description': self._generate_header_description(cr, uid, group, context=context),
'view_mailbox': True,
'compose_placeholder': 'Send a message to the group',
}
cobj = self.pool.get('ir.actions.client')
newref = cobj.copy(cr, SUPERUSER_ID, ref[1], default={'params': str(params), 'name': vals['name']}, context=context)

View File

@ -7,7 +7,6 @@
<field name="tag">mail.wall</field>
<field name="res_model">mail.message</field>
<field name="context">{
'search_default_message_unread': True
}</field>
<field name="params">{
'read_action': 'read'
@ -30,6 +29,7 @@
<field name="message_is_follower"/>
<field name="message_summary"/>
<field name="description"/>
<field name="alias_id"/>
<templates>
<t t-name="kanban-description">
<div class="oe_group_description" t-if="record.description.raw_value">
@ -43,6 +43,9 @@
</div>
<div class="oe_group_details">
<h4><a type="open"><field name="name"/></a></h4>
<div class="oe_kanban_alias" t-if="record.alias_id.value">
<span class="oe_e">%%</span><small><field name="alias_id"/></small>
</div>
<div class="oe_grey">
<field name="description"/>
</div>
@ -69,39 +72,43 @@
<field name="arch" type="xml">
<form string="Group Form" version="7.0">
<sheet class="openerp_mail_group_sheet">
<field name="image" widget='image' class="oe_avatar oe_left" options='{"preview_image": "image_medium"}'/>
<field name="image" widget='image' class="oe_avatar oe_left" options='{"preview_image": "image_small"}'/>
<div class="oe_title">
<div class="oe_edit_only">
<label for="name" string="Group Name"/>
</div>
<h1><field name="name" readonly="0"/></h1>
<div name="alias_box" colspan="4" attrs="{'invisible': [('alias_domain', '=', False)]}">
<field name="alias_id" invisible="1" required="0"/>
<label for="alias_name" class="oe_edit_only"/>
<field name="alias_name" nolabel="1" class="oe_inline" attrs="{'required': [('alias_id', '!=', False)]}"/>@<field name="alias_domain" nolabel="1" class="oe_inline"/>
<div name="group_alias"
attrs="{'invisible': [('alias_domain', '=', False)]}">
<label for="alias_id" string="Email Alias"/>
<field name="alias_id" class="oe_inline oe_read_only" required="0" nolabel="1"/>
<span name="edit_alias" class="oe_edit_only">
<field name="alias_name" class="oe_inline"
attrs="{'required': [('alias_id', '!=', False)]}"/>
@
<field name="alias_domain" class="oe_inline" readonly="1"/>
</span>
</div>
<field name="description" placeholder="Topics discussed in this group..."/>
</div>
<field name="description" placeholder="Topics discussed in this group..."/>
<div class="oe_clear"/>
<group>
<group class="oe_edit_only">
<field name="public"/>
<field name="group_public_id"
attrs="{'invisible': [('public','&lt;&gt;','groups')], 'required': [('public','=','groups')]}"
/>
<field name="group_ids" widget="many2many_tags"/>
</group>
<group>
<div class="oe_grey" attrs="{'invisible': [('public','&lt;&gt;','public')]}">
This group is visible by everyone,
including your customers if you installed
the portal module.
</div>
<div class="oe_grey" attrs="{'invisible': [('public','&lt;&gt;','private')]}">
Only the invited followers can read the
discussions on this group.
</div>
</group>
<group class="oe_edit_only">
<field name="public"/>
<field name="group_public_id"
attrs="{'invisible': [('public','&lt;&gt;','groups')], 'required': [('public','=','groups')]}"
/>
<field name="group_ids" widget="many2many_tags"/>
</group>
<group attrs="{'invisible': [('public', 'not in', ['public', 'private'])]}">
<div class="oe_grey" attrs="{'invisible': [('public','&lt;&gt;','public')]}">
This group is visible by everyone,
including your customers if you installed
the portal module.
</div>
<div class="oe_grey" attrs="{'invisible': [('public','&lt;&gt;','private')]}">
Only the invited followers can read the
discussions on this group.
</div>
</group>
</sheet>
<div class="oe_chatter">

View File

@ -256,7 +256,19 @@ class mail_mail(osv.Model):
body = self.send_get_mail_body(cr, uid, mail, partner=partner, context=context)
subject = self.send_get_mail_subject(cr, uid, mail, partner=partner, context=context)
body_alternative = tools.html2plaintext(body)
email_to = ['%s <%s>' % (partner.name, partner.email)] if partner else tools.email_split(mail.email_to)
# generate email_to, heuristic:
# 1. if 'partner' is specified and there is a related document: Followers of 'Doc' <email>
# 2. if 'partner' is specified, but no related document: Partner Name <email>
# 3; fallback on mail.email_to that we split to have an email addresses list
if partner and mail.record_name:
sanitized_record_name = re.sub(r'[^\w+.]+', '-', mail.record_name)
email_to = [_('"Followers of %s" <%s>') % (sanitized_record_name, partner.email)]
elif partner:
email_to = ['%s <%s>' % (partner.name, partner.email)]
else:
email_to = tools.email_split(mail.email_to)
return {
'body': body,
'body_alternative': body_alternative,

View File

@ -268,19 +268,25 @@ class mail_message(osv.Model):
domain = [('partner_id', '=', user_pid), ('message_id', 'in', msg_ids)]
if not create_missing:
domain += [('starred', '=', not starred)]
values = {
'starred': starred
}
if starred:
values['read'] = False
notif_ids = notification_obj.search(cr, uid, domain, context=context)
# all message have notifications: already set them as (un)starred
if len(notif_ids) == len(msg_ids) or not create_missing:
notification_obj.write(cr, uid, notif_ids, {'starred': starred}, context=context)
notification_obj.write(cr, uid, notif_ids, values, context=context)
return starred
# some messages do not have notifications: find which one, create notification, update starred status
notified_msg_ids = [notification.message_id.id for notification in notification_obj.browse(cr, uid, notif_ids, context=context)]
to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids))
for msg_id in to_create_msg_ids:
notification_obj.create(cr, uid, {'partner_id': user_pid, 'starred': starred, 'message_id': msg_id}, context=context)
notification_obj.write(cr, uid, notif_ids, {'starred': starred}, context=context)
notification_obj.create(cr, uid, dict(values, partner_id=user_pid, message_id=msg_id), context=context)
notification_obj.write(cr, uid, notif_ids, values, context=context)
return starred
#------------------------------------------------------

View File

@ -89,6 +89,46 @@ class mail_thread(osv.AbstractModel):
# :param function lambda: returns whether the tracking should record using this subtype
_track = {}
def get_empty_list_help(self, cr, uid, help, context=None):
""" Override of BaseModel.get_empty_list_help() to generate an help message
that adds alias information. """
model = context.get('empty_list_help_model')
res_id = context.get('empty_list_help_id')
ir_config_parameter = self.pool.get("ir.config_parameter")
catchall_domain = ir_config_parameter.get_param(cr, uid, "mail.catchall.domain", context=context)
document_name = context.get('empty_list_help_document_name', _('document'))
alias = None
if catchall_domain and model and res_id: # specific res_id -> find its alias (i.e. section_id specified)
object_id = self.pool.get(model).browse(cr, uid, res_id, context=context)
alias = object_id.alias_id
elif catchall_domain and model: # no specific res_id given -> generic help message, take an example alias (i.e. alias of some section_id)
model_id = self.pool.get('ir.model').search(cr, uid, [("model", "=", self._name)], context=context)[0]
alias_obj = self.pool.get('mail.alias')
alias_ids = alias_obj.search(cr, uid, [("alias_model_id", "=", model_id)], context=context, limit=1, order='id ASC')
if alias_ids:
alias = alias_obj.browse(cr, uid, alias_ids[0], context=context)
if alias:
alias_email = alias.name_get()[0][1]
return _("""<p class='oe_view_nocontent_create'>
Click here to add a new %(document)s or send an email to: <a href='mailto:%(email)s'>%(email)s</a>
</p>
%(static_help)s"""
) % {
'document': document_name,
'email': alias_email,
'static_help': help or ''
}
if document_name != 'document' and help and help.find("oe_view_nocontent_create") == -1:
return _("<p class='oe_view_nocontent_create'>Click here to add a new %(document)s</p>%(static_help)s") % {
'document': document_name,
'static_help': help or '',
}
return help
def _get_message_data(self, cr, uid, ids, name, args, context=None):
""" Computes:
- message_unread: has uid unread message for the document
@ -468,6 +508,8 @@ class mail_thread(osv.AbstractModel):
"""
assert isinstance(message, Message), 'message must be an email.message.Message at this point'
message_id = message.get('Message-Id')
email_from = decode_header(message, 'From')
email_to = decode_header(message, 'To')
references = decode_header(message, 'References')
in_reply_to = decode_header(message, 'In-Reply-To')
@ -481,8 +523,8 @@ class mail_thread(osv.AbstractModel):
model_pool = self.pool.get(model)
if thread_id and model and model_pool and model_pool.exists(cr, uid, thread_id) \
and hasattr(model_pool, 'message_update'):
_logger.debug('Routing mail with Message-Id %s: direct reply to model: %s, thread_id: %s, custom_values: %s, uid: %s',
message_id, model, thread_id, custom_values, uid)
_logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to model: %s, thread_id: %s, custom_values: %s, uid: %s',
email_from, email_to, message_id, model, thread_id, custom_values, uid)
return [(model, thread_id, custom_values, uid)]
# Verify whether this is a reply to a private message
@ -493,8 +535,8 @@ class mail_thread(osv.AbstractModel):
], limit=1, context=context)
if message_ids:
message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
_logger.debug('Routing mail with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
message_id, message.id, custom_values, uid)
_logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
email_from, email_to, message_id, message.id, custom_values, uid)
return [(message.model, message.res_id, custom_values, uid)]
# 2. Look for a matching mail.alias entry
@ -521,10 +563,11 @@ class mail_thread(osv.AbstractModel):
# Note: recognized partners will be added as followers anyway
# user_id = self._message_find_user_id(cr, uid, message, context=context)
user_id = uid
_logger.debug('No matching user_id for the alias %s', alias.alias_name)
_logger.info('No matching user_id for the alias %s', alias.alias_name)
routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, \
eval(alias.alias_defaults), user_id))
_logger.debug('Routing mail with Message-Id %s: direct alias match: %r', message_id, routes)
_logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r',
email_from, email_to, message_id, routes)
return routes
# 3. Fallback to the provided parameters, if they work
@ -539,14 +582,14 @@ class mail_thread(osv.AbstractModel):
except:
thread_id = False
assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
"No possible route found for incoming message with Message-Id %s. " \
"Create an appropriate mail.alias or force the destination model." % message_id
"No possible route found for incoming message from %s to %s (Message-Id %s:)." \
"Create an appropriate mail.alias or force the destination model." % (email_from, email_to, message_id)
if thread_id and not model_pool.exists(cr, uid, thread_id):
_logger.warning('Received mail reply to missing document %s! Ignoring and creating new document instead for Message-Id %s',
thread_id, message_id)
thread_id, message_id)
thread_id = None
_logger.debug('Routing mail with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s',
message_id, model, thread_id, custom_values, uid)
_logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s',
email_from, email_to, message_id, model, thread_id, custom_values, uid)
return [(model, thread_id, custom_values, uid)]
def message_process(self, cr, uid, model, message, custom_values=None,
@ -596,12 +639,24 @@ class mail_thread(osv.AbstractModel):
if isinstance(message, unicode):
message = message.encode('utf-8')
msg_txt = email.message_from_string(message)
routes = self.message_route(cr, uid, msg_txt, model,
thread_id, custom_values,
context=context)
# parse the message, verify we are not in a loop by checking message_id is not duplicated
msg = self.message_parse(cr, uid, msg_txt, save_original=save_original, context=context)
if strip_attachments:
msg.pop('attachments', None)
if msg.get('message_id'): # should always be True as message_parse generate one if missing
existing_msg_ids = self.pool.get('mail.message').search(cr, SUPERUSER_ID, [
('message_id', '=', msg.get('message_id')),
], context=context)
if existing_msg_ids:
_logger.info('Ignored mail from %s to %s with Message-Id %s:: found duplicated Message-Id during processing',
msg.get('from'), msg.get('to'), msg.get('message_id'))
return False
# find possible routes for the message
routes = self.message_route(cr, uid, msg_txt, model,
thread_id, custom_values,
context=context)
# postpone setting msg.partner_ids after message_post, to avoid double notifications
partner_ids = msg.pop('partner_ids', [])
@ -798,7 +853,7 @@ class mail_thread(osv.AbstractModel):
# as RFC2822 requires timezone offset in Date headers.
stored_date = parsed_date.replace(tzinfo=pytz.utc)
else:
stored_date = parsed_date.astimezone(pytz.utc)
stored_date = parsed_date.astimezone(tz=pytz.utc)
except Exception:
_logger.warning('Failed to parse Date header %r in incoming mail '
'with message-id %r, assuming current date/time.',
@ -817,7 +872,7 @@ class mail_thread(osv.AbstractModel):
if parent_ids:
msg_dict['parent_id'] = parent_ids[0]
msg_dict['body'], msg_dict['attachments'] = self._message_extract_payload(message)
msg_dict['body'], msg_dict['attachments'] = self._message_extract_payload(message, save_original=save_original)
return msg_dict
#------------------------------------------------------
@ -956,12 +1011,15 @@ class mail_thread(osv.AbstractModel):
], limit=1, context=context)
if author_ids:
kwargs['author_id'] = author_ids[0]
author_id = kwargs.get('author_id')
if author_id is None: # keep False values
author_id = self.pool.get('mail.message')._get_default_author(cr, uid, context=context)
# 1: Handle content subtype: if plaintext, converto into HTML
if content_subtype == 'plaintext':
body = tools.plaintext2html(body)
# 2: Private message: add recipients (recipients and author of parent message)
# 2: Private message: add recipients (recipients and author of parent message) - current author
# + legacy-code management (! we manage only 4 and 6 commands)
partner_ids = set()
kwargs_partner_ids = kwargs.pop('partner_ids', [])
@ -974,11 +1032,13 @@ class mail_thread(osv.AbstractModel):
partner_ids.add(partner_id)
else:
pass # we do not manage anything else
if parent_id and model == 'mail.thread':
if parent_id and not model:
parent_message = mail_message.browse(cr, uid, parent_id, context=context)
partner_ids |= set([partner.id for partner in parent_message.partner_ids])
private_followers = set([partner.id for partner in parent_message.partner_ids])
if parent_message.author_id:
partner_ids.add(parent_message.author_id.id)
private_followers.add(parent_message.author_id.id)
private_followers -= set([author_id])
partner_ids |= private_followers
# 3. Attachments
# - HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
@ -1039,6 +1099,7 @@ class mail_thread(osv.AbstractModel):
values = kwargs
values.update({
'author_id': author_id,
'model': model,
'res_id': thread_id or False,
'body': body,

View File

@ -568,7 +568,6 @@
text-shadow: none;
width: 100%;
}
.openerp .oe_followers button.oe_invite,
.openerp .oe_followers button.oe_follower.oe_following{
color: white;
background-color: #3465A4;
@ -626,6 +625,8 @@
height: 32px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-right: 10px;
}
.openerp .oe_followers .oe_partner img{
width: 32px;

View File

@ -14,6 +14,10 @@
padding: 0px 18px;
}
.openerp .oe_form_sheetbg.openerp_mail_group_sheet .oe_avatar {
padding-top: 3px;
}
/* Resize footer width */
.openerp .oe_form div.oe_mail_group_footer {
max-width: 80%;
@ -21,7 +25,7 @@
/* Resize group description */
.openerp .oe_form_sheetbg.openerp_mail_group_sheet .oe_form_field_text > textarea {
height: 40px;
height: 60px;
}
/* ------------------------------ */

View File

@ -1208,7 +1208,7 @@ openerp.mail = function (session) {
this.author_id = datasets.author_id || false;
this.thread_level = (datasets.thread_level+1) || 0;
datasets.partner_ids = datasets.partner_ids || [];
if (datasets.author_id && ! _.contains(datasets.partner_ids, datasets.author_id) && datasets.author_id[0]) {
if (datasets.author_id && !_.contains(_.flatten(datasets.partner_ids),datasets.author_id[0]) && datasets.author_id[0]) {
datasets.partner_ids.push(datasets.author_id);
}
this.partner_ids = datasets.partner_ids;
@ -1389,7 +1389,10 @@ openerp.mail = function (session) {
if (this.options.help) {
no_message.html(this.options.help);
}
no_message.appendTo(this.$el);
if (!this.$el.find(".oe_view_nocontent").length)
{
no_message.appendTo(this.$el);
}
},
/**

View File

@ -246,7 +246,11 @@
<!-- message itself -->
<div class="oe_msg_content">
<h1 t-if="(widget.show_record_name or widget.subject) and !widget.thread_level" class="oe_msg_title">
<a t-if="widget.options.show_link and widget.show_record_name" class="oe_mail_action_model" t-attf-href="#model=#{widget.model}&amp;id=#{widget.res_id}"><t t-raw="widget.record_name"/></a><span t-if="!widget.options.show_link and widget.show_record_name"><t t-raw="widget.record_name"/></span><t t-if="widget.show_record_name">: </t>
<a t-if="widget.options.show_link and widget.show_record_name" class="oe_mail_action_model" t-attf-href="#model=#{widget.model}&amp;id=#{widget.res_id}">
<t t-raw="widget.record_name"/>
</a>
<span t-if="!widget.options.show_link and widget.show_record_name"><t t-raw="widget.record_name"/></span>
<t t-if="widget.show_record_name and widget.subject">: </t>
<t t-if="widget.subject" t-raw="widget.subject"/>
</h1>
<div class="oe_msg_body">

View File

@ -30,7 +30,7 @@
-->
<div t-name="mail.followers.partner" class='oe_partner'>
<img class="oe_mail_thumbnail oe_mail_frame" t-attf-src="{record.avatar_url}"/>
<a t-attf-href="#model=res.partner&amp;id=#{record.id}"><t t-raw="record.name"/></a>
<a t-attf-href="#model=res.partner&amp;id=#{record.id}" t-att-title="record.name"><t t-esc="record.name"/></a>
<span t-if="widget.view_is_editable" class="oe_remove_follower oe_e" title="Remove this follower" t-att-data-id="record.id">X</span>
</div>

View File

@ -280,7 +280,8 @@ class test_mail(TestMailBase):
'message_post: mail.mail notifications should have been auto-deleted!')
# Test: notifications emails: to a and b, c is email only, r is author
test_emailto = ['Administrator <a@a>', 'Bert Tartopoils <b@b>']
# test_emailto = ['Administrator <a@a>', 'Bert Tartopoils <b@b>']
test_emailto = ['"Followers of -Pigs-" <a@a>', '"Followers of -Pigs-" <b@b>']
self.assertEqual(len(sent_emails), 2,
'message_post: notification emails wrong number of send emails')
self.assertEqual(set([m['email_to'][0] for m in sent_emails]), set(test_emailto),
@ -353,7 +354,8 @@ class test_mail(TestMailBase):
self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg2_id)]), 'mail.mail notifications should have been auto-deleted!')
# Test: emails send by server (to a, b, c, d)
test_emailto = [u'Administrator <a@a>', u'Bert Tartopoils <b@b>', u'Carine Poilvache <c@c>', u'D\xe9d\xe9 Grosbedon <d@d>']
# test_emailto = [u'Administrator <a@a>', u'Bert Tartopoils <b@b>', u'Carine Poilvache <c@c>', u'D\xe9d\xe9 Grosbedon <d@d>']
test_emailto = [u'"Followers of Pigs" <a@a>', u'"Followers of Pigs" <b@b>', u'"Followers of Pigs" <c@c>', u'"Followers of Pigs" <d@d>']
# self.assertEqual(len(sent_emails), 3, 'sent_email number of sent emails incorrect')
for sent_email in sent_emails:
self.assertEqual(sent_email['email_from'], 'Raoul Grosbedon <r@r>',

View File

@ -116,8 +116,11 @@ class TestMailgateway(TestMailBase):
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
sent_emails = self._build_email_kwargs_list
# Test: one group created by mailgateway administrator
self.assertTrue(len(frog_groups) == 1)
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
res = self.mail_group.perm_read(cr, uid, [frog_group.id], details=False)
self.assertEqual(res[0].get('create_uid'), uid,
'message_process: group should have been created by uid as alias_user__id is False on the alias')
# Test: one message that is the incoming email
self.assertEqual(len(frog_group.message_ids), 1,
'message_process: newly created group should have the incoming email in message_ids')
@ -150,9 +153,12 @@ class TestMailgateway(TestMailBase):
self._init_mock_build_email()
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
sent_emails = self._build_email_kwargs_list
# Test: one group created by raoul
self.assertTrue(len(frog_groups) == 1)
# Test: one group created by Raoul
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
res = self.mail_group.perm_read(cr, uid, [frog_group.id], details=False)
self.assertEqual(res[0].get('create_uid'), self.user_raoul_id,
'message_process: group should have been created by alias_user_id')
# Test: one message that is the incoming email
self.assertEqual(len(frog_group.message_ids), 1,
'message_process: newly created group should have the incoming email in message_ids')
@ -175,8 +181,8 @@ class TestMailgateway(TestMailBase):
# Do: incoming email from a known partner that is also an user that can create a mail.group
self.res_users.create(cr, uid, {'partner_id': p1id, 'login': 'sylvie', 'groups_id': [(6, 0, [self.group_employee_id])]})
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
# Test: one group created by Sylvie
self.assertTrue(len(frog_groups) == 1)
# Test: one group created by Raoul (or Sylvie maybe, if we implement it)
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: one message that is the incoming email
self.assertEqual(len(frog_group.message_ids), 1,
@ -195,6 +201,7 @@ class TestMailgateway(TestMailBase):
# Do: even with a wrong destination, a reply should end up in the correct thread
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other@gmail.com',
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
to='erroneous@example.com>', subject='Re: news',
extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
# Test: no group 'Re: news' created, still only 1 Frogs group
@ -205,12 +212,30 @@ class TestMailgateway(TestMailBase):
'message_process: reply on Frogs should not have created a duplicate group with old subject')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: one new message
self.assertTrue(len(frog_group.message_ids) == 2, 'message_process: group should contain 2 messages after reply')
self.assertEqual(len(frog_group.message_ids), 2, 'message_process: group should contain 2 messages after reply')
# Test: author (and not recipient) added as follower
frog_follower_ids = set([p.id for p in frog_group.message_follower_ids])
self.assertEqual(frog_follower_ids, set([p1id, p2id]),
'message_process: after reply, group should have 2 followers')
# Do: due to some issue, same email goes back into the mailgateway
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other@gmail.com',
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
subject='Re: news', extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
# Test: no group 'Re: news' created, still only 1 Frogs group
self.assertEqual(len(frog_groups), 0,
'message_process: reply on Frogs should not have created a new group with new subject')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
self.assertEqual(len(frog_groups), 1,
'message_process: reply on Frogs should not have created a duplicate group with old subject')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: no new message
self.assertEqual(len(frog_group.message_ids), 2, 'message_process: message with already existing message_id should not have been duplicated')
# Test: message_id is still unique
msg_ids = self.mail_message.search(cr, uid, [('message_id', 'ilike', '<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>')])
self.assertEqual(len(msg_ids), 1,
'message_process: message with already existing message_id should not have been duplicated')
# --------------------------------------------------
# Test3: email_from and partner finding
# --------------------------------------------------
@ -223,6 +248,7 @@ class TestMailgateway(TestMailBase):
# Do: post a new message, with a known partner -> duplicate emails -> partner
format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik <test_raoul@email.com>',
to='erroneous@example.com>', subject='Re: news (2)',
msg_id='<1198923581.41972151344608186760.JavaMail.new1@agrolait.com>',
extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
@ -236,6 +262,7 @@ class TestMailgateway(TestMailBase):
self.res_users.write(cr, uid, self.user_raoul_id, {'email': 'test_raoul@email.com'})
format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik <test_raoul@email.com>',
to='erroneous@example.com>', subject='Re: news (3)',
msg_id='<1198923581.41972151344608186760.JavaMail.new2@agrolait.com>',
extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
@ -250,6 +277,7 @@ class TestMailgateway(TestMailBase):
self.res_users.write(cr, uid, self.user_raoul_id, {'email': 'test_raoul@email.com'})
format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik <test_raoul@email.com>',
to='erroneous@example.com>', subject='Re: news (3)',
msg_id='<1198923581.41972151344608186760.JavaMail.new3@agrolait.com>',
extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
@ -265,23 +293,32 @@ class TestMailgateway(TestMailBase):
# Do: incoming email with model that does not accepts incoming emails must raise
self.assertRaises(AssertionError,
format_and_process,
MAIL_TEMPLATE, to='noone@example.com', subject='spam', extra='', model='res.country')
format_and_process,
MAIL_TEMPLATE,
to='noone@example.com', subject='spam', extra='', model='res.country',
msg_id='<1198923581.41972151344608186760.JavaMail.new4@agrolait.com>')
# Do: incoming email without model and without alias must raise
self.assertRaises(AssertionError,
format_and_process,
MAIL_TEMPLATE, to='noone@example.com', subject='spam', extra='')
format_and_process,
MAIL_TEMPLATE,
to='noone@example.com', subject='spam', extra='',
msg_id='<1198923581.41972151344608186760.JavaMail.new5@agrolait.com>')
# Do: incoming email with model that accepting incoming emails as fallback
frog_groups = format_and_process(MAIL_TEMPLATE, to='noone@example.com', subject='Spammy', extra='', model='mail.group')
frog_groups = format_and_process(MAIL_TEMPLATE,
to='noone@example.com',
subject='Spammy', extra='', model='mail.group',
msg_id='<1198923581.41972151344608186760.JavaMail.new6@agrolait.com>')
self.assertEqual(len(frog_groups), 1,
'message_process: erroneous email but with a fallback model should have created a new mail.group')
# Do: incoming email in plaintext should be stored as html
frog_groups = format_and_process(MAIL_TEMPLATE_PLAINTEXT, to='groups@example.com', subject='Frogs Return', extra='', msg_id='<deadcafe.1337@smtp.agrolait.com>')
frog_groups = format_and_process(MAIL_TEMPLATE_PLAINTEXT,
to='groups@example.com', subject='Frogs Return', extra='',
msg_id='<deadcafe.1337@smtp.agrolait.com>')
# Test: one group created with one message
self.assertTrue(len(frog_groups) == 1)
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
msg = frog_group.message_ids[0]
# Test: plain text content should be wrapped and stored as html
@ -305,19 +342,27 @@ class TestMailgateway(TestMailBase):
# Reply to msg1, make sure the reply is properly attached using the various reply identification mechanisms
# 0. Direct alias match
reply_msg1 = format(MAIL_TEMPLATE, to='Pretty Pigs <group+pigs@example.com>', extra='In-Reply-To: %s' % msg1.message_id)
reply_msg1 = format(MAIL_TEMPLATE, to='Pretty Pigs <group+pigs@example.com>',
extra='In-Reply-To: %s' % msg1.message_id,
msg_id='<1198923581.41972151344608186760.JavaMail.2@agrolait.com>')
self.mail_group.message_process(cr, uid, None, reply_msg1)
# 1. In-Reply-To header
reply_msg2 = format(MAIL_TEMPLATE, to='erroneous@example.com', extra='In-Reply-To: %s' % msg1.message_id)
reply_msg2 = format(MAIL_TEMPLATE, to='erroneous@example.com',
extra='In-Reply-To: %s' % msg1.message_id,
msg_id='<1198923581.41972151344608186760.JavaMail.3@agrolait.com>')
self.mail_group.message_process(cr, uid, None, reply_msg2)
# 2. References header
reply_msg3 = format(MAIL_TEMPLATE, to='erroneous@example.com', extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id)
reply_msg3 = format(MAIL_TEMPLATE, to='erroneous@example.com',
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id,
msg_id='<1198923581.41972151344608186760.JavaMail.4@agrolait.com>')
self.mail_group.message_process(cr, uid, None, reply_msg3)
# 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, but not to mail (not in msg1.child_ids)
reply_msg4 = format(MAIL_TEMPLATE, to='erroneous@example.com', extra='', subject='Re: [%s] 1' % self.group_pigs_id)
reply_msg4 = format(MAIL_TEMPLATE, to='erroneous@example.com',
extra='', subject='Re: [%s] 1' % self.group_pigs_id,
msg_id='<1198923581.41972151344608186760.JavaMail.5@agrolait.com>')
self.mail_group.message_process(cr, uid, 'mail.group', reply_msg4)
group_pigs.refresh()
@ -327,4 +372,55 @@ class TestMailgateway(TestMailBase):
def test_20_private_discussion(self):
""" Testing private discussion between partners. """
pass
cr, uid = self.cr, self.uid
# Do: Raoul writes to Bert and Administrator, with a thread_model in context that should not be taken into account
msg1_pids = [self.partner_admin_id, self.partner_bert_id]
msg1_id = self.mail_thread.message_post(cr, self.user_raoul_id, False,
partner_ids=msg1_pids,
subtype='mail.mt_comment',
context={'thread_model': 'mail.group'})
# Test: message recipients
msg = self.mail_message.browse(cr, uid, msg1_id)
msg_pids = [p.id for p in msg.partner_ids]
msg_nids = [p.id for p in msg.notified_partner_ids]
test_pids = msg1_pids
test_nids = msg1_pids
self.assertEqual(set(msg_pids), set(test_pids),
'message_post: private discussion: incorrect recipients')
self.assertEqual(set(msg_nids), set(test_nids),
'message_post: private discussion: incorrect notified recipients')
self.assertEqual(msg.model, False,
'message_post: private discussion: context key "thread_model" not correctly ignored when having no res_id')
# Do: Bert replies through mailgateway (is a customer)
msg2_id = self.mail_thread.message_post(cr, uid, False,
author_id=self.partner_bert_id,
parent_id=msg1_id, subtype='mail.mt_comment')
# Test: message recipients
msg = self.mail_message.browse(cr, uid, msg2_id)
msg_pids = [p.id for p in msg.partner_ids]
msg_nids = [p.id for p in msg.notified_partner_ids]
test_pids = [self.partner_admin_id, self.partner_raoul_id]
test_nids = test_pids
self.assertEqual(set(msg_pids), set(test_pids),
'message_post: private discussion: incorrect recipients when replying')
self.assertEqual(set(msg_nids), set(test_nids),
'message_post: private discussion: incorrect notified recipients when replying')
# Do: Administrator replies
msg3_id = self.mail_thread.message_post(cr, uid, False,
parent_id=msg2_id, subtype='mail.mt_comment')
# Test: message recipients
msg = self.mail_message.browse(cr, uid, msg3_id)
msg_pids = [p.id for p in msg.partner_ids]
msg_nids = [p.id for p in msg.notified_partner_ids]
test_pids = [self.partner_bert_id, self.partner_raoul_id]
test_nids = test_pids
self.assertEqual(set(msg_pids), set(test_pids),
'message_post: private discussion: incorrect recipients when replying')
self.assertEqual(set(msg_nids), set(test_nids),
'message_post: private discussion: incorrect notified recipients when replying')

View File

@ -175,11 +175,17 @@ class mail_compose_message(osv.TransientModel):
:param int res_id: id of the document record this mail is related to
"""
doc_name_get = self.pool.get(model).name_get(cr, uid, [res_id], context=context)
record_name = False
if doc_name_get:
record_name = doc_name_get[0][1]
else:
record_name = False
return {'model': model, 'res_id': res_id, 'record_name': record_name}
values = {
'model': model,
'res_id': res_id,
'record_name': record_name,
}
if record_name:
values['subject'] = 'Re: %s' % record_name
return values
def get_message_data(self, cr, uid, message_id, context=None):
""" Returns a defaults-like dict with initial values for the composition
@ -197,7 +203,7 @@ class mail_compose_message(osv.TransientModel):
# create subject
re_prefix = _('Re:')
reply_subject = tools.ustr(message_data.subject or '')
reply_subject = tools.ustr(message_data.subject or message_data.record_name or '')
if not (reply_subject.startswith('Re:') or reply_subject.startswith(re_prefix)) and message_data.subject:
reply_subject = "%s %s" % (re_prefix, reply_subject)
# get partner_ids from original message

View File

@ -45,7 +45,7 @@ class StockMove(osv.osv):
procurement_obj = self.pool.get('procurement.order')
product_obj = self.pool.get('product.product')
processed_ids = [move.id]
if move.product_id.supply_method == 'produce' and move.product_id.procure_method == 'make_to_order':
if move.product_id.supply_method == 'produce':
bis = bom_obj.search(cr, uid, [
('product_id','=',move.product_id.id),
('bom_id','=',False),

View File

@ -4,7 +4,8 @@ Created on 18 oct. 2011
@author: openerp
'''
from openerp.osv import fields, osv
from openerp.osv import osv
from openerp.tools.translate import _
class plugin_handler(osv.osv_memory):
_name = 'plugin.handler'
@ -29,7 +30,7 @@ class plugin_handler(osv.osv_memory):
partner_ids = partner_obj.search(cr, uid, [('email', 'like', address_email)])
res_id = partner_ids and partner_ids[0] or 0
url = self._make_url(cr, uid, res_id, 'res.partner')
return ('res.partner', res_id , url)
return ('res.partner', res_id, url)
def document_get(self, cr, uid, email):
"""
@ -48,7 +49,7 @@ class plugin_handler(osv.osv_memory):
message_id = msg.get('message_id')
msg_id = False
if message_id:
msg_ids = mail_message_obj.search(cr, uid, [('message_id','=', message_id)])
msg_ids = mail_message_obj.search(cr, uid, [('message_id', '=', message_id)])
msg_id = len(msg_ids) and msg_ids[0] or False
if not msg_id and parent_id:
msg_id = parent_id
@ -57,8 +58,8 @@ class plugin_handler(osv.osv_memory):
res_id = msg.res_id
model = msg.model
url = self._make_url(cr, uid, res_id, model)
name = self.pool.get(model).name_get(cr, uid, [res_id])[0][1]
return (model,res_id, url,name)
name = self.pool.get(model).name_get(cr, uid, [res_id])[0][1]
return (model, res_id, url, name)
def document_type(self, cr, uid, context=None):
"""
@ -94,26 +95,25 @@ class plugin_handler(osv.osv_memory):
model_obj = self.pool.get(model)
msg = self.pool.get('mail.thread').message_parse(cr, uid, email)
message_id = msg.get('message-id')
mail_ids = mail_message.search(cr, uid, [('message_id','=',message_id),('res_id','=',res_id),('model','=',model)])
if message_id and mail_ids :
mail_ids = mail_message.search(cr, uid, [('message_id', '=', message_id), ('res_id', '=', res_id), ('model', '=', model)])
if message_id and mail_ids:
mail_record = mail_message.browse(cr, uid, mail_ids)[0]
res_id = mail_record.res_id
notify = "Email already pushed"
notify = _("Email already pushed")
elif res_id == 0:
if model == 'res.partner':
notify = 'User the Partner button to create a new partner'
notify = _('Use the Partner button to create a new partner')
else:
res_id = model_obj.message_process(cr, uid, model, email)
notify = "Mail successfully pushed, a new %s has been created " % model
notify = _("Mail successfully pushed, a new %s has been created.") % model
else:
model_obj.message_post(cr, uid, [res_id],
body= msg.get('body'),
subject= msg.get('subject'),
type= 'email',
parent_id= msg.get('parent_id'),
attachments= msg.get('attachments'))
notify = "Mail successfully pushed"
body=msg.get('body'),
subject=msg.get('subject'),
type='email',
parent_id=msg.get('parent_id'),
attachments=msg.get('attachments'))
notify = _("Mail successfully pushed")
url = self._make_url(cr, uid, res_id, model)
return (model, res_id, url, notify)
@ -154,16 +154,17 @@ class plugin_handler(osv.osv_memory):
message_id = msg.get('message-id')
push_mail = self.push_message(cr, uid, model, headers, res_id)
res_id = push_mail[1]
model = push_mail[0]
model = push_mail[0]
notify = push_mail[3]
for name in attachments.keys():
attachment_ids = ir_attachment_obj.search(cr, uid, [('res_model', '=', model), ('res_id', '=', res_id), ('datas_fname', '=', name)])
if attachment_ids:
attach_ids.append( attachment_ids[0])
attach_ids.append(attachment_ids[0])
else:
vals = {"res_model": model, "res_id": res_id, "name": name, "datas" :attachments[name], "datas_fname" : name}
vals = {"res_model": model, "res_id": res_id, "name": name, "datas": attachments[name], "datas_fname": name}
attach_ids.append(ir_attachment_obj.create(cr, uid, vals))
mail_ids = mail_message.search(cr, uid, [('message_id','=',message_id),('res_id','=',res_id),('model','=',model)])
mail_ids = mail_message.search(cr, uid, [('message_id', '=', message_id), ('res_id', '=', res_id), ('model', '=', model)])
if mail_ids:
ids = mail_message.write(cr, uid, mail_ids[0], { 'attachment_ids': [(6, 0, attach_ids)],'body':body,'body_html':body_html})
mail_message.write(cr, uid, mail_ids[0], {'attachment_ids': [(6, 0, attach_ids)], 'body': body, 'body_html': body_html})
url = self._make_url(cr, uid, res_id, model)
return (model, res_id, url)
return (model, res_id, url, notify)

View File

@ -17,6 +17,7 @@
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@ -29,7 +30,6 @@
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
@ -53,9 +53,8 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="CookComputing.XmlRpcV2, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\OpenERPOutlookPlugin\bin\Release\CookComputing.XmlRpcV2.dll</HintPath>
<Reference Include="CookComputing.XmlRpcV2">
<HintPath>..\CookComputing.XmlRpcV2.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
@ -81,7 +80,7 @@
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
@ -91,7 +90,7 @@
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>

View File

@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenERPOutlookPlugin", "OpenERPOutlookPlugin\OpenERPOutlookPlugin.csproj", "{F4B2219B-F235-400F-81B4-92F15250BBA4}"
EndProject
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "OpenERPOutlookPluginSetup", "OpenERPOutlookPluginSetup\OpenERPOutlookPluginSetup.vdproj", "{96333293-0156-4998-9065-42721CEB0368}"

View File

@ -303,6 +303,7 @@ namespace OpenERPOutlookPlugin
foreach (outlook.MailItem mailitem in Tools.MailItems())
{
Object[] contact = Cache.OpenERPOutlookPlugin.RedirectPartnerPage(mailitem);
if ((int)contact[1] > 0)

View File

@ -95,7 +95,6 @@ namespace OpenERPOutlookPlugin
/*
* Will open the url into the web browser.
*/
System.Diagnostics.Process.Start(web_url.ToString());
}
@ -163,9 +162,16 @@ namespace OpenERPOutlookPlugin
args.Add(attachments);
object push_mail = this.Connection.Execute("plugin.handler", "push_message_outlook", args.ToArray());
object[] push = (object[])push_mail;
this.RedirectWeb(push[2].ToString());
return true;
if (Convert.ToInt32(push[1]) == 0)
{
MessageBox.Show(push[3].ToString());
}
else
{
this.RedirectWeb(push[2].ToString());
}
return true;
}
public long CreatePartnerRecord(string name)
{

View File

@ -295,7 +295,8 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
return;
}
//try to push an order to the server
(new instance.web.Model('pos.order')).get_func('create_from_ui')([order])
// shadow : true is to prevent a spinner to appear in case of timeout
(new instance.web.Model('pos.order')).call('create_from_ui',[[order]],undefined,{ shadow:true })
.fail(function(unused, event){
//don't show error popup if it fails
event.preventDefault();

View File

@ -794,7 +794,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
renderElement: function() {
var self = this;
this._super();
this.$('.oe_pos_synch-notification-button').click(function(){
this.$el.click(function(){
self.pos.flush();
});
},
@ -879,6 +879,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
instance.web.unblockUI();
self.$('.loader').animate({opacity:0},1500,'swing',function(){self.$('.loader').hide();});
self.pos.flush();
}).fail(function(){ // error when loading models data from the backend
instance.web.unblockUI();
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_session_opening']], ['res_id'])

View File

@ -21,7 +21,6 @@
<field name="params" eval="&quot;{
'domain': [
('to_read', '=', True),
('starred', '=', False),
],
'show_compose_message': False,
'show_link': False,
@ -40,6 +39,7 @@
</field>
</record>
<!-- TODO: remove me in 8.0 -->
<record id="action_mail_star_feeds_portal" model="ir.actions.client">
<field name="name">To-do</field>
<field name="tag">mail.wall</field>
@ -67,6 +67,9 @@
</p>
</field>
</record>
<menuitem name="To-do" id="portal_mail_starfeeds" parent="portal_messages"
action="action_mail_star_feeds_portal" sequence="20" groups="base.group_no_one"/>
<!-- end -->
<record id="action_mail_archives_feeds_portal" model="ir.actions.client">
<field name="name">Archives</field>
@ -84,7 +87,6 @@
'show_compose_message': False,
'show_link': False,
'view_mailbox': True,
'read_action': 'read'
}&quot;"/>
<field name="help" type="html">
<p>
@ -98,8 +100,6 @@
<menuitem name="Inbox" id="portal_inbox" parent="portal_messages"
action="action_mail_inbox_feeds_portal" sequence="10" groups="portal.group_portal"/>
<menuitem name="To-do" id="portal_mail_starfeeds" parent="portal_messages"
action="action_mail_star_feeds_portal" sequence="20" groups="portal.group_portal"/>
<menuitem name="Archives" id="portal_mail_archivesfeeds" parent="portal_messages"
action="action_mail_archives_feeds_portal" sequence="30" groups="portal.group_portal"/>
@ -107,7 +107,7 @@
Create menu items that we'll leave empty for now - they'll be
filled up by other portal modules.
-->
<menuitem name="Quotations and Sales Orders" id="portal_orders" parent="portal_menu" sequence="20"/>
<menuitem name="Billing" id="portal_orders" parent="portal_menu" sequence="20"/>
<menuitem name="After Sale Services" id="portal_after_sales" parent="portal_menu" sequence="30"/>
<menuitem name="Projects" id="portal_projects" parent="portal_menu" sequence="40"/>

View File

@ -59,19 +59,8 @@ class sale_order(osv.Model):
assert len(ids) == 1
document = self.browse(cr, uid, ids[0], context=context)
partner = document.partner_id
# TDE note: this code should be improved: used a real invite wizard instead of an ugly email
if partner.id not in document.message_follower_ids:
self.message_subscribe(cr, uid, ids, [partner.id], context=context)
mail_values = {
'recipient_ids': [(4, partner.id)],
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
'body_html': 'You have been invited to follow %s' % document.name_get()[0][1],
'auto_delete': True,
'type': 'email',
}
mail_obj = self.pool.get('mail.mail')
mail_id = mail_obj.create(cr, uid, mail_values, context=context)
mail_obj.send(cr, uid, [mail_id], context=context)
return super(sale_order, self).action_button_confirm(cr, uid, ids, context=context)
def get_signup_url(self, cr, uid, ids, context=None):

View File

@ -374,7 +374,7 @@ class product_pricelist_item(osv.osv):
result.append((line.id, line.name))
result.append((-1, _('Other Pricelist')))
result.append((-2, _('Partner section of the product form')))
result.append((-2, _('Supplier Prices on the product form')))
return result
_name = "product.pricelist.item"

View File

@ -588,10 +588,13 @@ class product_product(osv.osv):
# Check if the product is last product of this template
other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context)
if not other_product_ids:
unlink_product_tmpl_ids.append(tmpl_id)
unlink_product_tmpl_ids.append(tmpl_id)
unlink_ids.append(product.id)
res = super(product_product, self).unlink(cr, uid, unlink_ids, context=context)
# delete templates after calling super, as deleting template could lead to deleting
# products due to ondelete='cascade'
self.pool.get('product.template').unlink(cr, uid, unlink_product_tmpl_ids, context=context)
return super(product_product, self).unlink(cr, uid, unlink_ids, context=context)
return res
def onchange_uom(self, cursor, user, ids, uom_id, uom_po_id):
if uom_id and uom_po_id:

View File

@ -581,6 +581,7 @@
<field name="delay"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
<p groups="product.group_purchase_pricelist" class="oe_grey">The prices below will only be taken into account when your pricelist is set as based on supplier prices.</p>
<field groups="product.group_purchase_pricelist" name="pricelist_ids">
<tree editable="bottom" string="Pricelist">
<field name="min_quantity"/>

View File

@ -286,7 +286,6 @@ class project(osv.osv):
'type_ids': _get_type_common,
'alias_model': 'project.task',
'privacy_visibility': 'public',
'alias_domain': False, # always hide alias during creation
}
# TODO: Why not using a SQL contraints ?
@ -531,11 +530,11 @@ def Project():
context = dict(context, project_creation_in_progress=True)
mail_alias = self.pool.get('mail.alias')
if not vals.get('alias_id') and vals.get('name', False):
vals.pop('alias_name', None) # prevent errors during copy()
alias_name = vals.pop('alias_name', None) # prevent errors during copy()
alias_id = mail_alias.create_unique_alias(cr, uid,
# Using '+' allows using subaddressing for those who don't
# have a catchall domain setup.
{'alias_name': "project+"+short_name(vals['name'])},
{'alias_name': alias_name or "project+"+short_name(vals['name'])},
model_name=vals.get('alias_model', 'project.task'),
context=context)
vals['alias_id'] = alias_id
@ -605,8 +604,7 @@ class task(base_stage, osv.osv):
search_domain = []
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
if project_id:
search_domain += ['|', ('project_ids', '=', project_id)]
search_domain += [('id', 'in', ids)]
search_domain += [('project_ids', '=', project_id)]
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
# restore order of the search
@ -889,6 +887,12 @@ class task(base_stage, osv.osv):
res['fields'][f]['string'] = res['fields'][f]['string'].replace('Hours',tm)
return res
def get_empty_list_help(self, cr, uid, help, context=None):
context['empty_list_help_id'] = context.get('default_project_id')
context['empty_list_help_model'] = 'project.project'
context['empty_list_help_document_name'] = _("tasks")
return super(task, self).get_empty_list_help(cr, uid, help, context=context)
# ----------------------------------------
# Case management
# ----------------------------------------

View File

@ -21,6 +21,7 @@
<record id="all_projects_account" model="account.analytic.account">
<field name="name">Projects</field>
<field name="code">3</field>
<field name="type">view</field>
</record>
<function id="parent_project_default_set" model="ir.values" name="set" eval="('default',False,'parent_id', [('project.project', False)], all_projects_account, True, False, False, False, True)"/>

Some files were not shown because too many files have changed in this diff Show More