[MERGE]merge with parent branch
bzr revid: sgo@tinyerp.com-20120904093250-fwawd23g26064wnl
This commit is contained in:
@@ -30,6 +30,8 @@ from osv import fields, osv
|
||||
import decimal_precision as dp
|
||||
from tools.translate import _
|
||||
from tools.float_utils import float_round
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -819,7 +821,7 @@ class account_journal(osv.osv):
|
||||
if not 'sequence_id' in vals or not vals['sequence_id']:
|
||||
# if we have the right to create a journal, we should be able to
|
||||
# create it's sequence.
|
||||
vals.update({'sequence_id': self.create_sequence(cr, 1, vals, context)})
|
||||
vals.update({'sequence_id': self.create_sequence(cr, SUPERUSER_ID, vals, context)})
|
||||
return super(account_journal, self).create(cr, uid, vals, context)
|
||||
|
||||
def name_get(self, cr, user, ids, context=None):
|
||||
@@ -1858,7 +1860,7 @@ class account_tax(osv.osv):
|
||||
|
||||
def get_precision_tax():
|
||||
def change_digit_tax(cr):
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, 1, 'Account')
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, SUPERUSER_ID, 'Account')
|
||||
return (16, res+2)
|
||||
return change_digit_tax
|
||||
|
||||
@@ -3347,13 +3349,11 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||
# Install all the templates objects and generate the real objects
|
||||
acc_template_ref, taxes_ref, tax_code_ref = self._install_template(cr, uid, obj_wizard.chart_template_id.id, company_id, code_digits=obj_wizard.code_digits, obj_wizard=obj_wizard, context=context)
|
||||
|
||||
# write values of default taxes for product
|
||||
# write values of default taxes for product as super user
|
||||
if obj_wizard.sale_tax and taxes_ref:
|
||||
ir_values_obj.set(cr, uid, key='default', key2=False, name="taxes_id", company=company_id,
|
||||
models =[('product.product',False)], value=[taxes_ref[obj_wizard.sale_tax.id]])
|
||||
ir_values_obj.set_default(cr, SUPERUSER_ID, 'product.product', "taxes_id", [taxes_ref[obj_wizard.sale_tax.id]], for_all_users=True, company_id=company_id)
|
||||
if obj_wizard.purchase_tax and taxes_ref:
|
||||
ir_values_obj.set(cr, uid, key='default', key2=False, name="supplier_taxes_id", company=company_id,
|
||||
models =[('product.product',False)], value=[taxes_ref[obj_wizard.purchase_tax.id]])
|
||||
ir_values_obj.set_default(cr, SUPERUSER_ID, 'product.product', "supplier_taxes_id", [taxes_ref[obj_wizard.purchase_tax.id]], for_all_users=True, company_id=company_id)
|
||||
|
||||
# Create Bank journals
|
||||
self._create_bank_journals_from_o2m(cr, uid, obj_wizard, company_id, acc_template_ref, context=context)
|
||||
|
||||
@@ -1298,16 +1298,15 @@ class account_invoice(osv.osv):
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>created</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
||||
self.message_post(cr, uid, [obj.id],body=_("%s <b>created</b>.") % (self._get_document_type(obj.type)), subtype="new", context=context)
|
||||
|
||||
def confirm_paid_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (self._get_document_type(obj.type)), subtype="paid", context=context)
|
||||
|
||||
def invoice_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
||||
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (self._get_document_type(obj.type)), subtype="cancelled", context=context)
|
||||
account_invoice()
|
||||
|
||||
class account_invoice_line(osv.osv):
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
<!--
|
||||
Account Statement Sequences
|
||||
-->
|
||||
|
||||
<record id="sequence_reconcile" model="ir.sequence.type">
|
||||
<field name="name">Account Reconcile</field>
|
||||
<field name="code">account.reconcile</field>
|
||||
@@ -554,8 +553,6 @@
|
||||
<field eval="1" name="number_next"/>
|
||||
<field eval="1" name="number_increment"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!--
|
||||
Invoice requests (deprecated)
|
||||
-->
|
||||
@@ -563,8 +560,28 @@
|
||||
<field name="name">Invoice</field>
|
||||
<field name="object">account.invoice</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="name">new</field>
|
||||
<field name="model_ids" eval="[(4,ref('analytic.model_account_analytic_account')),(4,ref('account.model_account_invoice'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_paid" model="mail.message.subtype">
|
||||
<field name="name">paid</field>
|
||||
<field name="model_ids" eval="[(4,ref('account.model_account_invoice'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="name">cancelled</field>
|
||||
<field name="model_ids" eval="[(4,ref('account.model_account_invoice'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('account.model_account_invoice')), (4,ref('analytic.model_account_analytic_account'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('account.model_account_invoice')), (4,ref('analytic.model_account_analytic_account'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('account.model_account_invoice')), (4,ref('analytic.model_account_analytic_account'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -0,0 +1,546 @@
|
||||
# Norwegian Bokmal translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
|
||||
"PO-Revision-Date: 2012-09-02 09:46+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-09-03 05:21+0000\n"
|
||||
"X-Generator: Launchpad (build 15890)\n"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:analytic.plan.create.model:0
|
||||
msgid ""
|
||||
"This distribution model has been saved.You will be able to reuse it later."
|
||||
msgstr ""
|
||||
"Denne fordeling modellen har vært lagret. Du vil kunne bruke den senere."
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance.line,plan_id:0
|
||||
msgid "Plan Id"
|
||||
msgstr "Plan ID"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "From Date"
|
||||
msgstr "Fra dato"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
#: view:account.crossovered.analytic:0
|
||||
#: model:ir.actions.act_window,name:account_analytic_plans.action_account_crossovered_analytic
|
||||
#: model:ir.actions.report.xml,name:account_analytic_plans.account_analytic_account_crossovered_analytic
|
||||
msgid "Crossovered Analytic"
|
||||
msgstr "Krysset Analyse"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.analytic.plan:0
|
||||
#: field:account.analytic.plan,name:0
|
||||
#: field:account.analytic.plan.line,plan_id:0
|
||||
#: model:ir.actions.act_window,name:account_analytic_plans.account_analytic_plan_form_action
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_analytic_plan
|
||||
#: model:ir.ui.menu,name:account_analytic_plans.menu_account_analytic_plan_action
|
||||
msgid "Analytic Plan"
|
||||
msgstr "Analytisk Plan"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,journal_id:0
|
||||
#: view:account.crossovered.analytic:0
|
||||
#: field:account.crossovered.analytic,journal_ids:0
|
||||
msgid "Analytic Journal"
|
||||
msgstr "Analytisk journal"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.analytic.plan.line:0
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_analytic_plan_line
|
||||
msgid "Analytic Plan Line"
|
||||
msgstr "Analytisk plan linje"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/wizard/account_crossovered_analytic.py:61
|
||||
#, python-format
|
||||
msgid "User Error"
|
||||
msgstr "Brukerfeil"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_analytic_plan_instance
|
||||
msgid "Analytic Plan Instance"
|
||||
msgstr "Analytisk Plan forekomst"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:analytic.plan.create.model:0
|
||||
msgid "Ok"
|
||||
msgstr "Ok"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,plan_id:0
|
||||
msgid "Model's Plan"
|
||||
msgstr "Modell Plan"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,account2_ids:0
|
||||
msgid "Account2 Id"
|
||||
msgstr "Konto2 ID"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: sql_constraint:account.invoice:0
|
||||
msgid "Invoice Number must be unique per Company!"
|
||||
msgstr "Fakturanummer må være unik pr. firma!"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Amount"
|
||||
msgstr "Beløp"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.journal:0
|
||||
msgid ""
|
||||
"Configuration error! The currency chosen should be shared by the default "
|
||||
"accounts too."
|
||||
msgstr ""
|
||||
"Konfigurasjon feil! Den valgte valutaen bør deles av standard kontoer også."
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: sql_constraint:account.move.line:0
|
||||
msgid "Wrong credit or debit value in accounting entry !"
|
||||
msgstr "Feil kredit eller debet beløp i regnskaps oppføringen !"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,account6_ids:0
|
||||
msgid "Account6 Id"
|
||||
msgstr "Konto6 ID"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.ui.menu,name:account_analytic_plans.menu_account_analytic_multi_plan_action
|
||||
msgid "Multi Plans"
|
||||
msgstr "Multi Planer"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_bank_statement_line
|
||||
msgid "Bank Statement Line"
|
||||
msgstr "Kontoutskriftlinje"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.actions.act_window,name:account_analytic_plans.account_analytic_plan_form_action_installer
|
||||
msgid "Define your Analytic Plans"
|
||||
msgstr "Definer dine analytiske planer."
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.invoice:0
|
||||
msgid "Invalid BBA Structured Communication !"
|
||||
msgstr "Ugyldig BBA Strukturert Kommunikasjon!"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.bank.statement:0
|
||||
msgid "The journal and period chosen have to belong to the same company."
|
||||
msgstr "Tidsskriftet og perioden valgt å tilhøre samme selskap."
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.move.line:0
|
||||
msgid ""
|
||||
"The date of your Journal Entry is not in the defined period! You should "
|
||||
"change the date or remove this constraint from the journal."
|
||||
msgstr ""
|
||||
"Datoen for din bilagsregistrering ikke er i den definerte perioden! Du bør "
|
||||
"endre datoen eller fjerne denne begrensningen fra tidsskriftet."
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: sql_constraint:account.journal:0
|
||||
msgid "The code of the journal must be unique per company !"
|
||||
msgstr "Journalkoden må være unik pr firma!"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.crossovered.analytic,ref:0
|
||||
msgid "Analytic Account Reference"
|
||||
msgstr "Analytisk konto Referanse."
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_sale_order_line
|
||||
msgid "Sales Order Line"
|
||||
msgstr "Salgsordrelinje"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/wizard/analytic_plan_create_model.py:47
|
||||
#: view:analytic.plan.create.model:0
|
||||
#, python-format
|
||||
msgid "Distribution Model Saved"
|
||||
msgstr "Distribusjon Model Lagret"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.actions.act_window,name:account_analytic_plans.account_analytic_plan_instance_action
|
||||
msgid "Analytic Distribution's Models"
|
||||
msgstr "Analytisk distribusjon modeller"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.crossovered.analytic:0
|
||||
msgid "Print"
|
||||
msgstr "Skriv ut"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
#: field:account.analytic.line,percentage:0
|
||||
msgid "Percentage"
|
||||
msgstr "Prosentdel"
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:221
|
||||
#, python-format
|
||||
msgid "A model having this name and code already exists !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/wizard/analytic_plan_create_model.py:41
|
||||
#, python-format
|
||||
msgid "No analytic plan defined !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance.line,rate:0
|
||||
msgid "Rate (%)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.analytic.plan:0
|
||||
#: field:account.analytic.plan,plan_ids:0
|
||||
#: field:account.journal,plan_id:0
|
||||
msgid "Analytic Plans"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Perc(%)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.line,max_required:0
|
||||
msgid "Maximum Allowed (%)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Printing date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.analytic.plan.line:0
|
||||
msgid "Analytic Plan Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.bank.statement.line:0
|
||||
msgid ""
|
||||
"The amount of the voucher must be the same amount as the one on the "
|
||||
"statement line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_invoice_line
|
||||
msgid "Invoice Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.move.line:0
|
||||
msgid ""
|
||||
"The selected account of your Journal Entry forces to provide a secondary "
|
||||
"currency. You should remove the secondary currency on the account or select "
|
||||
"a multi-currency view on the journal."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.crossovered.analytic,date1:0
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,account_ids:0
|
||||
msgid "Account Id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,account5_ids:0
|
||||
msgid "Account5 Id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_analytic_plan_instance_line
|
||||
msgid "Analytic Instance Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.line,root_analytic_id:0
|
||||
msgid "Root Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "To Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:341
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:485
|
||||
#, python-format
|
||||
msgid "You have to define an analytic journal on the '%s' journal!"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.crossovered.analytic,empty_line:0
|
||||
msgid "Dont show empty lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.actions.act_window,name:account_analytic_plans.action_analytic_plan_create_model
|
||||
msgid "analytic.plan.create.model.action"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_analytic_line
|
||||
msgid "Analytic Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Analytic Account :"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Analytic Account Reference:"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.line,name:0
|
||||
msgid "Plan Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan,default_instance_id:0
|
||||
msgid "Default Entries"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_move_line
|
||||
msgid "Journal Items"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,account1_ids:0
|
||||
msgid "Account1 Id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.line,min_required:0
|
||||
msgid "Minimum Allowed (%)"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: help:account.analytic.plan.line,root_analytic_id:0
|
||||
msgid "Root account of this plan."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:221
|
||||
#: code:addons/account_analytic_plans/wizard/analytic_plan_create_model.py:38
|
||||
#: code:addons/account_analytic_plans/wizard/analytic_plan_create_model.py:41
|
||||
#, python-format
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:analytic.plan.create.model:0
|
||||
msgid "Save This Distribution as a Model"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.move.line:0
|
||||
msgid "You can not create journal items on an account of type view."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/wizard/analytic_plan_create_model.py:38
|
||||
#, python-format
|
||||
msgid "Please put a name and a code before saving the model !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_crossovered_analytic
|
||||
msgid "Print Crossovered Analytic"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:341
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:485
|
||||
#, python-format
|
||||
msgid "No Analytic Journal !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance.line,analytic_account_id:0
|
||||
msgid "Analytic Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_bank_statement
|
||||
msgid "Bank Statement"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,account3_ids:0
|
||||
msgid "Account3 Id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.analytic.line:0
|
||||
msgid "You can not create analytic line on view account."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_invoice
|
||||
msgid "Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.crossovered.analytic:0
|
||||
#: view:analytic.plan.create.model:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,account4_ids:0
|
||||
msgid "Account4 Id"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.move.line:0
|
||||
msgid "Company must be the same for its related account and period."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.analytic.plan.instance.line:0
|
||||
msgid "Analytic Distribution Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:234
|
||||
#, python-format
|
||||
msgid "The Total Should be Between %s and %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "at"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Account Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: view:account.analytic.plan.instance.line:0
|
||||
msgid "Analytic Distribution Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.instance,code:0
|
||||
msgid "Distribution Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "%"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "100.00%"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.default,analytics_id:0
|
||||
#: view:account.analytic.plan.instance:0
|
||||
#: field:account.analytic.plan.instance,name:0
|
||||
#: field:account.bank.statement.line,analytics_id:0
|
||||
#: field:account.invoice.line,analytics_id:0
|
||||
#: field:account.move.line,analytics_id:0
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_analytic_default
|
||||
msgid "Analytic Distribution"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_account_journal
|
||||
msgid "Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.model,name:account_analytic_plans.model_analytic_plan_create_model
|
||||
msgid "analytic.plan.create.model"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.crossovered.analytic,date2:0
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.actions.act_window,name:account_analytic_plans.account_analytic_instance_model_open
|
||||
msgid "Distribution Models"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: model:ir.actions.act_window,help:account_analytic_plans.account_analytic_plan_form_action_installer
|
||||
msgid ""
|
||||
"To setup a multiple analytic plans environment, you must define the root "
|
||||
"analytic accounts for each plan set. Then, you must attach a plan set to "
|
||||
"your account journals."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: constraint:account.move.line:0
|
||||
msgid "You can not create journal items on closed account."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: report:account.analytic.account.crossovered.analytic:0
|
||||
msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: field:account.analytic.plan.line,sequence:0
|
||||
msgid "Sequence"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: sql_constraint:account.journal:0
|
||||
msgid "The name of the journal must be unique per company !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_analytic_plans
|
||||
#: code:addons/account_analytic_plans/account_analytic_plans.py:234
|
||||
#, python-format
|
||||
msgid "Value Error"
|
||||
msgstr ""
|
||||
@@ -1293,17 +1293,17 @@ class account_voucher(osv.osv):
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
message = "%s <b>created</b>." % self._document_type[obj.type or False]
|
||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=message, subtype="new", context=context)
|
||||
|
||||
def post_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
message = "%s '%s' is <b>posted</b>." % (self._document_type[obj.type or False], obj.move_id.name)
|
||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=message, subtype="post", context=context)
|
||||
|
||||
def reconcile_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
message = "%s <b>reconciled</b>." % self._document_type[obj.type or False]
|
||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=message, subtype="reconcile", context=context)
|
||||
|
||||
account_voucher()
|
||||
|
||||
|
||||
@@ -2,16 +2,38 @@
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<!-- notify all employees of module installation -->
|
||||
<record model="mail.message" id="module_install_notification">
|
||||
<field name="model">mail.group</field>
|
||||
<field name="res_id" ref="mail.group_all_employees"/>
|
||||
<field name="type">notification</field>
|
||||
<field name="subject">eInvoicing & Payments application installed!</field>
|
||||
<field name="body">OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
|
||||
<function model="mail.group" name="message_post">
|
||||
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
|
||||
<value eval="[ref('mail.group_all_employees')]"/>
|
||||
<value>OpenERP's electronic invoicing allows to ease and fasten the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
|
||||
|
||||
You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability.
|
||||
You can track customer payments easily and automate the reminders. You get an overview of the discussion with your customers on each invoice to ensure a full traceability.
|
||||
|
||||
For advanced accounting features, you should install the "Accounting and Finance" module.</field>
|
||||
If you want to use advanced accounting features, you should install the "Accounting and Finance" module.</value>
|
||||
<value>Module eInvoicing & Payments has been installed.</value>
|
||||
</function>
|
||||
<!-- Message Sub Type -->
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('account_voucher.model_account_voucher'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_post" model="mail.message.subtype">
|
||||
<field name="name">post</field>
|
||||
<field name="model_ids" eval="[(4,ref('account_voucher.model_account_voucher'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_reconcile" model="mail.message.subtype">
|
||||
<field name="name">reconcile</field>
|
||||
<field name="model_ids" eval="[(4,ref('account_voucher.model_account_voucher'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('account_voucher.model_account_voucher'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('account_voucher.model_account_voucher'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('account_voucher.model_account_voucher'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -297,7 +297,7 @@ class account_analytic_account(osv.osv):
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name), subtype="new", context=context)
|
||||
|
||||
account_analytic_account()
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ from tools.translate import _
|
||||
import pooler
|
||||
import time
|
||||
import tools
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
class audittrail_rule(osv.osv):
|
||||
"""
|
||||
@@ -252,10 +253,10 @@ class audittrail_objects_proxy(object_proxy):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
resource_pool = pool.get(model)
|
||||
model_pool = pool.get('ir.model')
|
||||
model_ids = model_pool.search(cr, 1, [('model', '=', model)])
|
||||
model_ids = model_pool.search(cr, SUPERUSER_ID, [('model', '=', model)])
|
||||
model_id = model_ids and model_ids[0] or False
|
||||
assert model_id, _("'%s' Model does not exist..." %(model))
|
||||
model = model_pool.browse(cr, 1, model_id)
|
||||
model = model_pool.browse(cr, SUPERUSER_ID, model_id)
|
||||
|
||||
# fields to log. currently only used by log on read()
|
||||
field_list = []
|
||||
@@ -322,7 +323,7 @@ class audittrail_objects_proxy(object_proxy):
|
||||
data = {}
|
||||
resource_pool = pool.get(model.model)
|
||||
# read all the fields of the given resources in super admin mode
|
||||
for resource in resource_pool.read(cr, 1, res_ids):
|
||||
for resource in resource_pool.read(cr, SUPERUSER_ID, res_ids):
|
||||
values = {}
|
||||
values_text = {}
|
||||
resource_id = resource['id']
|
||||
@@ -332,19 +333,19 @@ class audittrail_objects_proxy(object_proxy):
|
||||
continue
|
||||
values[field] = resource[field]
|
||||
# get the textual value of that field for this record
|
||||
values_text[field] = self.get_value_text(cr, 1, pool, resource_pool, method, field, resource[field])
|
||||
values_text[field] = self.get_value_text(cr, SUPERUSER_ID, pool, resource_pool, method, field, resource[field])
|
||||
|
||||
field_obj = resource_pool._all_columns.get(field).column
|
||||
if field_obj._type in ('one2many','many2many'):
|
||||
# check if an audittrail rule apply in super admin mode
|
||||
if self.check_rules(cr, 1, field_obj._obj, method):
|
||||
if self.check_rules(cr, SUPERUSER_ID, field_obj._obj, method):
|
||||
# check if the model associated to a *2m field exists, in super admin mode
|
||||
x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)])
|
||||
x2m_model_ids = pool.get('ir.model').search(cr, SUPERUSER_ID, [('model', '=', field_obj._obj)])
|
||||
x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False
|
||||
assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj))
|
||||
x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id)
|
||||
x2m_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, x2m_model_id)
|
||||
#recursive call on x2m fields that need to be checked too
|
||||
data.update(self.get_data(cr, 1, pool, resource[field], x2m_model, method))
|
||||
data.update(self.get_data(cr, SUPERUSER_ID, pool, resource[field], x2m_model, method))
|
||||
data[(model.id, resource_id)] = {'text':values_text, 'value': values}
|
||||
return data
|
||||
|
||||
@@ -389,12 +390,12 @@ class audittrail_objects_proxy(object_proxy):
|
||||
field_obj = field_definition.column
|
||||
if field_obj._type in ('one2many','many2many'):
|
||||
# checking if an audittrail rule apply in super admin mode
|
||||
if self.check_rules(cr, 1, field_obj._obj, method):
|
||||
if self.check_rules(cr, SUPERUSER_ID, field_obj._obj, method):
|
||||
# checking if the model associated to a *2m field exists, in super admin mode
|
||||
x2m_model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', field_obj._obj)])
|
||||
x2m_model_ids = pool.get('ir.model').search(cr, SUPERUSER_ID, [('model', '=', field_obj._obj)])
|
||||
x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False
|
||||
assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj))
|
||||
x2m_model = pool.get('ir.model').browse(cr, 1, x2m_model_id)
|
||||
x2m_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, x2m_model_id)
|
||||
# the resource_ids that need to be checked are the sum of both old and previous values (because we
|
||||
# need to log also creation or deletion in those lists).
|
||||
x2m_old_values_ids = old_values.get(key, {'value': {}})['value'].get(field_name, [])
|
||||
@@ -402,7 +403,7 @@ class audittrail_objects_proxy(object_proxy):
|
||||
# We use list(set(...)) to remove duplicates.
|
||||
res_ids = list(set(x2m_old_values_ids + x2m_new_values_ids))
|
||||
for res_id in res_ids:
|
||||
lines.update(self.prepare_audittrail_log_line(cr, 1, pool, x2m_model, res_id, method, old_values, new_values, field_list))
|
||||
lines.update(self.prepare_audittrail_log_line(cr, SUPERUSER_ID, pool, x2m_model, res_id, method, old_values, new_values, field_list))
|
||||
# if the value value is different than the old value: record the change
|
||||
if key not in old_values or key not in new_values or old_values[key]['value'][field_name] != new_values[key]['value'][field_name]:
|
||||
data = {
|
||||
@@ -459,9 +460,9 @@ class audittrail_objects_proxy(object_proxy):
|
||||
vals.update({'method': 'unlink'})
|
||||
# create the audittrail log in super admin mode, only if a change has been detected
|
||||
if lines[(model_id, resource_id)]:
|
||||
log_id = pool.get('audittrail.log').create(cr, 1, vals)
|
||||
log_id = pool.get('audittrail.log').create(cr, SUPERUSER_ID, vals)
|
||||
model = pool.get('ir.model').browse(cr, uid, model_id)
|
||||
self.create_log_line(cr, 1, log_id, model, lines[(model_id, resource_id)])
|
||||
self.create_log_line(cr, SUPERUSER_ID, log_id, model, lines[(model_id, resource_id)])
|
||||
return True
|
||||
|
||||
def check_rules(self, cr, uid, model, method):
|
||||
@@ -475,11 +476,11 @@ class audittrail_objects_proxy(object_proxy):
|
||||
"""
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
if 'audittrail.rule' in pool.models:
|
||||
model_ids = pool.get('ir.model').search(cr, 1, [('model', '=', model)])
|
||||
model_ids = pool.get('ir.model').search(cr, SUPERUSER_ID, [('model', '=', model)])
|
||||
model_id = model_ids and model_ids[0] or False
|
||||
if model_id:
|
||||
rule_ids = pool.get('audittrail.rule').search(cr, 1, [('object_id', '=', model_id), ('state', '=', 'subscribed')])
|
||||
for rule in pool.get('audittrail.rule').read(cr, 1, rule_ids, ['user_id','log_read','log_write','log_create','log_unlink','log_action','log_workflow']):
|
||||
rule_ids = pool.get('audittrail.rule').search(cr, SUPERUSER_ID, [('object_id', '=', model_id), ('state', '=', 'subscribed')])
|
||||
for rule in pool.get('audittrail.rule').read(cr, SUPERUSER_ID, rule_ids, ['user_id','log_read','log_write','log_create','log_unlink','log_action','log_workflow']):
|
||||
if len(rule['user_id']) == 0 or uid in rule['user_id']:
|
||||
if rule.get('log_'+method,0):
|
||||
return True
|
||||
|
||||
@@ -7,6 +7,7 @@ import werkzeug.utils
|
||||
import openerp.modules.registry
|
||||
import openerp.addons.web.controllers.main
|
||||
import openerp.addons.web.common.http as openerpweb
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,7 +19,7 @@ class OAuthController(openerpweb.Controller):
|
||||
registry = openerp.modules.registry.RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
providers = registry.get('auth.oauth.provider')
|
||||
l = providers.read(cr, 1, providers.search(cr, 1, [('enabled','=',True)]))
|
||||
l = providers.read(cr, SUPERUSER_ID, providers.search(cr, SUPERUSER_ID, [('enabled','=',True)]))
|
||||
return l
|
||||
|
||||
@openerpweb.httprequest
|
||||
@@ -30,7 +31,7 @@ class OAuthController(openerpweb.Controller):
|
||||
with registry.cursor() as cr:
|
||||
try:
|
||||
u = registry.get('res.users')
|
||||
credentials = u.auth_oauth(cr, 1, provider, kw)
|
||||
credentials = u.auth_oauth(cr, SUPERUSER_ID, provider, kw)
|
||||
cr.commit()
|
||||
return openerp.addons.web.controllers.main.login_and_redirect(req, *credentials)
|
||||
except AttributeError:
|
||||
|
||||
@@ -6,6 +6,7 @@ import simplejson
|
||||
|
||||
import openerp
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -63,7 +64,7 @@ class res_users(osv.Model):
|
||||
try:
|
||||
return super(res_users, self).check_credentials(cr, uid, password)
|
||||
except openerp.exceptions.AccessDenied:
|
||||
res = self.search(cr, 1, [('id','=',uid),('oauth_access_token','=',password)])
|
||||
res = self.search(cr, SUPERUSER_ID, [('id','=',uid),('oauth_access_token','=',password)])
|
||||
if not res:
|
||||
raise
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import logging
|
||||
import os
|
||||
import tempfile
|
||||
import urllib
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
import werkzeug.urls
|
||||
import werkzeug.exceptions
|
||||
@@ -176,7 +177,7 @@ class OpenIDController(openerpweb.Controller):
|
||||
with registry.cursor() as cr:
|
||||
Modules = registry.get('ir.module.module')
|
||||
|
||||
installed = Modules.search_count(cr, 1, ['&', ('name', '=', 'auth_openid'), ('state', '=', 'installed')]) == 1
|
||||
installed = Modules.search_count(cr, SUPERUSER_ID, ['&', ('name', '=', 'auth_openid'), ('state', '=', 'installed')]) == 1
|
||||
if installed:
|
||||
|
||||
Users = registry.get('res.users')
|
||||
@@ -196,13 +197,13 @@ class OpenIDController(openerpweb.Controller):
|
||||
|
||||
domain += [('openid_url', '=', openid_url), ('active', '=', True)]
|
||||
|
||||
ids = Users.search(cr, 1, domain)
|
||||
ids = Users.search(cr, SUPERUSER_ID, domain)
|
||||
assert len(ids) < 2
|
||||
if ids:
|
||||
user_id = ids[0]
|
||||
login = Users.browse(cr, 1, user_id).login
|
||||
login = Users.browse(cr, SUPERUSER_ID, user_id).login
|
||||
key = randomString(utils.KEY_LENGTH, '0123456789abcdef')
|
||||
Users.write(cr, 1, [user_id], {'openid_key': key})
|
||||
Users.write(cr, SUPERUSER_ID, [user_id], {'openid_key': key})
|
||||
# TODO fill empty fields with the ones from sreg/ax
|
||||
cr.commit()
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import urlparse
|
||||
|
||||
from openerp.tools import config
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
TWENTY_FOUR_HOURS = 24 * 60 * 60
|
||||
|
||||
@@ -76,9 +77,9 @@ class res_users(osv.osv):
|
||||
MailMessage.send(cr, uid, [msg_id], context=context)
|
||||
|
||||
def send_reset_password_request(self, cr, uid, email, context=None):
|
||||
ids = self.pool.get('res.users').search(cr, 1, [('user_email', '=', email)], context=context)
|
||||
ids = self.pool.get('res.users').search(cr, SUPERUSER_ID, [('user_email', '=', email)], context=context)
|
||||
if ids:
|
||||
self._auth_reset_password_send_email(cr, 1, email, 'reset_password_email', ids[0], context=context)
|
||||
self._auth_reset_password_send_email(cr, SUPERUSER_ID, email, 'reset_password_email', ids[0], context=context)
|
||||
return True
|
||||
#else:
|
||||
# _m, company_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'main_company')
|
||||
@@ -109,7 +110,7 @@ class auth_reset_password(osv.TransientModel):
|
||||
Users = self.pool.get('res.users')
|
||||
data = Users._auth_reset_password_check_token(cr, uid, values.get('token', ''))
|
||||
if data:
|
||||
Users.write(cr, 1, data['uid'], {'password': pw}, context=context)
|
||||
Users.write(cr, SUPERUSER_ID, data['uid'], {'password': pw}, context=context)
|
||||
else:
|
||||
raise osv.except_osv('Error', 'Invalid token')
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import werkzeug.urls
|
||||
from openerp.modules.registry import RegistryManager
|
||||
from openerp.addons.web.controllers.main import login_and_redirect
|
||||
import openerp.addons.web.common.http as openerpweb
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,7 +19,7 @@ class OpenIDController(openerpweb.Controller):
|
||||
with registry.cursor() as cr:
|
||||
try:
|
||||
Users = registry.get('res.users')
|
||||
credentials = Users.auth_signup(cr, 1, name, login, password)
|
||||
credentials = Users.auth_signup(cr, SUPERUSER_ID, name, login, password)
|
||||
cr.commit()
|
||||
return login_and_redirect(req, *credentials)
|
||||
except AttributeError:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import openerp
|
||||
from openerp.osv import osv
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
class res_users(osv.Model):
|
||||
_inherit = 'res.users'
|
||||
@@ -15,9 +16,9 @@ class res_users(osv.Model):
|
||||
#
|
||||
user_template_id = self.pool.get('ir.config_parameter').get_param(cr, uid, 'auth.signup_template_user_id', 0)
|
||||
if user_template_id:
|
||||
self.pool.get('res.users').copy(cr, 1, user_template_id, new_user, context=context)
|
||||
self.pool.get('res.users').copy(cr, SUPERUSER_ID, user_template_id, new_user, context=context)
|
||||
else:
|
||||
self.pool.get('res.users').create(cr, 1, new_user, context=context)
|
||||
self.pool.get('res.users').create(cr, SUPERUSER_ID, new_user, context=context)
|
||||
|
||||
def auth_signup(self, cr, uid, name, login, password, context=None):
|
||||
r = (cr.dbname, login, password)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Openerp sa (<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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import res_company
|
||||
import ir_translation
|
||||
import wizard
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'Automated Translations through Gengo API',
|
||||
'version': '0.1',
|
||||
'category': 'Tools',
|
||||
'description': """
|
||||
Automated Translations through Gengo API
|
||||
----------------------------------------
|
||||
This module will install passive scheduler job for automated translations
|
||||
using the Gengo API. To activate it, you must
|
||||
1) Configure your Gengo authentication parameters under `Settings > Companies > Gengo Parameters`
|
||||
2) Launch the wizard under `Settings > Application Terms > Gengo: Manual Request of Translation` and follow the wizard.
|
||||
|
||||
This wizard will activate the CRON job and the Scheduler and will start the automatic translation via Gengo Services for all the terms where you requested it.
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['base'],
|
||||
'init_xml': ['gengo_sync_schedular_data.xml'],
|
||||
'update_xml': [
|
||||
'ir_translation.xml',
|
||||
'res_company_view.xml',
|
||||
'wizard/base_gengo_translations_view.xml',
|
||||
],
|
||||
'demo_xml': [],
|
||||
'test': [],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!--Scheduler sync Receive Request-->
|
||||
<record id="gengo_sync_receive_request_scheduler" model="ir.cron">
|
||||
<field name="name" >Gengo Sync Translation (Response)</field>
|
||||
<field eval="False" name="active"/>
|
||||
<field name="interval_number">20</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="'base.gengo.translations'" name="model"></field>
|
||||
<field eval="'_sync_response'" name="function"/>
|
||||
<field eval="'(20,)'" name="args"/>
|
||||
</record>
|
||||
|
||||
<!--Scheduler Sync Send Request-->
|
||||
<record id="gengo_sync_send_request_scheduler" model="ir.cron">
|
||||
<field name="name" >Gengo Sync Translation (Request)</field>
|
||||
<field eval="False" name="active"/>
|
||||
<field name="interval_number">20</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="'base.gengo.translations'" name="model"></field>
|
||||
<field eval="'_sync_request'" name="function"/>
|
||||
<field eval="'(20,)'" name="args"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,88 @@
|
||||
# -*- 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
LANG_CODE_MAPPING = {
|
||||
'ar_SA': ('ar', 'Arabic'),
|
||||
'id_ID': ('id', 'Indonesian'),
|
||||
'nl_NL': ('nl', 'Dutch'),
|
||||
'fr_CA': ('fr-ca', 'French (Canada)'),
|
||||
'pl_PL': ('pl', 'Polish'),
|
||||
'zh_TW': ('zh-tw', 'Chinese (Traditional)'),
|
||||
'sv_SE': ('sv', 'Swedish'),
|
||||
'ko_KR': ('ko', 'Korean'),
|
||||
'pt_PT': ('pt', 'Portuguese (Europe)'),
|
||||
'en_US': ('en', 'English'),
|
||||
'ja_JP': ('ja', 'Japanese'),
|
||||
'es_ES': ('es', 'Spanish (Spain)'),
|
||||
'zh_CN': ('zh', 'Chinese (Simplified)'),
|
||||
'de_DE': ('de', 'German'),
|
||||
'fr_FR': ('fr', 'French'),
|
||||
'fr_BE': ('fr', 'French'),
|
||||
'ru_RU': ('ru', 'Russian'),
|
||||
'it_IT': ('it', 'Italian'),
|
||||
'pt_BR': ('pt-br', 'Portuguese (Brazil)')
|
||||
}
|
||||
|
||||
class ir_translation(osv.Model):
|
||||
_name = "ir.translation"
|
||||
_inherit = "ir.translation"
|
||||
_columns = {
|
||||
'gengo_comment': fields.text("Comments & Activity Linked to Gengo"),
|
||||
'job_id': fields.char('Gengo Job ID', size=32),
|
||||
"gengo_translation": fields.selection([('machine', 'Translation By Machine'),
|
||||
('standard', 'Standard'),
|
||||
('pro', 'Pro'),
|
||||
('ultra', 'Ultra')], "Gengo Translation Service Level", help='You can select here the service level you want for an automatic translation using Gengo.'),
|
||||
}
|
||||
|
||||
def _get_all_supported_languages(self, cr, uid, context=None):
|
||||
flag, gengo = self.pool.get('base.gengo.translations').gengo_authentication(cr, uid, context=context)
|
||||
if not flag:
|
||||
raise osv.except_osv(_('Gengo Authentication Error'), gengo)
|
||||
supported_langs = {}
|
||||
lang_pair = gengo.getServiceLanguagePairs(lc_src='en')
|
||||
if lang_pair['opstat'] == 'ok':
|
||||
for g_lang in lang_pair['response']:
|
||||
if g_lang['lc_tgt'] not in supported_langs:
|
||||
supported_langs[g_lang['lc_tgt']] = []
|
||||
supported_langs[g_lang['lc_tgt']] += [g_lang['tier']]
|
||||
return supported_langs
|
||||
|
||||
def _get_gengo_corresponding_language(cr, lang):
|
||||
return lang in LANG_CODE_MAPPING and LANG_CODE_MAPPING[lang][0] or lang
|
||||
|
||||
def _check_lang_support(self, cr, uid, ids, context=None):
|
||||
for term in self.browse(cr, uid, ids, context=context):
|
||||
if term.gengo_translation:
|
||||
supported_langs = self._get_all_supported_languages(cr, uid, context=context)
|
||||
if supported_langs:
|
||||
tier = "nonprofit" if term.gengo_translation == 'machine' else term.gengo_translation
|
||||
language = self._get_gengo_corresponding_language(term.lang)
|
||||
if tier not in supported_langs.get(language,[]):
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_lang_support, 'The Gengo translation service selected is not supported for this language.', ['gengo_translation'])
|
||||
]
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_translation_search" model="ir.ui.view">
|
||||
<field name="name">Translations</field>
|
||||
<field name="model">ir.translation</field>
|
||||
<field name="inherit_id" ref="base.view_translation_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Translations">
|
||||
<filter string="To Approve In Gengo" domain="[('state','=','inprogress'),('gengo_translation','=',True)]"></filter>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ir.translation form view -->
|
||||
<record model="ir.ui.view" id="view_ir_translation_inherit_base_gengo_form">
|
||||
<field name="name">ir.translation.form.inherit</field>
|
||||
<field name="inherit_id" ref="base.view_translation_form"/>
|
||||
<field name="model">ir.translation</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form[@string='Translations']/sheet" position="inside">
|
||||
<group string="Gengo Translation Service" col="4" colspan="4">
|
||||
<field name="gengo_translation" />
|
||||
<label string="Note: If the translation state is 'In Progress', it means that the translation has to be approved to be uploaded in this system. You are supposed to do that directly by using your Gengo Account"/>
|
||||
<field name="gengo_comment" nolabel="1" placeholder="Gengo Comments & Activity..." colspan="4"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,37 @@
|
||||
# -*- 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 osv import fields, osv
|
||||
|
||||
|
||||
class res_company(osv.Model):
|
||||
_name = "res.company"
|
||||
_inherit = "res.company"
|
||||
_columns = {
|
||||
"gengo_private_key": fields.text("Gengo Private Key"),
|
||||
"gengo_public_key": fields.text("Gengo Public Key"),
|
||||
"gengo_comment": fields.text("Comments", help="This comment will be automatically be enclosed in each an every request sent to Gengo"),
|
||||
"gengo_auto_approve": fields.boolean("Auto Approve Translation ?", help="Jobs are Automatically Approved by Gengo."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
"gengo_auto_approve": True,
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- res.company form view -->
|
||||
<record model="ir.ui.view" id="view_company_inherit_base_gengo_form">
|
||||
<field name="name">res.company.form.inherit</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="model">res.company</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<page string="Gengo Parameters">
|
||||
<group col="2">
|
||||
<group col="1" string="Public Key">
|
||||
<field name="gengo_public_key" nolabel="1" placeholder="Add Gengo login Public Key..."/>
|
||||
</group>
|
||||
<group col="1" string="Private Key">
|
||||
<field name="gengo_private_key" password="True" nolabel="1" placeholder="Add Gengo login Private Key..."/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="4">
|
||||
<field name="gengo_auto_approve"/>
|
||||
</group>
|
||||
<group string="Comments for Translator" col="1">
|
||||
<field name="gengo_comment" nolabel="1" placeholder="Add your comments here for translator...."/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import base_gengo_translations
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,253 @@
|
||||
# -*- 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 osv import osv, fields
|
||||
from tools.translate import _
|
||||
import re
|
||||
try:
|
||||
from mygengo import MyGengo
|
||||
except ImportError:
|
||||
raise osv.except_osv(_('Gengo ImportError'), _('Please install mygengo lib from http://pypi.python.org/pypi/mygengo'))
|
||||
|
||||
import logging
|
||||
import tools
|
||||
import time
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
GENGO_DEFAULT_LIMIT = 20
|
||||
|
||||
DEFAULT_CRON_VALS = {
|
||||
'active': True,
|
||||
'interval_number': 20,
|
||||
'interval_type': 'minutes',
|
||||
'model': "'base.gengo.translations'",
|
||||
'args': "'(%s,)'" % (str(GENGO_DEFAULT_LIMIT)),
|
||||
}
|
||||
|
||||
class base_gengo_translations(osv.osv_memory):
|
||||
|
||||
_name = 'base.gengo.translations'
|
||||
_columns = {
|
||||
'restart_send_job': fields.boolean("Restart Sending Job"),
|
||||
'lang_id': fields.many2one('res.lang', 'Language', help="Leave empty if you don't want to restrict the request to a single language"),
|
||||
}
|
||||
|
||||
def gengo_authentication(self, cr, uid, context=None):
|
||||
'''
|
||||
This method tries to open a connection with Gengo. For that, it uses the Public and Private
|
||||
keys that are linked to the company (given by Gengo on subscription). It returns a tuple with
|
||||
* as first element: a boolean depicting if the authentication was a success or not
|
||||
* as second element: the connection, if it was a success, or the error message returned by
|
||||
Gengo when the connection failed.
|
||||
This error message can either be displayed in the server logs (if the authentication was called
|
||||
by the cron) or in a dialog box (if requested by the user), thus it's important to return it
|
||||
translated.
|
||||
'''
|
||||
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
if not user.company_id.gengo_public_key or not user.company_id.gengo_private_key:
|
||||
return (False, _("Invalid Gengo configuration. Gengo authentication `Public Key` or `Private Key` is missing. Complete Gengo authentication parameters under `Settings > Companies > Gengo Parameters`."))
|
||||
try:
|
||||
gengo = MyGengo(
|
||||
public_key=user.company_id.gengo_public_key.encode('ascii'),
|
||||
private_key=user.company_id.gengo_private_key.encode('ascii'),
|
||||
sandbox=True,
|
||||
)
|
||||
gengo.getAccountStats()
|
||||
|
||||
return (True, gengo)
|
||||
except Exception, e:
|
||||
return (False, _("Gengo Connection Error\n%s") %e)
|
||||
|
||||
def do_check_schedular(self, cr, uid, xml_id, name, fn, context=None):
|
||||
"""
|
||||
This function is used to reset a cron to its default values, or to recreate it if it was deleted.
|
||||
"""
|
||||
cron_pool = self.pool.get('ir.cron')
|
||||
cron_vals = DEFAULT_CRON_VALS.copy()
|
||||
cron_vals.update({'name': name, "function": fn})
|
||||
try:
|
||||
res = []
|
||||
model, res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base_gengo', xml_id)
|
||||
cron_pool.write(cr, uid, [res], cron_vals, context=context)
|
||||
except:
|
||||
#the cron job was not found, probably deleted previously, so we create it again using default values
|
||||
cron_vals.update({'numbercall': -1})
|
||||
return cron_pool.create(cr, uid, cron_vals, context=context)
|
||||
|
||||
def act_update(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
Function called by the wizard.
|
||||
'''
|
||||
if context == None:
|
||||
context = {}
|
||||
|
||||
flag, gengo = self.gengo_authentication(cr, uid, context=context)
|
||||
if not flag:
|
||||
raise osv.except_osv(_('Gengo Authentication Error'), gengo)
|
||||
for wizard in self.browse(cr, uid, ids, context=context):
|
||||
supported_langs = self.pool.get('ir.translation')._get_all_supported_languages(cr, uid, context=context)
|
||||
language = self.pool.get('ir.translation')._get_gengo_corresponding_language(wizard.lang_id.code)
|
||||
if language not in supported_langs:
|
||||
raise osv.except_osv(_("Warning"), _('This language is not supported by the Gengo translation services.'))
|
||||
|
||||
#send immediately a new request for the selected language (if any)
|
||||
ctx = context.copy()
|
||||
ctx['gengo_language'] = wizard.lang_id.id
|
||||
self._sync_request(cr, uid, limit=GENGO_DEFAULT_LIMIT, context=ctx)
|
||||
self._sync_response( cr, uid, limit=GENGO_DEFAULT_LIMIT, context=ctx)
|
||||
#check the cron jobs and eventually restart/recreate them
|
||||
if wizard.restart_send_job:
|
||||
self.do_check_schedular(cr, uid, 'gengo_sync_send_request_scheduler', _('Gengo Sync Translation (Request)'), '_sync_request', context=context)
|
||||
self.do_check_schedular(cr, uid, 'gengo_sync_receive_request_scheduler', _('Gengo Sync Translation (Response)'), '_sync_response', context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def _sync_response(self, cr, uid, limit=GENGO_DEFAULT_LIMIT, context=None):
|
||||
"""
|
||||
This method will be called by cron services to get translations from
|
||||
Gengo. It will read translated terms and comments from Gengo and will
|
||||
update respective ir.translation in openerp.
|
||||
"""
|
||||
translation_pool = self.pool.get('ir.translation')
|
||||
flag, gengo = self.gengo_authentication(cr, uid, context=context)
|
||||
if not flag:
|
||||
_logger.warning("%s", gengo)
|
||||
else:
|
||||
translation_id = translation_pool.search(cr, uid, [('state', '=', 'inprogress'), ('gengo_translation', 'in', ('machine','standard','pro','ultra'))], limit=limit, context=context)
|
||||
for term in translation_pool.browse(cr, uid, translation_id, context=context):
|
||||
up_term = up_comment = 0
|
||||
if term.job_id:
|
||||
vals={}
|
||||
job_response = gengo.getTranslationJob(id=term.job_id)
|
||||
if job_response['opstat'] != 'ok':
|
||||
_logger.warning("Invalid Response! Skipping translation Terms with `id` %s." % (term.job_id))
|
||||
continue
|
||||
if job_response['response']['job']['status'] == 'approved':
|
||||
vals.update({'state': 'translated',
|
||||
'value': job_response['response']['job']['body_tgt']})
|
||||
up_term += 1
|
||||
job_comment = gengo.getTranslationJobComments(id=term.job_id)
|
||||
if job_comment['opstat']=='ok':
|
||||
gengo_comments=""
|
||||
for comment in job_comment['response']['thread']:
|
||||
gengo_comments += _('%s\n\n--\n Commented on %s by %s.') % (comment['body'], time.ctime(comment['ctime']), comment['author'])
|
||||
vals.update({'gengo_comment': gengo_comments})
|
||||
up_comment += 1
|
||||
if vals:
|
||||
translation_pool.write(cr, uid, term.id, vals)
|
||||
_logger.info("Successfully Updated `%d` terms and %d Comments." % (up_term, up_comment ))
|
||||
else:
|
||||
_logger.warning("%s", 'Cannot retrieve the Gengo job ID for translation %s: %s' % (term.id, term.src))
|
||||
return True
|
||||
|
||||
def _update_terms(self, cr, uid, response, context=None):
|
||||
"""
|
||||
Update the terms after their translation were requested to Gengo
|
||||
"""
|
||||
translation_pool = self.pool.get('ir.translation')
|
||||
for jobs in response['jobs']:
|
||||
for t_id, res in jobs.items():
|
||||
vals = {}
|
||||
t_id = int(t_id)
|
||||
tier = translation_pool.read(cr, uid, [t_id], ['gengo_translation'], context=context)[0]['gengo_translation']
|
||||
if tier == "machine":
|
||||
vals.update({'value': res['body_tgt'], 'state': 'translated'})
|
||||
else:
|
||||
vals.update({'job_id': res['job_id'], 'state': 'inprogress'})
|
||||
translation_pool.write(cr, uid, [t_id], vals, context=context)
|
||||
return
|
||||
|
||||
def pack_jobs_request(self, cr, uid, term_ids, context=None):
|
||||
''' prepare the terms that will be requested to gengo and returns them in a dictionary with following format
|
||||
{'jobs': {
|
||||
'term1.id': {...}
|
||||
'term2.id': {...}
|
||||
}
|
||||
}'''
|
||||
|
||||
translation_pool = self.pool.get('ir.translation')
|
||||
jobs = {}
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
auto_approve = 1 if user.company_id.gengo_auto_approve else 0
|
||||
for term in translation_pool.browse(cr, uid, term_ids, context=context):
|
||||
if re.search(r"\w", term.src or ""):
|
||||
jobs[term.id] = {'type': 'text',
|
||||
'slug': 'single::English to ' + term.lang,
|
||||
'tier': tools.ustr(term.gengo_translation),
|
||||
'body_src': term.src,
|
||||
'lc_src': 'en',
|
||||
'lc_tgt': translation_pool._get_gengo_corresponding_language(term.lang),
|
||||
'auto_approve': auto_approve,
|
||||
'comment': user.company_id.gengo_comment,
|
||||
}
|
||||
return {'jobs': jobs}
|
||||
|
||||
|
||||
def _send_translation_terms(self, cr, uid, term_ids, context=None):
|
||||
"""
|
||||
Send a request to Gengo with all the term_ids in a different job, get the response and update the terms in
|
||||
database accordingly.
|
||||
"""
|
||||
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
flag, gengo = self.gengo_authentication(cr, uid, context=context)
|
||||
if flag:
|
||||
request = self.pack_jobs_request(cr, uid, term_ids, context=context)
|
||||
if request['jobs']:
|
||||
result = gengo.postTranslationJobs(jobs=request)
|
||||
if result['opstat'] == 'ok':
|
||||
self._update_terms(cr, uid, result['response'], context=context)
|
||||
else:
|
||||
_logger.error(gengo)
|
||||
return True
|
||||
|
||||
def _sync_request(self, cr, uid, limit=GENGO_DEFAULT_LIMIT, context=None):
|
||||
"""
|
||||
This scheduler will send a job request to the gengo , which terms are
|
||||
waiing to be translated and for which gengo_translation is enabled.
|
||||
|
||||
A special key 'gengo_language' can be passed in the context in order to
|
||||
request only translations of that language only. Its value is the language
|
||||
ID in openerp.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
language_pool = self.pool.get('res.lang')
|
||||
translation_pool = self.pool.get('ir.translation')
|
||||
try:
|
||||
#by default, the request will be made for all terms that needs it, whatever the language
|
||||
lang_ids = language_pool.search(cr, uid, [], context=context)
|
||||
if context.get('gengo_language'):
|
||||
#but if this specific key is given, then we restrict the request on terms of this language only
|
||||
lang_ids = [context.get('gengo_language')]
|
||||
langs = [lang.code for lang in language_pool.browse(cr, uid, lang_ids, context=context)]
|
||||
#search for the n first terms to translate
|
||||
term_ids = translation_pool.search(cr, uid, [('state', '=', 'to_translate'), ('gengo_translation', 'in', ('machine','standard','pro','ultra')), ('lang', 'in', langs)], limit=limit, context=context)
|
||||
if term_ids:
|
||||
self._send_translation_terms(cr, uid, term_ids, context=context)
|
||||
_logger.info("%s Translation terms have been posted to Gengo successfully", len(term_ids))
|
||||
else:
|
||||
_logger.info('No Translation terms to process.')
|
||||
except Exception, e:
|
||||
_logger.error("%s", e)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="base_gengo_translation_wizard_from">
|
||||
<field name="name">base.gengo.translation.form</field>
|
||||
<field name="model">base.gengo.translations</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Gengo Request Form" version="7.0">
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="lang_id" required="1"/>
|
||||
<field name="restart_send_job"/>
|
||||
</group>
|
||||
<group>
|
||||
<label colspan="2" string="Leave empty for requesting all the terms to Gengo that needs it, regardless of their language"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="act_update" string="Send" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button name="act_cancel" special="cancel" string="Cancel" type="object" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_wizard_base_gengo_translations" model="ir.actions.act_window">
|
||||
<field name="name">Gengo: Manual Request of Translation</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">base.gengo.translations</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
<menuitem action="action_wizard_base_gengo_translations" id="menu_action_wizard_base_gengo_translations" parent="base.menu_translation_app"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -595,18 +595,9 @@ class crm_lead(base_stage, osv.osv):
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
if lead.state in ('done', 'cancel'):
|
||||
continue
|
||||
|
||||
vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
|
||||
self.write(cr, uid, [lead.id], vals, context=context)
|
||||
|
||||
self.convert_opportunity_send_note(cr, uid, lead, context=context)
|
||||
#TOCHECK: why need to change partner details in all messages of lead ?
|
||||
# TDE FIXME: I propose to delete this, makes no sense to update partner of an already-send email ...
|
||||
# if lead.partner_id:
|
||||
# msg_ids = [x.id for x in lead.message_ids]
|
||||
# mail_message.write(cr, uid, msg_ids, {
|
||||
# 'partner_id': lead.partner_id.id
|
||||
# }, context=context)
|
||||
|
||||
if user_ids or section_id:
|
||||
self.allocate_salesman(cr, uid, ids, user_ids, section_id, context=context)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
from osv import osv, fields
|
||||
import tools
|
||||
import pooler
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
class decimal_precision(osv.osv):
|
||||
_name = 'decimal.precision'
|
||||
@@ -56,7 +57,7 @@ decimal_precision()
|
||||
|
||||
def get_precision(application):
|
||||
def change_digit(cr):
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, 1, application)
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, SUPERUSER_ID, application)
|
||||
return (16, res)
|
||||
return change_digit
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ from tools.safe_eval import safe_eval as eval
|
||||
import time
|
||||
import urllib
|
||||
import uuid
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
try:
|
||||
from tools.dict_tools import dict_filter
|
||||
except ImportError:
|
||||
@@ -233,7 +235,7 @@ class node_acl_mixin(object):
|
||||
|
||||
if props_to_delete:
|
||||
# explicitly delete, as admin, any of the ids we have identified.
|
||||
propobj.unlink(cr, 1, props_to_delete)
|
||||
propobj.unlink(cr, SUPERUSER_ID, props_to_delete)
|
||||
|
||||
if lock_data.get('unlock_mode', False):
|
||||
return lock_found and True
|
||||
|
||||
@@ -42,6 +42,7 @@ from tools import config
|
||||
from xmlrpclib import Transport, ProtocolError
|
||||
import StringIO
|
||||
import base64
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -361,7 +362,7 @@ class DAVClient(object):
|
||||
to break if "base_crypt" is used.
|
||||
"""
|
||||
ruob = obj.pool.get('res.users')
|
||||
res = ruob.read(cr, 1, [uid,], ['login', 'password'])
|
||||
res = ruob.read(cr, SUPERUSER_ID, [uid,], ['login', 'password'])
|
||||
assert res, "uid %s not found" % uid
|
||||
self.user = res[0]['login']
|
||||
self.passwd = res[0]['password']
|
||||
|
||||
@@ -29,7 +29,7 @@ from osv import fields
|
||||
import tools
|
||||
from tools.translate import _
|
||||
from tools.html_sanitize import html_sanitize
|
||||
from tools import html2plaintext
|
||||
from tools import append_content_to_html
|
||||
from urllib import quote as quote
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -40,10 +40,8 @@ except ImportError:
|
||||
|
||||
class email_template(osv.osv):
|
||||
"Templates for sending email"
|
||||
_inherit = 'mail.mail'
|
||||
_name = "email.template"
|
||||
_description = 'Email Templates'
|
||||
_rec_name = 'name' # override mail.message's behavior
|
||||
|
||||
def render_template(self, cr, uid, template, model, res_id, context=None):
|
||||
"""Render the given template text, replace mako expressions ``${expr}``
|
||||
@@ -103,57 +101,44 @@ class email_template(osv.osv):
|
||||
mod_name = self.pool.get('ir.model').browse(cr, uid, model_id, context).model
|
||||
return {'value':{'model': mod_name}}
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
""" Override name_get of mail.message: return directly the template
|
||||
name, and not the generated name from mail.message.common."""
|
||||
return [(record.id, record.name) for record in self.browse(cr, uid, ids, context=context)]
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=250),
|
||||
'model_id': fields.many2one('ir.model', 'Related document model'),
|
||||
'lang': fields.char('Language Selection', size=250,
|
||||
'name': fields.char('Name'),
|
||||
'model_id': fields.many2one('ir.model', 'Applies to', help="The kind of document with with this template can be used"),
|
||||
'model': fields.related('model_id', 'model', type='char', string='Related Document Model',
|
||||
size=128, select=True, store=True, readonly=True),
|
||||
'lang': fields.char('Language',
|
||||
help="Optional translation language (ISO code) to select when sending out an email. "
|
||||
"If not set, the english version will be used. "
|
||||
"This should usually be a placeholder expression "
|
||||
"that provides the appropriate language code, e.g. "
|
||||
"${object.partner_id.lang.code}."),
|
||||
"${object.partner_id.lang.code}.",
|
||||
placeholder="${object.partner_id.lang.code}"),
|
||||
'user_signature': fields.boolean('Add Signature',
|
||||
help="If checked, the user's signature will be appended to the text version "
|
||||
"of the message"),
|
||||
'report_name': fields.char('Report Filename', size=200, translate=True,
|
||||
help="Name to use for the generated report file (may contain placeholders)\n"
|
||||
"The extension can be omitted and will then come from the report type."),
|
||||
'report_template':fields.many2one('ir.actions.report.xml', 'Optional report to print and attach'),
|
||||
'ref_ir_act_window':fields.many2one('ir.actions.act_window', 'Sidebar action', readonly=True,
|
||||
help="Sidebar action to make this template available on records "
|
||||
"of the related document model"),
|
||||
'ref_ir_value':fields.many2one('ir.values', 'Sidebar Button', readonly=True,
|
||||
help="Sidebar button to open the sidebar action"),
|
||||
'track_campaign_item': fields.boolean('Resource Tracking',
|
||||
help="Enable this is you wish to include a special tracking marker "
|
||||
"in outgoing emails so you can identify replies and link "
|
||||
"them back to the corresponding resource record. "
|
||||
"This is useful for CRM leads for example"),
|
||||
|
||||
# Overridden mail.message.common fields for technical reasons:
|
||||
'model': fields.related('model_id', 'model', type='char', string='Related Document Model',
|
||||
size=128, select=True, store=True, readonly=True),
|
||||
# we need a separate m2m table to avoid ID collisions with the original mail.message entries
|
||||
#'attachment_ids': fields.many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id',
|
||||
# 'attachment_id', 'Files to attach',
|
||||
# help="You may attach files to this template, to be added to all "
|
||||
# "emails created from this template"),
|
||||
|
||||
# Overridden mail.message.common fields to make tooltips more appropriate:
|
||||
'subject': fields.char('Subject', translate=True, help="Subject (placeholders may be used here)",),
|
||||
'email_from': fields.char('From', size=128, help="Sender address (placeholders may be used here)"),
|
||||
'email_to': fields.char('To', size=256, help="Comma-separated recipient addresses (placeholders may be used here)"),
|
||||
'email_cc': fields.char('Cc', size=256, help="Carbon copy recipients (placeholders may be used here)"),
|
||||
'reply_to': fields.char('Reply-To', size=250, help="Preferred response address (placeholders may be used here)"),
|
||||
'email_from': fields.char('From', help="Sender address (placeholders may be used here)"),
|
||||
'email_to': fields.char('To', help="Comma-separated recipient addresses (placeholders may be used here)"),
|
||||
'email_cc': fields.char('Cc', help="Carbon copy recipients (placeholders may be used here)"),
|
||||
'reply_to': fields.char('Reply-To', help="Preferred response address (placeholders may be used here)"),
|
||||
'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False,
|
||||
help="Optional preferred server for outgoing mails. If not set, the highest "
|
||||
"priority one will be used."),
|
||||
'body_html': fields.text('Rich-text Contents', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
|
||||
'body_html': fields.text('Body', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
|
||||
'report_name': fields.char('Report Filename', translate=True,
|
||||
help="Name to use for the generated report file (may contain placeholders)\n"
|
||||
"The extension can be omitted and will then come from the report type."),
|
||||
'report_template': fields.many2one('ir.actions.report.xml', 'Optional report to print and attach'),
|
||||
'ref_ir_act_window': fields.many2one('ir.actions.act_window', 'Sidebar action', readonly=True,
|
||||
help="Sidebar action to make this template available on records "
|
||||
"of the related document model"),
|
||||
'ref_ir_value': fields.many2one('ir.values', 'Sidebar Button', readonly=True,
|
||||
help="Sidebar button to open the sidebar action"),
|
||||
'attachment_ids': fields.many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id',
|
||||
'attachment_id', 'Attachments',
|
||||
help="You may attach files to this template, to be added to all "
|
||||
"emails created from this template"),
|
||||
'auto_delete': fields.boolean('Auto Delete', help="Permanently delete this email after sending it, to save space"),
|
||||
|
||||
# Fake fields used to implement the placeholder assistant
|
||||
'model_object_field': fields.many2one('ir.model.fields', string="Field",
|
||||
@@ -167,12 +152,8 @@ class email_template(osv.osv):
|
||||
help="When a relationship field is selected as first field, "
|
||||
"this field lets you select the target field within the "
|
||||
"destination document model (sub-model)."),
|
||||
'null_value': fields.char('Null value', help="Optional value to use if the target field is empty", size=128),
|
||||
'copyvalue': fields.char('Expression', size=256, help="Final placeholder expression, to be copy-pasted in the desired template field."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'track_campaign_item': True
|
||||
'null_value': fields.char('Default Value', help="Optional value to use if the target field is empty"),
|
||||
'copyvalue': fields.char('Placeholder Expression', help="Final placeholder expression, to be copy-pasted in the desired template field."),
|
||||
}
|
||||
|
||||
def create_action(self, cr, uid, ids, context=None):
|
||||
@@ -217,7 +198,7 @@ class email_template(osv.osv):
|
||||
if template.ref_ir_value:
|
||||
ir_values_obj = self.pool.get('ir.values')
|
||||
ir_values_obj.unlink(cr, uid, template.ref_ir_value.id, context)
|
||||
except:
|
||||
except Exception:
|
||||
raise osv.except_osv(_("Warning"), _("Deletion of the action record failed."))
|
||||
return True
|
||||
|
||||
@@ -289,32 +270,14 @@ class email_template(osv.osv):
|
||||
:param res_id: id of the record to use for rendering the template (model
|
||||
is taken from template definition)
|
||||
:returns: a dict containing all relevant fields for creating a new
|
||||
mail.message entry, with the addition one additional
|
||||
special key ``attachments`` containing a list of
|
||||
mail.mail entry, with one extra key ``attachments``, in the
|
||||
format expected by :py:meth:`mail_thread.message_post`.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
values = {
|
||||
'subject': False,
|
||||
'body_html': False,
|
||||
'email_from': False,
|
||||
'email_to': False,
|
||||
'email_cc': False,
|
||||
'reply_to': False,
|
||||
'auto_delete': False,
|
||||
'model': False,
|
||||
'res_id': False,
|
||||
'mail_server_id': False,
|
||||
'attachments': False,
|
||||
'attachment_ids': False,
|
||||
'message_id': False,
|
||||
'state': 'outgoing',
|
||||
}
|
||||
if not template_id:
|
||||
return values
|
||||
|
||||
report_xml_pool = self.pool.get('ir.actions.report.xml')
|
||||
template = self.get_email_template(cr, uid, template_id, res_id, context)
|
||||
values = {'model': template.model_id.model}
|
||||
|
||||
for field in ['subject', 'body_html', 'email_from',
|
||||
'email_to', 'email_cc', 'reply_to']:
|
||||
@@ -322,21 +285,20 @@ class email_template(osv.osv):
|
||||
template.model, res_id, context=context) \
|
||||
or False
|
||||
|
||||
if values['body_html']:
|
||||
values['body'] = html_sanitize(values['body_html'])
|
||||
values['body_text'] = html2plaintext(values['body_html'])
|
||||
|
||||
if template.user_signature:
|
||||
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
|
||||
values['body'] += '\n\n' + signature
|
||||
values['body_html'] = append_content_to_html(values['body_html'], signature)
|
||||
|
||||
if values['body_html']:
|
||||
values['body'] = html_sanitize(values['body_html'])
|
||||
|
||||
values.update(mail_server_id = template.mail_server_id.id or False,
|
||||
auto_delete = template.auto_delete,
|
||||
model=template.model,
|
||||
res_id=res_id or False)
|
||||
|
||||
attachments = {}
|
||||
# Add report as a Document
|
||||
attachments = []
|
||||
# Add report in attachments
|
||||
if template.report_template:
|
||||
report_name = self.render_template(cr, uid, template.report_name, template.model, res_id, context=context)
|
||||
report_service = 'report.' + report_xml_pool.browse(cr, uid, template.report_template.id, context).report_name
|
||||
@@ -352,12 +314,11 @@ class email_template(osv.osv):
|
||||
ext = "." + format
|
||||
if not report_name.endswith(ext):
|
||||
report_name += ext
|
||||
attachments[report_name] = result
|
||||
attachments.append(report_name, result)
|
||||
|
||||
# Add document attachments
|
||||
# Add template attachments
|
||||
for attach in template.attachment_ids:
|
||||
# keep the bytes as fetched from the db, base64 encoded
|
||||
attachments[attach.datas_fname] = attach.datas
|
||||
attachments.append(attach.datas_fname, attach.datas)
|
||||
|
||||
values['attachments'] = attachments
|
||||
return values
|
||||
|
||||
@@ -1,95 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="email_template_form">
|
||||
<field name="name">email.template.form</field>
|
||||
<field name="model">email.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Templates" version="7.0">
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name" required="1"/>
|
||||
<field name="model_id" required="1" on_change="onchange_model_id(model_id)"/>
|
||||
<field name="model" invisible="1"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Email Details">
|
||||
<group>
|
||||
<field name="email_from" required="1"/>
|
||||
<field name="email_to" required="1"/>
|
||||
<field name="email_cc"/>
|
||||
<field name="reply_to"/>
|
||||
<field name="subject" required="1"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Body (HTML)">
|
||||
<field name="body_html" colspan="4" width="250" height="250" nolabel="1"/>
|
||||
<label string="Note: This is Raw HTML." colspan="4"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<field name="user_signature"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Dynamic Values Builder">
|
||||
<group>
|
||||
<field name="model_object_field"
|
||||
domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]"
|
||||
on_change="onchange_sub_model_object_value_field(model_object_field)"/>
|
||||
<field name="sub_object" readonly="1"/>
|
||||
<field name="sub_model_object_field"
|
||||
domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]"
|
||||
attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}"
|
||||
on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
|
||||
<field name="null_value" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)"/>
|
||||
<field name="copyvalue"/>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/><h1><field name="name" required="1"/></h1>
|
||||
<h3><label for="model_id"/><field name="model_id" required="1" on_change="onchange_model_id(model_id)" class="oe_inline"/></h3>
|
||||
<field name="model" invisible="1"/>
|
||||
</div>
|
||||
<div class="oe_right oe_button_box" name="buttons">
|
||||
<field name="ref_ir_act_window" invisible="1"/>
|
||||
<button name="create_action" string="Add context action" type="object"
|
||||
attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
|
||||
help="Display an option on related documents to open a composition wizard with this template"/>
|
||||
<button name="unlink_action" string="Remove context action" type="object"
|
||||
attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
|
||||
help="Remove the contextual action to use this template on related documents"/>
|
||||
<button name="%(wizard_email_template_preview)d" string="Preview"
|
||||
type="action" target="new"
|
||||
context="{'template_id':active_id}"/>
|
||||
</div>
|
||||
<notebook>
|
||||
<page string="Email Details">
|
||||
<group>
|
||||
<group string="Addressing">
|
||||
<field name="email_from" required="1"/>
|
||||
<field name="email_to" required="1"/>
|
||||
<field name="email_cc"/>
|
||||
<field name="reply_to"/>
|
||||
<field name="user_signature"/>
|
||||
</group>
|
||||
<group string="Dynamic Value Builder" class="oe_edit_only">
|
||||
<field name="model_object_field" domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]" on_change="onchange_sub_model_object_value_field(model_object_field)"/>
|
||||
<field name="sub_object" readonly="1"/>
|
||||
<field name="sub_model_object_field" domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]" attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
|
||||
<field name="null_value" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)"/>
|
||||
<field name="copyvalue"/>
|
||||
</group>
|
||||
<group string="Contents" colspan="2">
|
||||
<field name="subject" required="1"/>
|
||||
<field name="body_html" width="250" height="450" nolabel="1" colspan="2" placeholder="Email contents (in raw HTML format)"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
<button name="%(wizard_email_template_preview)d" string="Preview Template"
|
||||
type="action" colspan="4" target="new" icon="gtk-zoom-fit" context="{'template_id':active_id}"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Advanced">
|
||||
<group colspan="2" col="2">
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Sidebar Button" colspan="2"/>
|
||||
<button name="create_action" string="Add sidebar button" type="object" icon="gtk-execute"
|
||||
colspan="2" attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
|
||||
help="Display a button in the sidebar of related documents to open a composition wizard with this template"
|
||||
/>
|
||||
<field name="ref_ir_act_window" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
|
||||
<field name="ref_ir_value" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
|
||||
<button name="unlink_action" string="Remove sidebar button" type="object" icon="gtk-delete"
|
||||
colspan="2" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
|
||||
help="Remove the sidebar button currently displayed on related documents"
|
||||
/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Advanced Options" colspan="2"/>
|
||||
<field name="mail_server_id"/>
|
||||
<field name="track_campaign_item"/>
|
||||
<field name="message_id"/>
|
||||
<field name="auto_delete"/>
|
||||
</page>
|
||||
<page string="Advanced">
|
||||
<group>
|
||||
<field name="lang"/>
|
||||
<field name="mail_server_id"/>
|
||||
<field name="auto_delete"/>
|
||||
<field name="report_template" domain="[('model','=',model)]"/>
|
||||
<field name="report_name" class="oe_inline"
|
||||
attrs="{'invisible':[('report_template','=',False)]}"/>
|
||||
<field name="attachment_ids">
|
||||
<tree><field name="name"/></tree>
|
||||
</field>
|
||||
</group>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Attachments" colspan="2"/>
|
||||
<notebook colspan="2">
|
||||
<page string="Attach Report">
|
||||
<group>
|
||||
<field name="report_template" colspan="4"
|
||||
domain="[('model','=',model)]"/>
|
||||
<field name="report_name" colspan="4" />
|
||||
</group>
|
||||
</page>
|
||||
<page string="Attach existing files">
|
||||
<field name="attachment_ids" colspan="4" nolabel="1" height="350"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -99,9 +71,9 @@
|
||||
<field name="model">email.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Templates">
|
||||
<field name="model_id"/>
|
||||
<field name="mail_server_id" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="model_id"/>
|
||||
<field name="subject"/>
|
||||
<field name="email_from"/>
|
||||
<field name="email_to"/>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_email_template,email.template,model_email_template,,1,0,0,0
|
||||
access_email_template,email.template,model_email_template,,1,1,1,0
|
||||
access_email_template_system,email.template system,model_email_template,base.group_system,1,1,1,1
|
||||
access_email_template_manager,email.template,model_email_template,,1,1,1,1
|
||||
access_email_template_preview_system,email.template.preview system,model_email_template_preview,base.group_system,1,1,1,1
|
||||
|
||||
|
@@ -53,51 +53,59 @@ class test_message_compose(common.TransactionCase):
|
||||
""" Tests designed for the mail.compose.message wizard updated by email_template. """
|
||||
cr, uid = self.cr, self.uid
|
||||
mail_compose = self.registry('mail.compose.message')
|
||||
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
|
||||
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a.a'})
|
||||
user_admin = self.res_users.browse(cr, uid, uid)
|
||||
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
|
||||
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
||||
group_bird_id = self.mail_group.create(cr, uid, {'name': 'Bird', 'description': 'I am angry !'})
|
||||
group_bird = self.mail_group.browse(cr, uid, group_bird_id)
|
||||
|
||||
# Create template on mail.group
|
||||
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
|
||||
email_template = self.registry('email.template')
|
||||
email_template_id = email_template.create(cr, uid, {'model_id': group_model_id,
|
||||
'name': 'Pigs Template', 'subject': '${record.name}',
|
||||
'name': 'Pigs Template', 'subject': '${object.name}',
|
||||
'body_html': '${object.description}', 'user_signature': True,
|
||||
'email_to': 'b@b c@c', 'email_cc': 'd@d'})
|
||||
# import pdb
|
||||
# pdb.set_trace()
|
||||
'email_to': 'b@b.b c@c.c', 'email_cc': 'd@d.d'})
|
||||
|
||||
# Mail data
|
||||
_subject = 'Pigs'
|
||||
_body_text = 'Pigs rules'
|
||||
_subject1 = 'Pigs'
|
||||
_subject2 = 'Bird'
|
||||
_body_text1 = 'Pigs rules'
|
||||
_body_text_html1 = 'Pigs rules<pre>Admin</pre>'
|
||||
_body_text2 = 'I am angry !'
|
||||
_body_text_html2 = 'I am angry !<pre>Admin</pre>'
|
||||
|
||||
# 3 - Create in mass_mail composition mode that should work with or without email_template installed
|
||||
# CASE1: create in mass_mail composition mode that should work with email_template installed
|
||||
compose_id = mail_compose.create(cr, uid,
|
||||
{'subject': _subject, 'body': _body_text},
|
||||
{'subject': 'Forget me subject', 'body': 'Dummy body'},
|
||||
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group',
|
||||
'default_res_id': -1, 'default_use_template': True,
|
||||
'active_ids': [self.group_pigs_id], 'default_template_id': email_template_id})
|
||||
'active_ids': [self.group_pigs_id, group_bird_id], 'default_template_id': email_template_id})
|
||||
compose = mail_compose.browse(cr, uid, compose_id)
|
||||
# print compose.subject
|
||||
|
||||
|
||||
# Try the 'onchange_template_id'
|
||||
values = mail_compose.onchange_template_id(cr, uid, [], compose.use_template, compose.template_id, compose.composition_mode, compose.res_id)
|
||||
# print values
|
||||
values = mail_compose.onchange_use_template(cr, uid, [], not compose.use_template, compose.template_id, compose.composition_mode, compose.res_id)
|
||||
# print values
|
||||
values = mail_compose.onchange_template_id(cr, uid, [], compose.use_template, compose.template_id, compose.composition_mode, compose.model, compose.res_id)
|
||||
print values
|
||||
# compose.write(values['value'])
|
||||
values = mail_compose.onchange_use_template(cr, uid, [], not compose.use_template, compose.template_id, compose.composition_mode, compose.model, compose.res_id)
|
||||
print values
|
||||
|
||||
compose.refresh()
|
||||
|
||||
|
||||
# # Post the comment, get created message
|
||||
# mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id]})
|
||||
# group_pigs.refresh()
|
||||
# msg = group_pigs.message_ids[0]
|
||||
|
||||
# # Test: last message on Pigs = last created message
|
||||
# test_msg = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [], limit=1))[0]
|
||||
# self.assertEqual(msg.id, test_msg.id, 'Pigs did not receive its mass mailing message')
|
||||
# # Test: mail.message: subject, body
|
||||
# self.assertEqual(msg.subject, _subject, 'mail.message subject is incorrect')
|
||||
# self.assertEqual(msg.body, group_pigs.description, 'mail.message body is incorrect')
|
||||
# Post the comment, get created message
|
||||
mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id, group_bird_id]})
|
||||
group_pigs.refresh()
|
||||
group_bird.refresh()
|
||||
message_pigs = group_pigs.message_ids[0]
|
||||
message_bird = group_bird.message_ids[0]
|
||||
# Test: subject, body
|
||||
self.assertEqual(message_pigs.subject, _subject1, 'mail.message subject on Pigs incorrect')
|
||||
self.assertEqual(message_bird.subject, _subject2, 'mail.message subject on Bird incorrect')
|
||||
self.assertEqual(message_pigs.body, _body_text_html1, 'mail.message body on Pigs incorrect')
|
||||
self.assertEqual(message_bird.body, _body_text_html2, 'mail.message body on Bird incorrect')
|
||||
# Test: partner_ids
|
||||
print message_pigs.partner_ids
|
||||
print message_pigs.partner_ids
|
||||
self.assertEqual(len(message_pigs.partner_ids), 6, 'mail.message partner_ids incorrect')
|
||||
@@ -65,29 +65,19 @@ class email_template_preview(osv.osv_memory):
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'res_id':fields.selection(_get_records, 'Sample Document'),
|
||||
'res_id': fields.selection(_get_records, 'Sample Document'),
|
||||
}
|
||||
|
||||
def on_change_res_id(self, cr, uid, ids, res_id, context=None):
|
||||
if not res_id:
|
||||
return {}
|
||||
if not res_id: return {}
|
||||
vals = {}
|
||||
email_template = self.pool.get('email.template')
|
||||
template_id = context and context.get('template_id')
|
||||
template = email_template.get_email_template(cr, uid, template_id=template_id, record_id=res_id, context=context)
|
||||
model = template.model
|
||||
vals['email_to'] = self.render_template(cr, uid, template.email_to, model, res_id, context)
|
||||
vals['email_cc'] = self.render_template(cr, uid, template.email_cc, model, res_id, context)
|
||||
vals['reply_to'] = self.render_template(cr, uid, template.reply_to, model, res_id, context)
|
||||
vals['subject'] = self.render_template(cr, uid, template.subject, model, res_id, context)
|
||||
description = self.render_template(cr, uid, template.body, model, res_id, context) or ''
|
||||
if template.user_signature:
|
||||
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
|
||||
description += '\n' + signature
|
||||
vals['body'] = description
|
||||
if template.body_html:
|
||||
vals['body_html'] = self.render_template(cr, uid, template.body_html, model, res_id, context) or ''
|
||||
vals['report_name'] = self.render_template(cr, uid, template.report_name, model, res_id, context)
|
||||
template = email_template.browse(cr, uid, template_id, context=context)
|
||||
vals['name'] = template.name
|
||||
mail_values = email_template.generate_email(cr, uid, template_id, res_id, context=context)
|
||||
for k in ('email_from','email_to','email_cc','reply_to','subject','body_html'):
|
||||
vals[k] = mail_values[k]
|
||||
return {'value': vals}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -6,26 +6,22 @@
|
||||
<field name="name">email_template.preview.form</field>
|
||||
<field name="model">email_template.preview</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Email Preview">
|
||||
<field name="model_id" invisible="1"/>
|
||||
<field name="res_id" on_change="on_change_res_id(res_id, context)"/>
|
||||
<group col="2" colspan="4">
|
||||
<field name="email_to" readonly="1"/>
|
||||
<field name="email_cc" readonly="1" attrs="{'invisible': [('email_cc','=',False)]}"/>
|
||||
<field name="reply_to" readonly="1" attrs="{'invisible': [('reply_to','=',False)]}"/>
|
||||
<field name="subject" readonly="1"/>
|
||||
<form string="Email Preview" version="7.0">
|
||||
<div>
|
||||
<h2>Preview of <field name="name" readonly="1" class="oe_inline"/></h2>
|
||||
<field name="model_id" invisible="1"/>
|
||||
<h3>Using sample document
|
||||
<field name="res_id" on_change="on_change_res_id(res_id, context)" class="oe_inline"/>
|
||||
</h3>
|
||||
</div>
|
||||
<group>
|
||||
<field name="email_from" readonly="1"/>
|
||||
<field name="email_to" readonly="1"/>
|
||||
<field name="email_cc" readonly="1" attrs="{'invisible':[('email_cc','=',False)]}"/>
|
||||
<field name="reply_to" readonly="1" attrs="{'invisible':[('reply_to','=',False)]}"/>
|
||||
<field name="subject" readonly="1"/>
|
||||
<field name="body_html" widget="html" readonly="1"/>
|
||||
</group>
|
||||
<group col="4" colspan="4">
|
||||
<notebook>
|
||||
<page string="Body (Text)">
|
||||
<field name="body" nolabel="1" colspan="4" height="350" width="350" readonly="1"/>
|
||||
</page>
|
||||
<page string="Body (Rich/HTML)" attrs="{'invisible': [('body_html','=', False)]}">
|
||||
<field name="body_html" nolabel="1" colspan="4" height="350" width="350" readonly="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</group>
|
||||
<field name="report_name" colspan="4" readonly="1"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -27,13 +27,9 @@ from osv import fields
|
||||
from tools.translate import _
|
||||
|
||||
class mail_compose_message(osv.osv_memory):
|
||||
""" Inherit mail_compose_message to add email template feature in the
|
||||
message composer. """
|
||||
|
||||
_inherit = 'mail.compose.message'
|
||||
|
||||
def _get_templates(self, cr, uid, context=None):
|
||||
""" Return Email Template of particular Model. """
|
||||
if context is None:
|
||||
context = {}
|
||||
model = False
|
||||
@@ -52,7 +48,6 @@ class mail_compose_message(osv.osv_memory):
|
||||
return []
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
""" Override to handle templates. """
|
||||
if context is None:
|
||||
context = {}
|
||||
result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
|
||||
@@ -65,43 +60,36 @@ class mail_compose_message(osv.osv_memory):
|
||||
'template_id': fields.selection(_get_templates, 'Template', size=-1),
|
||||
}
|
||||
|
||||
def onchange_template_id(self, cr, uid, ids, use_template, template_id, composition_mode, res_id, context=None):
|
||||
""" onchange_template_id: read or render the template if set, get back
|
||||
to default values if not. """
|
||||
def onchange_template_id(self, cr, uid, ids, use_template, template_id, composition_mode, model, res_id, context=None):
|
||||
""" - use_template not set: return default_get
|
||||
- use_template set:
|
||||
- mass_mailing: we cannot render, so return the template values
|
||||
- else: return rendered values """
|
||||
fields = ['body', 'body_html', 'subject', 'partner_ids', 'email_to', 'email_cc']
|
||||
if use_template and template_id:
|
||||
# use the original template values, to be rendered when actually sent
|
||||
if composition_mode == 'mass_mail':
|
||||
values = self.pool.get('email.template').read(cr, uid, template_id, fields, context)
|
||||
# render the mail as one-shot
|
||||
else:
|
||||
values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
|
||||
# retrofit generated attachments in the expected field format
|
||||
if values['attachments']:
|
||||
attachment = values.pop('attachments')
|
||||
attachment_obj = self.pool.get('ir.attachment')
|
||||
att_ids = []
|
||||
for fname, fcontent in attachment.iteritems():
|
||||
data_attach = {
|
||||
'name': fname,
|
||||
'datas': fcontent,
|
||||
'datas_fname': fname,
|
||||
'description': fname,
|
||||
'res_model' : self._name,
|
||||
'res_id' : ids[0] if ids else False
|
||||
}
|
||||
att_ids.append(attachment_obj.create(cr, uid, data_attach))
|
||||
values['attachment_ids'] = att_ids
|
||||
else: # restore defaults
|
||||
if use_template and template_id and composition_mode == 'mass_mail':
|
||||
values = self.pool.get('email.template').read(cr, uid, template_id, fields, context)
|
||||
elif use_template and template_id:
|
||||
values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
|
||||
|
||||
values['attachment_ids'] = []
|
||||
attachment_obj = self.pool.get('ir.attachment')
|
||||
for attach_fname, attach_datas in values.get('attachments', []):
|
||||
data_attach = {
|
||||
'name': attach_fname,
|
||||
'datas': attach_datas,
|
||||
'datas_fname': attach_fname,
|
||||
'description': fname,
|
||||
'res_model': model,
|
||||
'res_id': res_id,
|
||||
}
|
||||
values['attachment_ids'].append(attachment_obj.create(cr, uid, data_attach), context=context)
|
||||
else:
|
||||
values = self.default_get(cr, uid, fields, context=context)
|
||||
|
||||
if values.get('body_html') and not values.get('body'):
|
||||
values['body'] = values.get('body_html')
|
||||
|
||||
values.update(use_template=use_template, template_id=template_id)
|
||||
|
||||
print 'returning ', values
|
||||
|
||||
return {'value': values}
|
||||
|
||||
def toggle_template(self, cr, uid, ids, context=None):
|
||||
@@ -109,16 +97,15 @@ class mail_compose_message(osv.osv_memory):
|
||||
emulate an on_change, then writes the value to update the form. """
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
onchange_res = self.onchange_use_template(cr, uid, ids, not record.use_template,
|
||||
record.template_id, record.composition_mode, record.res_id, context=context)['value']
|
||||
record.template_id, record.composition_mode, record.model, record.res_id, context=context)['value']
|
||||
record.write(onchange_res)
|
||||
return True
|
||||
|
||||
def onchange_use_template(self, cr, uid, ids, use_template, template_id, composition_mode, res_id, context=None):
|
||||
def onchange_use_template(self, cr, uid, ids, use_template, template_id, composition_mode, model, res_id, context=None):
|
||||
""" onchange_use_template (values: True or False). If use_template is
|
||||
False, we do like an onchange with template_id False for values """
|
||||
onchange_template_values = self.onchange_template_id(cr, uid, ids, use_template,
|
||||
template_id, composition_mode, res_id, context=context)
|
||||
return onchange_template_values
|
||||
return self.onchange_template_id(cr, uid, ids, use_template,
|
||||
template_id, composition_mode, model, res_id, context=context)
|
||||
|
||||
def save_as_template(self, cr, uid, ids, context=None):
|
||||
""" hit save as template button: current form value will be a new
|
||||
@@ -144,9 +131,36 @@ class mail_compose_message(osv.osv_memory):
|
||||
record.write({'template_id': template_id, 'use_template': True})
|
||||
return True
|
||||
|
||||
#------------------------------------------------------
|
||||
# Wizard validation and send
|
||||
#------------------------------------------------------
|
||||
|
||||
def render_message(self, cr, uid, wizard, model, res_id, context=None):
|
||||
""" Generate an email from the template for given (model, res_id) pair.
|
||||
This method is meant to be inherited by email_template that will
|
||||
produce a more complete dictionary, with email_to, ...
|
||||
"""
|
||||
# render the template to get the email
|
||||
template_values = self.pool.get('email.template').generate_email(cr, uid, wizard.template_id, res_id, context=context)
|
||||
# TDE TODO: handle fields to update / not to update (mail_server_id, auto_delete, ...)
|
||||
# transform email_to, email_cc into partner_ids
|
||||
partner_ids = []
|
||||
mails = tools.email_split(template_values.pop('email_to', '') + ' ' + template_values.pop('email_cc', ''))
|
||||
for mail in mails:
|
||||
partner_search_ids = self.pool.get('res.partner').search(cr, uid, [('email', 'ilike', mail)], context=context)
|
||||
if partner_search_ids:
|
||||
partner_ids.append((4, partner_search_ids[0]))
|
||||
else:
|
||||
partner_id = self.pool.get('res.partner').name_create(cr, uid, mail, context=context)[0]
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||
partner_ids.append((4, partner_id))
|
||||
# get values to return
|
||||
email_dict = super(mail_compose_message, self).render_message(cr, uid, wizard, model, res_id, context)
|
||||
email_dict.update(template_values)
|
||||
email_dict.update(partner_ids=partner_ids, attachments=template_values.get('attachments'))
|
||||
return email_dict
|
||||
|
||||
def render_template(self, cr, uid, template, model, res_id, context=None):
|
||||
""" Override of mail.compose.message behavior: use the power of
|
||||
templates ! """
|
||||
return self.pool.get('email.template').render_template(cr, uid, template, model, res_id, context=context)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<group attrs="{'invisible':[('use_template','=',False)]}" colspan="4" col="4">
|
||||
<field name="use_template" invisible="1"/>
|
||||
<field name="template_id" colspan="3"
|
||||
on_change="onchange_template_id(use_template, template_id, composition_mode, res_id, context)"/>
|
||||
on_change="onchange_template_id(use_template, template_id, composition_mode, model, res_id, context)"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</data>
|
||||
@@ -34,10 +34,10 @@
|
||||
<data>
|
||||
<xpath expr="//field[@name='partner_ids']" position="after">
|
||||
<field name="use_template" colspan="2" nolabel="1" invisible="1"
|
||||
on_change="onchange_use_template(use_template, template_id, composition_mode, res_id, context)"/>
|
||||
on_change="onchange_use_template(use_template, template_id, composition_mode, model, res_id, context)"/>
|
||||
<field name="template_id" colspan="2" nolabel="1"
|
||||
attrs="{'invisible':[('use_template','=',False)]}"
|
||||
on_change="onchange_template_id(use_template, template_id, composition_mode, res_id, context)"/>
|
||||
on_change="onchange_template_id(use_template, template_id, composition_mode, model, res_id, context)"/>
|
||||
</xpath>
|
||||
<xpath expr="//button[@class='oe_mail_compose_message_attachment']" position="before">
|
||||
<button icon="/email_template/static/src/img/email_template.png"
|
||||
|
||||
@@ -3,7 +3,7 @@ var _t = instance.web._t;
|
||||
|
||||
instance.web.Sidebar = instance.web.Sidebar.extend({
|
||||
on_attachments_loaded: function(attachments) {
|
||||
self = this
|
||||
var self = this;
|
||||
self._super(attachments);
|
||||
// if attachment contains a google doc url do nothing
|
||||
// else display a button to create a google doc
|
||||
|
||||
@@ -25,6 +25,7 @@ import datetime, time
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
|
||||
import math
|
||||
import netsvc
|
||||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
@@ -112,7 +113,7 @@ class hr_holidays(osv.osv):
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Description', required=True, size=64),
|
||||
'name': fields.char('Description', size=64),
|
||||
'state': fields.selection([('draft', 'To Submit'), ('cancel', 'Cancelled'),('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved')],
|
||||
'State', readonly=True, help='The state is set to \'To Submit\', when a holiday request is created.\
|
||||
\nThe state is \'To Approve\', when holiday request is confirmed by user.\
|
||||
@@ -123,8 +124,6 @@ class hr_holidays(osv.osv):
|
||||
'date_to': fields.datetime('End Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
|
||||
'holiday_status_id': fields.many2one("hr.holidays.status", "Leave Type", required=True,readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
|
||||
'employee_id': fields.many2one('hr.employee', "Employee", select=True, invisible=False, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, help='Leave Manager can let this field empty if this leave request/allocation is for every employee'),
|
||||
#'manager_id': fields.many2one('hr.employee', 'Leave Manager', invisible=False, readonly=True, help='This area is automatically filled by the user who validate the leave'),
|
||||
#'notes': fields.text('Notes',readonly=True, states={'draft':[('readonly',False)]}),
|
||||
'manager_id': fields.many2one('hr.employee', 'First Approval', invisible=False, readonly=True, help='This area is automatically filled by the user who validate the leave'),
|
||||
'notes': fields.text('Reasons',readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
|
||||
'number_of_days_temp': fields.float('Number of Days', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
|
||||
@@ -134,8 +133,8 @@ class hr_holidays(osv.osv):
|
||||
'parent_id': fields.many2one('hr.holidays', 'Parent'),
|
||||
'linked_request_ids': fields.one2many('hr.holidays', 'parent_id', 'Linked Requests',),
|
||||
'department_id':fields.related('employee_id', 'department_id', string='Department', type='many2one', relation='hr.department', readonly=True, store=True),
|
||||
'category_id': fields.many2one('hr.employee.category', "Category", help='Category of Employee'),
|
||||
'holiday_type': fields.selection([('employee','By Employee'),('category','By Employee Category')], 'Allocation Type', help='By Employee: Allocation/Request for individual Employee, By Employee Category: Allocation/Request for group of employees in category', required=True),
|
||||
'category_id': fields.many2one('hr.employee.category', "Category", help='Category of Employee', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
|
||||
'holiday_type': fields.selection([('employee','By Employee'),('category','By Employee Category')], 'Allocation Mode', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, help='By Employee: Allocation/Request for individual Employee, By Employee Category: Allocation/Request for group of employees in category', required=True),
|
||||
'manager_id2': fields.many2one('hr.employee', 'Second Approval', readonly=True, help='This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation)'),
|
||||
'double_validation': fields.related('holiday_status_id', 'double_validation', type='boolean', relation='hr.holidays.status', string='Apply Double Validation'),
|
||||
}
|
||||
@@ -147,16 +146,11 @@ class hr_holidays(osv.osv):
|
||||
'holiday_type': 'employee'
|
||||
}
|
||||
_sql_constraints = [
|
||||
('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "You have to select an employee or a category."),
|
||||
('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "The employee or employee category of this request is missing."),
|
||||
('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be before the end date !"),
|
||||
('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0 !"),
|
||||
]
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
obj_id = super(hr_holidays, self).create(cr, uid, vals, context=context)
|
||||
self.create_notificate(cr, uid, [obj_id], context=context)
|
||||
return obj_id
|
||||
|
||||
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 '''
|
||||
obj_res_leave = self.pool.get('resource.calendar.leaves')
|
||||
@@ -201,8 +195,8 @@ class hr_holidays(osv.osv):
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
for rec in self.browse(cr, uid, ids, context=context):
|
||||
if rec.state<>'draft':
|
||||
raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is not in draft state !'))
|
||||
if rec.state not in ['draft', 'cancel', 'confirm']:
|
||||
raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is in %s state!')%(rec.state))
|
||||
return super(hr_holidays, self).unlink(cr, uid, ids, context)
|
||||
|
||||
def onchange_date_from(self, cr, uid, ids, date_to, date_from):
|
||||
@@ -210,7 +204,7 @@ class hr_holidays(osv.osv):
|
||||
if date_to and date_from:
|
||||
diff_day = self._get_number_of_days(date_from, date_to)
|
||||
result['value'] = {
|
||||
'number_of_days_temp': round(diff_day)+1
|
||||
'number_of_days_temp': round(math.floor(diff_day))+1
|
||||
}
|
||||
return result
|
||||
result['value'] = {
|
||||
@@ -244,29 +238,30 @@ class hr_holidays(osv.osv):
|
||||
self.unlink(cr, uid, to_unlink, context=context)
|
||||
return True
|
||||
|
||||
def holidays_validate(self, cr, uid, ids, context=None):
|
||||
def holidays_first_validate(self, cr, uid, ids, context=None):
|
||||
self.check_holidays(cr, uid, ids, context=context)
|
||||
obj_emp = self.pool.get('hr.employee')
|
||||
ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
|
||||
manager = ids2 and ids2[0] or False
|
||||
self.holidays_validate_notificate(cr, uid, ids, context=context)
|
||||
self.holidays_first_validate_notificate(cr, uid, ids, context=context)
|
||||
return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager})
|
||||
|
||||
def holidays_validate2(self, cr, uid, ids, context=None):
|
||||
def holidays_validate(self, cr, uid, ids, context=None):
|
||||
self.check_holidays(cr, uid, ids, context=context)
|
||||
obj_emp = self.pool.get('hr.employee')
|
||||
ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
|
||||
manager = ids2 and ids2[0] or False
|
||||
self.write(cr, uid, ids, {'state':'validate'})
|
||||
data_holiday = self.browse(cr, uid, ids)
|
||||
holiday_ids = []
|
||||
for record in data_holiday:
|
||||
if record.holiday_status_id.double_validation:
|
||||
holiday_ids.append(record.id)
|
||||
if record.double_validation:
|
||||
self.write(cr, uid, [record.id], {'manager_id2': manager})
|
||||
else:
|
||||
self.write(cr, uid, [record.id], {'manager_id': manager})
|
||||
if record.holiday_type == 'employee' and record.type == 'remove':
|
||||
meeting_obj = self.pool.get('crm.meeting')
|
||||
meeting_vals = {
|
||||
'name': record.name,
|
||||
'name': record.name or _('Leave Request'),
|
||||
'categ_ids': record.holiday_status_id.categ_id and [(6,0,[record.holiday_status_id.categ_id.id])] or [],
|
||||
'duration': record.number_of_days_temp * 8,
|
||||
'description': record.notes,
|
||||
@@ -301,25 +296,27 @@ class hr_holidays(osv.osv):
|
||||
wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'confirm', cr)
|
||||
wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'validate', cr)
|
||||
wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'second_validate', cr)
|
||||
if holiday_ids:
|
||||
self.holidays_valid2_notificate(cr, uid, holiday_ids, context=context)
|
||||
self.write(cr, uid, holiday_ids, {'manager_id2': manager})
|
||||
self.holidays_validate_notificate(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def holidays_confirm(self, cr, uid, ids, context=None):
|
||||
self.check_holidays(cr, uid, ids, context=context)
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
if record.employee_id and record.employee_id.parent_id and record.employee_id.parent_id.user_id:
|
||||
self.message_subscribe(cr, uid, [record.id], user_ids=[record.employee_id.parent_id.user_id.id], context=context)
|
||||
self.holidays_confirm_notificate(cr, uid, ids, context=context)
|
||||
return self.write(cr, uid, ids, {'state':'confirm'})
|
||||
|
||||
def holidays_refuse(self, cr, uid, ids, approval, context=None):
|
||||
def holidays_refuse(self, cr, uid, ids, context=None):
|
||||
obj_emp = self.pool.get('hr.employee')
|
||||
ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
|
||||
manager = ids2 and ids2[0] or False
|
||||
if approval == 'first_approval':
|
||||
self.write(cr, uid, ids, {'state': 'refuse', 'manager_id': manager})
|
||||
else:
|
||||
self.write(cr, uid, ids, {'state': 'refuse', 'manager_id2': manager})
|
||||
self.holidays_refuse_notificate(cr, uid, ids, approval, context=context)
|
||||
for holiday in self.browse(cr, uid, ids, context=context):
|
||||
if holiday.state == 'validate1':
|
||||
self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id': manager})
|
||||
else:
|
||||
self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id2': manager})
|
||||
self.holidays_refuse_notificate(cr, uid, ids, context=context)
|
||||
self.holidays_cancel(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
@@ -333,7 +330,7 @@ class hr_holidays(osv.osv):
|
||||
# If a category that created several holidays, cancel all related
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
for request in record.linked_request_ids or []:
|
||||
wf_service.trg_validate(uid, 'hr.holidays', request.id, 'cancel', cr)
|
||||
wf_service.trg_validate(uid, 'hr.holidays', request.id, 'refuse', cr)
|
||||
|
||||
self._remove_resource_leave(cr, uid, ids, context=context)
|
||||
return True
|
||||
@@ -367,39 +364,33 @@ class hr_holidays(osv.osv):
|
||||
def create_notificate(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, ids,
|
||||
_("The %s request has been <b>created</b> and is waiting for confirmation.")
|
||||
% ('leave' if obj.type == 'remove' else 'allocation',), context=context)
|
||||
_("The request has been <b>created</b> and is waiting confirmation."), context=context)
|
||||
return True
|
||||
|
||||
def holidays_confirm_notificate(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids):
|
||||
self.message_post(cr, uid, [obj.id], _("The %s request has been <b>confirmed</b> and is waiting for validation by the manager.")
|
||||
% ('leave' if obj.type == 'remove' else 'allocation',), context=context)
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The request has been <b>submitted</b> and is waiting for validation by the manager."), context=context)
|
||||
|
||||
def holidays_first_validate_notificate(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The request has been <b>approved</b>. A second validation is necessary and is now pending."), context=context)
|
||||
|
||||
def holidays_validate_notificate(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids):
|
||||
if obj.holiday_status_id.double_validation:
|
||||
if obj.double_validation:
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The %s request has been <b>approved</b>. A second validation is necessary and is now pending.")
|
||||
% ('leave' if obj.type == 'remove' else 'allocation',), context=context)
|
||||
_("The request has been <b>double validated</b>. The validation process is now over."), context=context)
|
||||
else:
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The %s request has been <b>approved</b>. The validation process is now over.")
|
||||
% ('leave' if obj.type == 'remove' else 'allocation',), context=context)
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The request has been <b>approved</b>. The validation process is now over."), context=context)
|
||||
|
||||
def holidays_valid2_notificate(self, cr, uid, ids, context=None):
|
||||
def holidays_refuse_notificate(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids):
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The %s request has been <b>double validated</b>. The validation process is now over.")
|
||||
% ('leave' if obj.type == 'remove' else 'allocation',), context=context)
|
||||
|
||||
def holidays_refuse_notificate(self, cr, uid, ids, approval, context=None):
|
||||
for obj in self.browse(cr, uid, ids):
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The %s request has been <b>refused</b>. The validation process is now over.")
|
||||
% ('leave' if obj.type == 'remove' else 'allocation',), context=context)
|
||||
|
||||
hr_holidays()
|
||||
self.message_post(cr, uid, [obj.id],
|
||||
_("The request has been <b>refused</b>. The validation process is now over."), context=context)
|
||||
|
||||
|
||||
class resource_calendar_leaves(osv.osv):
|
||||
_inherit = "resource.calendar.leaves"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<record model="hr.holidays" id="hr_holidays_employee1_cl">
|
||||
<field name="name">Trip with Family</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_cl"/>
|
||||
<field name="holiday_status_id" ref="holiday_status_comp"/>
|
||||
<field eval="time.strftime('%Y-%m-01')" name="date_from"/>
|
||||
<field eval="time.strftime('%Y-%m-03')" name="date_to"/>
|
||||
<field name="type">remove</field>
|
||||
@@ -52,13 +52,10 @@
|
||||
<field name="employee_id" ref="hr.employee_fp"/>
|
||||
</record>
|
||||
|
||||
<workflow action="confirm" model="hr.holidays" ref="hr_holidays_employee1_allocation_cl"/>
|
||||
<workflow action="validate" model="hr.holidays" ref="hr_holidays_employee1_allocation_cl"/>
|
||||
|
||||
<workflow action="confirm" model="hr.holidays" ref="hr_holidays_employee1_sl"/>
|
||||
<workflow action="validate" model="hr.holidays" ref="hr_holidays_employee1_sl"/>
|
||||
|
||||
<workflow action="confirm" model="hr.holidays" ref="hr_holidays_employee1_int_tour"/>
|
||||
<workflow action="validate" model="hr.holidays" ref="hr_holidays_employee1_int_tour"/>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -83,56 +83,42 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="edit_holiday_new">
|
||||
<record model="ir.ui.view" id="edit_holiday_new">
|
||||
<field name="name">Leave Request</field>
|
||||
<field name="model">hr.holidays</field>
|
||||
<field name="priority">1</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Leave Request" version="7.0">
|
||||
<header>
|
||||
<button string="Submit to Manager" name="confirm" states="draft" type="workflow" class="oe_highlight"/>
|
||||
<button string="Approve" name="validate" states="confirm" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
|
||||
<button string="Validate" name="second_validate" states="validate1" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
|
||||
<button string="Refuse" name="refuse" states="confirm,validate1" type="workflow" groups="base.group_hr_user,base.group_hr_manager" class="oe_highlight"/>
|
||||
<button string="Reset to New" name="set_to_draft" states="refuse,validate" type="object" groups="base.group_hr_user" />
|
||||
<button string="Refuse" name="refuse" states="confirm,validate1,validate" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
|
||||
<button string="Reset to New" name="set_to_draft" states="refuse" type="object" groups="base.group_hr_user" />
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,validate" statusbar_colors='{"confirm":"blue","validate1":"blue","refuse":"red"}'/>
|
||||
</header>
|
||||
<sheet string="Leave Request">
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" attrs="{'readonly':[('state','!=','draft'),('state','!=','confirm')]}"/>
|
||||
<field name="holiday_type" on_change="onchange_type(holiday_type)" attrs="{'readonly':[('state','!=','draft')]}" width="130" string="Mode" groups="base.group_hr_user"/>
|
||||
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')],'invisible':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
|
||||
<field name="category_id" attrs="{'required':[('holiday_type','=','category')], 'invisible':[('holiday_type','=','employee')], 'readonly':[('state','!=','draft'), ('state','!=','confirm')]}"/>
|
||||
<field name="department_id" attrs="{'readonly':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="holiday_status_id" on_change="onchange_status_id(holiday_status_id)" context="{'employee_id':employee_id}"/>
|
||||
<label for="number_of_days_temp" string="Duration"/>
|
||||
<div>
|
||||
<field name="date_from" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/> -
|
||||
<field name="date_to" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/>
|
||||
<group col="3">
|
||||
<field name="date_from" nolabel="1" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/><label string="-" class="oe_inline" />
|
||||
<field name="date_to" nolabel="1" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/>
|
||||
</group>
|
||||
<div>
|
||||
<field name="number_of_days_temp" class="oe_inline"/> days
|
||||
</div>
|
||||
</div>
|
||||
<field name="category_id" attrs="{'required':[('holiday_type','=','category')], 'invisible':[('holiday_type','=','employee')], 'readonly':[('state','!=','draft'), ('state','!=','confirm')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="holiday_type" on_change="onchange_type(holiday_type)" attrs="{'readonly':[('state','!=','draft')]}" width="130" string="Mode" groups="base.group_hr_user"/>
|
||||
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')],'invisible':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
|
||||
<field name="department_id" attrs="{'readonly':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="General">
|
||||
<group>
|
||||
<group>
|
||||
<field name="manager_id" groups="base.group_no_one"/>
|
||||
<field name="double_validation" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="manager_id2" attrs="{'invisible':[('double_validation', '!=', True)]}" groups="base.group_no_one"/>
|
||||
</group>
|
||||
</group>
|
||||
<newline/>
|
||||
<field name="notes" nolabel="1" colspan="4" placeholder="Add a reason..."/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
@@ -149,37 +135,27 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="Allocation Request" version="7.0">
|
||||
<header>
|
||||
<button string="Submit to Manager" name="confirm" states="draft" type="workflow" class="oe_highlight"/>
|
||||
<button string="Approve" name="validate" states="confirm" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
|
||||
<button string="Validate" name="second_validate" states="validate1" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
|
||||
<button string="Refuse" name="refuse" states="confirm,validate1" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
|
||||
<button string="Reset to New" name="set_to_draft" states="cancel,validate,refuse" type="object" groups="base.group_hr_user" />
|
||||
<button string="Refuse" name="refuse" states="confirm,validate,validate1" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
|
||||
<button string="Reset to New" name="set_to_draft" states="cancel,refuse" type="object" groups="base.group_hr_user" />
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,validate" statusbar_colors='{"confirm":"blue","validate1":"blue","refuse":"red"}'/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="holiday_type" on_change="onchange_type(holiday_type)" attrs="{'readonly':[('state','!=','draft')]}" string="Allocation Mode" groups="base.group_hr_manager"/>
|
||||
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')], 'invisible':[('holiday_type','=','category')]}"/>
|
||||
<field name="category_id" attrs="{'required':[('holiday_type','=','category')], 'readonly':[('state','!=','draft')], 'invisible':[('holiday_type','=','employee')]}"/>
|
||||
<field name="department_id" attrs="{'readonly':['|', ('holiday_type','=','category'), ('state','not in' ,('draft', 'confirm'))]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="name" required="1" attrs="{'readonly':[('state','!=','draft'),('state','!=','confirm')]}"/>
|
||||
<field name="holiday_status_id" on_change="onchange_status_id(holiday_status_id)" context="{'employee_id':employee_id}"/>
|
||||
<field name="number_of_days_temp"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="holiday_type" on_change="onchange_type(holiday_type)"/>
|
||||
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')], 'invisible':[('holiday_type','=','category')]}"/>
|
||||
<field name="category_id" attrs="{'required':[('holiday_type','=','category')], 'invisible':[('holiday_type','=','employee')]}"/>
|
||||
<field name="department_id" attrs="{'invisible':[('holiday_type','=','category')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="General">
|
||||
<group col="4">
|
||||
<field name="double_validation" invisible="1"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="manager_id2" attrs="{'invisible':[('double_validation', '!=', True)]}"/>
|
||||
</group>
|
||||
<field name="notes" placeholder="Add a reason..."/>
|
||||
</page>
|
||||
</notebook>
|
||||
<field name="notes" nolabel="1" colspan="4" placeholder="Add a reason..."/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
@@ -223,7 +199,6 @@
|
||||
<field name="state"/>
|
||||
</header>
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="holiday_status_id"/>
|
||||
<field name="type"/>
|
||||
<field name="date_from" on_change="onchange_date_from(date_to, date_from)" attrs="{'readonly':[('type','=','add')], 'required':[('type','=','remove')]}"/>
|
||||
@@ -231,7 +206,7 @@
|
||||
<field name="number_of_days_temp"/>
|
||||
<field name="manager_id"/>
|
||||
</group>
|
||||
<field name="notes"/>
|
||||
<field name="name" placeholder="Add a reason..."/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -284,12 +259,12 @@
|
||||
<menuitem name="Leaves" parent="hr.menu_hr_root" id="menu_open_ask_holidays" sequence="20"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="open_ask_holidays">
|
||||
<field name="name">Leave Requests</field>
|
||||
<field name="name">My Leave Requests</field>
|
||||
<field name="res_model">hr.holidays</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="edit_holiday_new"/>
|
||||
<field name="context">{}</field>
|
||||
<field name="domain">[('type','=','remove')]</field>
|
||||
<field name="domain">[('type','=','remove'),('employee_id.user_id','=', uid)]</field>
|
||||
<field name="search_view_id" ref="view_hr_holidays_filter"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
@@ -323,7 +298,7 @@
|
||||
<field name="view_id" ref="view_holiday_new_calendar"/>
|
||||
<field name="act_window_id" ref="open_ask_holidays"/>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem name="My Leave Requests" parent="menu_open_ask_holidays" id="menu_open_ask_holidays_new" action="open_ask_holidays"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="request_approve_holidays">
|
||||
@@ -353,11 +328,11 @@
|
||||
<menuitem name="Leave Requests to Approve" parent="menu_open_ask_holidays" id="menu_request_approve_holidays" action="request_approve_holidays" groups="base.group_hr_user"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="open_allocation_holidays">
|
||||
<field name="name">Allocation Requests</field>
|
||||
<field name="name">My Allocation Requests</field>
|
||||
<field name="res_model">hr.holidays</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{'default_type':'add'}</field>
|
||||
<field name="domain">[('type','=','add')]</field>
|
||||
<field name="domain">[('type','=','add'),('employee_id.user_id','=', uid)]</field>
|
||||
<field name="view_id" ref="allocation_leave_new"/>
|
||||
<field name="search_view_id" ref="view_hr_holidays_filter"/>
|
||||
</record>
|
||||
@@ -376,7 +351,7 @@
|
||||
<field name="act_window_id" ref="open_allocation_holidays"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Allocation Requests" parent="menu_open_ask_holidays" id="menu_open_allocation_holidays" action="open_allocation_holidays"/>
|
||||
<menuitem name="My Allocation Requests" parent="menu_open_ask_holidays" id="menu_open_allocation_holidays" action="open_allocation_holidays"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="open_company_allocation">
|
||||
<field name="name">Leaves Summary</field>
|
||||
|
||||
@@ -2,7 +2,16 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Workflow definition -->
|
||||
<!-- Workflow definition
|
||||
1. draft->submitted (no signal)
|
||||
2. submitted->accepted (validate signal) if not double_validation
|
||||
2. submitted -> first_accepted (validate signal) if double_validation
|
||||
2. submitted->refused (refuse signal)
|
||||
3. accepted->refused (refuse signal)
|
||||
4. first_accepted -> accepted (second_validate signal)
|
||||
4. first_accepted -> refused (refuse signal)
|
||||
|
||||
-->
|
||||
|
||||
<record model="workflow" id="wkf_holidays">
|
||||
<field name="name">hr.wkf.holidays</field>
|
||||
@@ -10,13 +19,13 @@
|
||||
<field name="on_create">True</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_draft">
|
||||
<record model="workflow.activity" id="act_draft"> <!-- draft -->
|
||||
<field name="wkf_id" ref="wkf_holidays" />
|
||||
<field name="flow_start">True</field>
|
||||
<field name="name">draft</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_confirm">
|
||||
<record model="workflow.activity" id="act_confirm"> <!-- submitted -->
|
||||
<field name="wkf_id" ref="wkf_holidays" />
|
||||
<field name="name">confirm</field>
|
||||
<field name="kind">function</field>
|
||||
@@ -24,74 +33,94 @@
|
||||
<field name="split_mode">OR</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_validate">
|
||||
<record model="workflow.activity" id="act_validate"> <!-- accepted -->
|
||||
<field name="wkf_id" ref="wkf_holidays" />
|
||||
<field name="name">validate</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">holidays_validate()</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_validate1">
|
||||
<record model="workflow.activity" id="act_validate1"> <!-- first_accepted -->
|
||||
<field name="wkf_id" ref="wkf_holidays" />
|
||||
<field name="name">second_validate</field>
|
||||
<field name="name">first_validate</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">holidays_validate2()</field>
|
||||
<field name="action">holidays_first_validate()</field>
|
||||
<field name="split_mode">OR</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="workflow.activity" id="act_refuse">
|
||||
<record model="workflow.activity" id="act_refuse"> <!-- refused -->
|
||||
<field name="wkf_id" ref="wkf_holidays" />
|
||||
<field name="name">refuse</field>
|
||||
<field name="flow_stop">True</field>
|
||||
<field name="kind">stopall</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">holidays_refuse()</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
workflow transition
|
||||
-->
|
||||
|
||||
<record model="workflow.transition" id="t1">
|
||||
<record model="workflow.transition" id="holiday_draft2confirm"> <!-- 1. draft->submitted (no signal) -->
|
||||
<field name="act_from" ref="act_draft" />
|
||||
<field name="act_to" ref="act_confirm" />
|
||||
<field name="signal">confirm</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t2">
|
||||
<record model="workflow.transition" id="holiday_confirm2validate"> <!-- 2. submitted->accepted (validate signal) if not double_validation-->
|
||||
<field name="act_from" ref="act_confirm" />
|
||||
<field name="act_to" ref="act_validate" />
|
||||
<field name="signal">validate</field>
|
||||
<field name="condition">not double_validation</field>
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="holiday_confirm2validate1"> <!-- 2. submitted -> first_accepted (validate signal) if double_validation-->
|
||||
<field name="act_from" ref="act_confirm" />
|
||||
<field name="act_to" ref="act_validate1" />
|
||||
<field name="condition">double_validation</field>
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="workflow.transition" id="holiday_confirm2refuse"> <!-- 2. submitted->refused (refuse signal) -->
|
||||
<field name="act_from" ref="act_confirm" />
|
||||
<field name="act_to" ref="act_refuse" />
|
||||
<field name="signal">refuse</field>
|
||||
<field name="condition">True</field>
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t3">
|
||||
<field name="act_from" ref="act_confirm" />
|
||||
<field name="act_to" ref="act_refuse" />
|
||||
<field name="signal">refuse</field>
|
||||
<field name="condition">holidays_refuse('first_approval')</field>
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t4">
|
||||
<record model="workflow.transition" id="holiday_validate2refuse"> <!-- 3. accepted->refused (refuse signal) -->
|
||||
<field name="act_from" ref="act_validate" />
|
||||
<field name="act_to" ref="act_refuse" />
|
||||
<field name="signal">refuse</field>
|
||||
<field name="condition">holidays_refuse('second_approval')</field>
|
||||
<field name="condition">True</field>
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t8">
|
||||
<record model="workflow.transition" id="holiday_validate2refuse"> <!-- 3. accepted->refused (refuse signal) -->
|
||||
<field name="act_from" ref="act_validate" />
|
||||
<field name="act_to" ref="act_validate1" />
|
||||
<field name="act_to" ref="act_refuse" />
|
||||
<field name="signal">refuse</field>
|
||||
<field name="condition">True</field>
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="workflow.transition" id="holiday_validate1_validate"> <!-- 4. first_accepted -> accepted (second_validate signal) -->
|
||||
<field name="act_from" ref="act_validate1" />
|
||||
<field name="act_to" ref="act_validate" />
|
||||
<field name="condition">True</field>
|
||||
<field name="signal">second_validate</field>
|
||||
<field name="group_id" ref="base.group_hr_manager" />
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t11">
|
||||
<field name="act_from" ref="act_validate" />
|
||||
<field name="act_to" ref="act_validate1" />
|
||||
<field name="condition">not holiday_status_id.double_validation</field>
|
||||
<field name="signal" eval="False"/>
|
||||
<record model="workflow.transition" id="holiday_validate1_refuse"> <!-- 4. first_accepted->refused (refuse signal) -->
|
||||
<field name="act_from" ref="act_validate1" />
|
||||
<field name="act_to" ref="act_refuse" />
|
||||
<field name="signal">refuse</field>
|
||||
<field name="condition">True</field>
|
||||
<field name="group_id" ref="base.group_hr_user"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -4,5 +4,5 @@ access_hr_holidays_user,hr.holidays.user,model_hr_holidays,base.group_hr_user,1,
|
||||
access_hr_holidays_employee,hr.holidays.employee,model_hr_holidays,base.group_user,1,1,1,1
|
||||
access_hr_holydays_status_employee,hr.holidays.status employee,model_hr_holidays_status,base.group_user,1,0,0,0
|
||||
access_hr_holidays_remain_user,hr.holidays.ramain.user,model_hr_holidays_remaining_leaves_user,base.group_hr_user,1,1,1,1
|
||||
access_resource_calendar_leaves_manager,resource_calendar_leaves_manager,resource.model_resource_calendar_leaves,base.group_hr_manager,1,1,1,1
|
||||
access_resource_calendar_leaves_user,resource_calendar_leaves_user,resource.model_resource_calendar_leaves,base.group_hr_user,1,1,1,1
|
||||
access_crm_meeting_type_manager,crm.meeting.type.manager,base_calendar.model_crm_meeting_type,base.group_hr_manager,1,1,1,1
|
||||
|
||||
|
@@ -1,6 +1,19 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="property_rule_holidays_employee" model="ir.rule">
|
||||
<field name="name">Employee Holidays</field>
|
||||
<field model="ir.model" name="model_id" ref="model_hr_holidays"/>
|
||||
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
|
||||
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="property_rule_holidays_officer" model="ir.rule">
|
||||
<field name="name">Holidays Officer</field>
|
||||
<field model="ir.model" name="model_id" ref="model_hr_holidays"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4,ref('base.group_hr_user'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
# Mongolian translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
|
||||
"PO-Revision-Date: 2012-08-31 07:21+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Mongolian <mn@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-09-01 04:55+0000\n"
|
||||
"X-Generator: Launchpad (build 15890)\n"
|
||||
|
||||
#. module: import_google
|
||||
#: help:synchronize.google.import,group_name:0
|
||||
msgid "Choose which group to import, By default it takes all."
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:synchronize.google.import:0
|
||||
msgid "Import Google Calendar Events"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:synchronize.google.import:0
|
||||
msgid "_Import Events"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google_data.py:71
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No Google Username or password Defined for user.\n"
|
||||
"Please define in user view"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google_data.py:127
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Invalid login detail !\n"
|
||||
" Specify Username/Password."
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: field:synchronize.google.import,supplier:0
|
||||
msgid "Supplier"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:synchronize.google.import:0
|
||||
msgid "Import Options"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: field:synchronize.google.import,group_name:0
|
||||
msgid "Group Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: model:ir.model,name:import_google.model_crm_case_categ
|
||||
msgid "Category of Case"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: model:ir.actions.act_window,name:import_google.act_google_login_contact_form
|
||||
#: model:ir.ui.menu,name:import_google.menu_sync_contact
|
||||
msgid "Import Google Contacts"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:google.import.message:0
|
||||
msgid "Import Google Data"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:crm.meeting:0
|
||||
msgid "Meeting Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google.py:38
|
||||
#: code:addons/import_google/wizard/import_google_data.py:28
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please install gdata-python-client from http://code.google.com/p/gdata-"
|
||||
"python-client/downloads/list"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: model:ir.model,name:import_google.model_google_login
|
||||
msgid "Google Contact"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:synchronize.google.import:0
|
||||
msgid "Import contacts from a google account"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google_data.py:133
|
||||
#, python-format
|
||||
msgid "Please specify correct user and password !"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: field:synchronize.google.import,customer:0
|
||||
msgid "Customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:synchronize.google.import:0
|
||||
msgid "_Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: model:ir.model,name:import_google.model_synchronize_google_import
|
||||
msgid "synchronize.google.import"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:synchronize.google.import:0
|
||||
msgid "_Import Contacts"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: model:ir.actions.act_window,name:import_google.act_google_login_form
|
||||
#: model:ir.ui.menu,name:import_google.menu_sync_calendar
|
||||
msgid "Import Google Calendar"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google_data.py:50
|
||||
#, python-format
|
||||
msgid "Import google"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google_data.py:127
|
||||
#: code:addons/import_google/wizard/import_google_data.py:133
|
||||
#, python-format
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google_data.py:71
|
||||
#, python-format
|
||||
msgid "Warning !"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: field:synchronize.google.import,create_partner:0
|
||||
msgid "Options"
|
||||
msgstr "Тохируулга"
|
||||
|
||||
#. module: import_google
|
||||
#: view:google.import.message:0
|
||||
msgid "_Ok"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: code:addons/import_google/wizard/import_google.py:38
|
||||
#: code:addons/import_google/wizard/import_google_data.py:28
|
||||
#, python-format
|
||||
msgid "Google Contacts Import Error!"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: model:ir.model,name:import_google.model_google_import_message
|
||||
msgid "Import Message"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: field:synchronize.google.import,calendar_name:0
|
||||
msgid "Calendar Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: help:synchronize.google.import,supplier:0
|
||||
msgid "Check this box to set newly created partner as Supplier."
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: selection:synchronize.google.import,create_partner:0
|
||||
msgid "Import only address"
|
||||
msgstr "Зөвхөн хаяг оруулах"
|
||||
|
||||
#. module: import_google
|
||||
#: field:crm.case.categ,user_id:0
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: view:synchronize.google.import:0
|
||||
msgid "Partner Status for this Group:"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: field:google.import.message,name:0
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: selection:synchronize.google.import,create_partner:0
|
||||
msgid "Create partner for each contact"
|
||||
msgstr ""
|
||||
|
||||
#. module: import_google
|
||||
#: help:synchronize.google.import,customer:0
|
||||
msgid "Check this box to set newly created partner as Customer."
|
||||
msgstr ""
|
||||
@@ -29,6 +29,7 @@ import decimal_precision as dp
|
||||
from tools.misc import currency
|
||||
from tools.translate import _
|
||||
from tools import config
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
class account_tax_code_template(osv.osv):
|
||||
|
||||
@@ -53,7 +54,7 @@ class account_tax_template(osv.osv):
|
||||
|
||||
def get_precision_tax():
|
||||
def change_digit_tax(cr):
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, 1, 'Account')
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, SUPERUSER_ID, 'Account')
|
||||
return (16, res+2)
|
||||
return change_digit_tax
|
||||
|
||||
@@ -91,7 +92,7 @@ class account_tax(osv.osv):
|
||||
|
||||
def get_precision_tax():
|
||||
def change_digit_tax(cr):
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, 1, 'Account')
|
||||
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, SUPERUSER_ID, 'Account')
|
||||
return (16, res+2)
|
||||
return change_digit_tax
|
||||
|
||||
|
||||
@@ -92,9 +92,8 @@ class mail_alias(osv.Model):
|
||||
_defaults = {
|
||||
'alias_defaults': '{}',
|
||||
'alias_user_id': lambda self,cr,uid,context: uid,
|
||||
|
||||
# looks better when creating new aliases - even if the field is informative only
|
||||
'alias_domain': lambda self,cr,uid,context: self._get_alias_domain(cr,1,[1],None,None)[1]
|
||||
'alias_domain': lambda self,cr,uid,context: self._get_alias_domain(cr, SUPERUSER_ID,[1],None,None)[1]
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
|
||||
@@ -102,12 +102,7 @@ class mail_notification(osv.Model):
|
||||
body_html = msg.body
|
||||
signature = msg.author_id and msg.author_id.user_ids[0].signature or ''
|
||||
if signature:
|
||||
signature_block = u'\n<pre>%s</pre>\n' % signature
|
||||
insertion_point = body_html.find('</html>')
|
||||
if insertion_point > -1:
|
||||
body_html = body_html[:insertion_point] + signature_block + body_html[insertion_point:]
|
||||
else:
|
||||
body_html += signature_block
|
||||
body_html = tools.append_content_to_html(body_html, signature)
|
||||
|
||||
towrite = {
|
||||
'mail_message_id': msg.id,
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_tree">
|
||||
<field name="name">mail.message.tree</field>
|
||||
<field name="name">mail.mail.tree</field>
|
||||
<field name="model">mail.mail</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Emails" colors="grey:state in ('sent', 'cancel');blue:state=='outgoing';red:state=='exception';black:state=='received'">
|
||||
@@ -113,15 +113,15 @@
|
||||
</record>
|
||||
|
||||
<record id="action_view_mail_mail" model="ir.actions.act_window">
|
||||
<field name="name">Messages</field>
|
||||
<field name="name">Emails</field>
|
||||
<field name="res_model">mail.mail</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'search_default_received': 1, 'search_default_type_email': 1}</field>
|
||||
<field name="context">{'search_default_outgoing': 1, 'search_default_type_email': 1}</field>
|
||||
<field name="search_view_id" ref="view_mail_search"/>
|
||||
</record>
|
||||
|
||||
<!-- Add menu entry in Settings/Email -->
|
||||
<menuitem name="Mails" id="menu_mail_mail" parent="base.menu_email" action="action_view_mail_mail" />
|
||||
<menuitem name="Emails" id="menu_mail_mail" parent="base.menu_email" action="action_view_mail_mail" />
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+18
-32
@@ -167,12 +167,10 @@ class mail_message(osv.Model):
|
||||
|
||||
def message_read_tree_flatten(self, cr, uid, messages, current_level, level, context=None):
|
||||
""" Given a tree with several roots of following structure :
|
||||
[
|
||||
{'id': 1, 'child_ids':[
|
||||
{'id': 11, 'child_ids': [...] },
|
||||
] },
|
||||
{...}
|
||||
]
|
||||
[ {'id': 1, 'child_ids': [
|
||||
{'id': 11, 'child_ids': [...] },],
|
||||
},
|
||||
{...} ]
|
||||
Flatten it to have a maximum number of level, with 0 being
|
||||
completely flat.
|
||||
Perform the flattening at leafs if above the maximum depth, then get
|
||||
@@ -187,40 +185,29 @@ class mail_message(osv.Model):
|
||||
return [msg_dict] + child_ids
|
||||
# Depth-first flattening
|
||||
for message in messages:
|
||||
if message.get('type') == 'expandable':
|
||||
continue
|
||||
message['child_ids'] = self.message_read_tree_flatten(cr, uid, message['child_ids'], current_level+1, level, context=context)
|
||||
# Flatten if above maximum depth
|
||||
if current_level < level:
|
||||
return messages
|
||||
new_list = []
|
||||
for x in range(0, len(messages)):
|
||||
flatenned = _flatten(messages[x])
|
||||
for flat in flatenned:
|
||||
new_list.append(flat)
|
||||
messages = new_list
|
||||
return messages
|
||||
|
||||
def _debug_print_tree(self, tree, prefix=''):
|
||||
for elem in tree:
|
||||
print '%s%s (%s childs: %s)' % (prefix, elem['id'], len(elem['child_ids']), [xelem['id'] for xelem in elem['child_ids']])
|
||||
if elem['child_ids']:
|
||||
self._debug_print_tree(elem['child_ids'], prefix+'--')
|
||||
for message in messages:
|
||||
for flat_message in _flatten(message):
|
||||
new_list.append(flat_message)
|
||||
return new_list
|
||||
|
||||
def message_read(self, cr, uid, ids=False, domain=[], thread_level=0, limit=None, context=None):
|
||||
"""
|
||||
If IDS are provided, fetch these records, otherwise use the domain to
|
||||
fetch the matching records. After having fetched the records provided
|
||||
by IDS, it will fetch children (according to thread_level).
|
||||
|
||||
Return [
|
||||
|
||||
]
|
||||
""" If IDs are provided, fetch these records. Otherwise use the domain
|
||||
to fetch the matching records.
|
||||
After having fetched the records provided by IDs, it will fetch the
|
||||
parents to have well-formed threads.
|
||||
:return list: list of trees of messages
|
||||
"""
|
||||
limit = limit or self._message_read_limit
|
||||
context = context or {}
|
||||
if ids is False:
|
||||
if not ids:
|
||||
ids = self.search(cr, uid, domain, context=context, limit=limit)
|
||||
|
||||
# FP Todo: flatten to max X level of mail_thread
|
||||
messages = self.browse(cr, uid, ids, context=context)
|
||||
|
||||
result = []
|
||||
@@ -253,9 +240,8 @@ class mail_message(osv.Model):
|
||||
break
|
||||
|
||||
# Flatten the result
|
||||
# if thread_level > 0:
|
||||
# result = self.message_read_tree_flatten(cr, uid, result, 0, thread_level, context=context)
|
||||
|
||||
if thread_level > 0:
|
||||
result = self.message_read_tree_flatten(cr, uid, result, 0, thread_level, context=context)
|
||||
return result
|
||||
|
||||
#------------------------------------------------------
|
||||
|
||||
@@ -208,10 +208,11 @@ class mail_thread(osv.Model):
|
||||
# mail.message wrappers and tools
|
||||
#------------------------------------------------------
|
||||
|
||||
def _needaction_domain_get(self, cr, uid, context={}):
|
||||
def _needaction_domain_get(self, cr, uid, context=None):
|
||||
if self._needaction:
|
||||
return [('message_unread', '=', True)]
|
||||
return []
|
||||
|
||||
#------------------------------------------------------
|
||||
# Mail gateway
|
||||
#------------------------------------------------------
|
||||
@@ -460,29 +461,15 @@ class mail_thread(osv.Model):
|
||||
continue
|
||||
# 2) text/plain -> <pre/>
|
||||
if part.get_content_type() == 'text/plain' and (not alternative or not body):
|
||||
insertion_point = body.find('</html>')
|
||||
# plain text is wrapped in <pre/> to preserve formatting
|
||||
text = u'<pre>%s</pre>' % tools.ustr(part.get_payload(decode=True),
|
||||
encoding, errors='replace')
|
||||
if insertion_point != -1:
|
||||
body = body[:insertion_point] + text + body[insertion_point:]
|
||||
else:
|
||||
body += text
|
||||
body = tools.append_content_to_html(body, tools.ustr(part.get_payload(decode=True),
|
||||
encoding, errors='replace'))
|
||||
# 3) text/html -> raw
|
||||
elif part.get_content_type() == 'text/html':
|
||||
html = tools.ustr(part.get_payload(decode=True), encoding, errors='replace')
|
||||
if alternative:
|
||||
body = html
|
||||
# force </html> tag to lowercase, for easier matching
|
||||
body = re.sub(r'(?i)</html>', r'</html>', body)
|
||||
else:
|
||||
# strip enclosing html/body tags and append to existing body
|
||||
html = re.sub(r'(?i)(</?html>|</?body>)', '', html)
|
||||
insertion_point = body.find('</html>')
|
||||
if insertion_point != -1:
|
||||
body = body[:insertion_point] + html + body[insertion_point:]
|
||||
else:
|
||||
body += html
|
||||
body = tools.append_content_to_html(body, html, plaintext=False)
|
||||
# 4) Anything else -> attachment
|
||||
else:
|
||||
attachments.append((filename or 'attachment', part.get_payload(decode=True)))
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.tests import common
|
||||
import base64
|
||||
import tools
|
||||
|
||||
from openerp.tests import common
|
||||
|
||||
MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
|
||||
To: {to}
|
||||
Received: by mail1.openerp.com (Postfix, from userid 10002)
|
||||
@@ -246,10 +248,10 @@ class test_mail(common.TransactionCase):
|
||||
_body2 = '<html>Pigs rules</html>'
|
||||
_mail_body2 = '<html>Pigs rules\n<pre>Admin</pre>\n</html>'
|
||||
_mail_bodyalt2 = 'Pigs rules\nAdmin\n'
|
||||
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
|
||||
|
||||
# Post comment with body and subject, comment preference
|
||||
# CASE1: post comment, body and subject specified
|
||||
msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, msg_type='comment')
|
||||
# Fetch: created mail_message, mail_mail, sent_email
|
||||
message = self.mail_message.browse(cr, uid, msg_id)
|
||||
mail_ids = self.mail_mail.search(cr, uid, [], limit=1)
|
||||
mail = self.mail_mail.browse(cr, uid, mail_ids[0])
|
||||
@@ -262,7 +264,7 @@ class test_mail(common.TransactionCase):
|
||||
self.assertEqual(mail.subject, _subject, 'mail.mail subject incorrect')
|
||||
self.assertEqual(mail.body_html, _mail_body1, 'mail.mail body_html incorrect')
|
||||
self.assertEqual(mail.mail_message_id.id, msg_id, 'mail_mail.mail_message_id is not the id of its related mail_message)')
|
||||
# Test: sent_email: email send by server: correct subject and body
|
||||
# Test: sent_email: email send by server: correct subject, body; body_alternative
|
||||
self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
|
||||
self.assertEqual(sent_email['body'], _mail_body1, 'sent_email body incorrect')
|
||||
self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1, 'sent_email body_alternative is incorrect')
|
||||
@@ -277,23 +279,24 @@ class test_mail(common.TransactionCase):
|
||||
# Test: sent_email: email_to should contain b@b, not c@c (pref email), not a@a (writer)
|
||||
self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect')
|
||||
|
||||
# New post: test automatic subject, signature in html, add a partner, email preference, parent_id previous message
|
||||
msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, msg_type='email', partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id)
|
||||
# Fetch: created mail_message, mail_mail, sent_email
|
||||
# CASE2: post an email with attachments, parent_id, partner_ids
|
||||
# TESTS: automatic subject, signature in body_html, attachments propagation
|
||||
msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, msg_type='email',
|
||||
partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id, attachments=_attachments)
|
||||
message = self.mail_message.browse(cr, uid, msg_id2)
|
||||
mail_ids = self.mail_mail.search(cr, uid, [], limit=1)
|
||||
mail = self.mail_mail.browse(cr, uid, mail_ids[0])
|
||||
sent_email = self._build_email_kwargs
|
||||
|
||||
# Test: mail_message: subject is False, body is _body1 (no formatting done), parent_id is msg_id
|
||||
# Test: mail_message: subject is False, body is _body2 (no formatting done), parent_id is msg_id
|
||||
self.assertEqual(message.subject, False, 'mail.message subject incorrect')
|
||||
self.assertEqual(message.body, _body2, 'mail.message body incorrect')
|
||||
self.assertEqual(message.parent_id.id, msg_id, 'mail.message parent_id incorrect')
|
||||
# Test: mail_mail: subject is False, body_html is _mail_body1 (signature appended)
|
||||
# Test: mail_mail: subject is False, body_html is _mail_body2 (signature appended)
|
||||
self.assertEqual(mail.subject, False, 'mail.mail subject is incorrect')
|
||||
self.assertEqual(mail.body_html, _mail_body2, 'mail.mail body_html incorrect')
|
||||
self.assertEqual(mail.mail_message_id.id, msg_id2, 'mail_mail.mail_message_id incorrect')
|
||||
# Test: sent_email: email send by server: correct subject and body
|
||||
# Test: sent_email: email send by server: correct subject, body, body_alternative
|
||||
self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect')
|
||||
self.assertEqual(sent_email['body'], _mail_body2, 'sent_email body incorrect')
|
||||
self.assertEqual(sent_email['body_alternative'], _mail_bodyalt2, 'sent_email body_alternative incorrect')
|
||||
@@ -301,17 +304,20 @@ class test_mail(common.TransactionCase):
|
||||
message_pids = set([partner.id for partner in message.partner_ids])
|
||||
test_pids = set([p_a_id, p_b_id, p_c_id, p_d_id])
|
||||
self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect')
|
||||
# Test: notification linked to this message = group followers = partner_ids
|
||||
# Test: notifications linked to this message = group followers = partner_ids
|
||||
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
||||
notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
|
||||
self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
|
||||
# Test: sent_email: email_to should contain b@b, c@c, not a@a (writer)
|
||||
self.assertEqual(set(sent_email['email_to']), set(['b@b', 'c@c']), 'sent_email email_to incorrect')
|
||||
# Test: attachments
|
||||
for i in range(len(message.attachment_ids)):
|
||||
self.assertEqual(message.attachment_ids[i].name, _attachments[i][0], 'mail.message attachment name incorrect')
|
||||
self.assertEqual(message.attachment_ids[i].res_model, 'mail.group', 'mail.message attachment res_model incorrect')
|
||||
self.assertEqual(message.attachment_ids[i].res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
|
||||
self.assertEqual(base64.b64decode(message.attachment_ids[i].datas), _attachments[i][1], 'mail.message attachment data incorrect')
|
||||
|
||||
def test_21_message_post_attachments(self):
|
||||
""" Tests designed for attachments. """
|
||||
|
||||
def test_22_message_compose_wizard(self):
|
||||
def test_21_message_compose_wizard(self):
|
||||
""" Tests designed for the mail.compose.message wizard. """
|
||||
cr, uid = self.cr, self.uid
|
||||
mail_compose = self.registry('mail.compose.message')
|
||||
@@ -321,11 +327,16 @@ class test_mail(common.TransactionCase):
|
||||
|
||||
# Mail data
|
||||
_subject = 'Pigs'
|
||||
_subject_reply = 'Re: Pigs'
|
||||
_mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)
|
||||
_body_text = 'Pigs rules'
|
||||
_msg_body1 = '<pre>Pigs rules</pre>'
|
||||
_body_html = '<html>Pigs rules</html>'
|
||||
_msg_body2 = '<html>Pigs rules</html>'
|
||||
_attachments = [
|
||||
{'name': 'First', 'datas': base64.b64encode('My first attachment')},
|
||||
{'name': 'Second', 'datas': base64.b64encode('My second attachment')}
|
||||
]
|
||||
|
||||
# Create partners
|
||||
# 0 - Admin
|
||||
@@ -340,46 +351,59 @@ class test_mail(common.TransactionCase):
|
||||
# Subscribe #1
|
||||
group_pigs.message_subscribe([p_b_id])
|
||||
|
||||
# Comment group_pigs: body_text
|
||||
# CASE1: comment group_pigs with body_text and subject
|
||||
compose_id = mail_compose.create(cr, uid,
|
||||
{'subject': _subject, 'body_text': _body_text, 'partner_ids': [(4, p_c_id), (4, p_d_id)]},
|
||||
{'mail.compose.message.mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id})
|
||||
compose = mail_compose.browse(cr, uid, compose_id)
|
||||
|
||||
# Test: model, res_id
|
||||
self.assertTrue(compose.model == 'mail.group' and compose.res_id == self.group_pigs_id,
|
||||
'mail.compose.message has model %s and res_id %s; should be mail.group and %s' % (compose.model, compose.res_id, self.group_pigs_id))
|
||||
# Test: mail.compose.message: model, res_id
|
||||
self.assertEqual(compose.model, 'mail.group', 'mail.compose.message incorrect model')
|
||||
self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
|
||||
|
||||
# Post the comment, get created message
|
||||
mail_compose.send_mail(cr, uid, [compose_id])
|
||||
group_pigs.refresh()
|
||||
msg = group_pigs.message_ids[0]
|
||||
message = group_pigs.message_ids[0]
|
||||
|
||||
# Test: mail.message: subject, body inside pre
|
||||
self.assertTrue(msg.subject == False and msg.body == _msg_body1,
|
||||
'mail.message subject is %s, body is %s; should be %s and %s' % (msg.subject, msg.body, False, _msg_body1))
|
||||
# Test: mail.message partners = notified people: group_pigs followers (a, b) + mail.compose.message partner_ids (c, d)
|
||||
msg_pids = [partner.id for partner in msg.partner_ids]
|
||||
self.assertEqual(message.subject, False, 'mail.message incorrect subject')
|
||||
self.assertEqual(message.body, _msg_body1, 'mail.message incorrect body')
|
||||
# Test: mail.message: partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d)
|
||||
msg_pids = [partner.id for partner in message.partner_ids]
|
||||
test_pids = [p_a_id, p_b_id, p_c_id, p_d_id]
|
||||
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', msg.id)])
|
||||
self.assertTrue(len(msg_pids) == 4, 'There are %s partners linked to the newly posted comment; should be 4' % (len(msg_pids)))
|
||||
self.assertTrue(len(notif_ids) == 4, 'There are %s entries in mail_notification: should be 4' % (len(notif_ids)))
|
||||
self.assertTrue(all(id in msg_pids for id in test_pids) and len(msg_pids) == len(test_pids),
|
||||
'Admin, Bert Raoul and Roger should be the 4 partners of the newly created message')
|
||||
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
||||
self.assertEqual(len(notif_ids), 4, 'mail.message: too much notifications created')
|
||||
self.assertEqual(set(msg_pids), set(test_pids), 'mail.message partner_ids incorrect')
|
||||
|
||||
# Create a reply to the last comment
|
||||
# CASE2: reply to last comment (update its subject) with attachments
|
||||
message.write({'subject': _subject})
|
||||
compose_id = mail_compose.create(cr, uid,
|
||||
{}, {'mail.compose.message.mode': 'reply', 'default_model': 'mail.thread', 'default_res_id': self.group_pigs_id,
|
||||
'active_id': msg.id})
|
||||
{'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])]},
|
||||
{'mail.compose.message.mode': 'reply', 'default_model': 'mail.thread', 'default_res_id': self.group_pigs_id, 'active_id': message.id})
|
||||
compose = mail_compose.browse(cr, uid, compose_id)
|
||||
|
||||
# Test: model, res_id, parent_id
|
||||
self.assertTrue(compose.model == 'mail.group' and compose.res_id == self.group_pigs_id,
|
||||
'Wizard message has model: %s and res_id:%s; should be mail.group and %s' % (compose.model, compose.res_id, self.group_pigs_id))
|
||||
self.assertEqual(compose.parent_id.id, msg.id,
|
||||
'Wizard parent_id is %d; should be %d' % (compose.parent_id.id, msg.id))
|
||||
# Test: form view methods
|
||||
# Test: model, res_id, parent_id, content_subtype
|
||||
self.assertEqual(compose.model, 'mail.group', 'mail.compose.message incorrect model')
|
||||
self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
|
||||
self.assertEqual(compose.parent_id.id, message.id, 'mail.compose.message incorrect parent_id')
|
||||
self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message incorrect content_subtype')
|
||||
|
||||
# 3 - Create in mass_mail composition mode that should work with or without email_template installed
|
||||
# Post the comment, get created message
|
||||
mail_compose.send_mail(cr, uid, [compose_id])
|
||||
group_pigs.refresh()
|
||||
message = group_pigs.message_ids[0]
|
||||
# Test: subject as Re:.., body in html
|
||||
self.assertEqual(message.subject, _subject_reply, 'mail.message incorrect subject')
|
||||
self.assertIn('Administrator wrote:<blockquote><pre>Pigs rules</pre></blockquote></div>', message.body, 'mail.message body is incorrect')
|
||||
# Test: attachments
|
||||
for i in range(len(message.attachment_ids)):
|
||||
self.assertEqual(message.attachment_ids[i].name, _attachments[i]['name'], 'mail.message attachment name incorrect')
|
||||
self.assertEqual(message.attachment_ids[i].res_model, 'mail.group', 'mail.message attachment res_model incorrect')
|
||||
self.assertEqual(message.attachment_ids[i].res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
|
||||
self.assertEqual(base64.b64decode(message.attachment_ids[i].datas), base64.b64decode(_attachments[i]['datas']), 'mail.message attachment data incorrect')
|
||||
|
||||
# CASE3 - Create in mass_mail composition mode that should work with or without email_template installed
|
||||
compose_id = mail_compose.create(cr, uid,
|
||||
{'subject': _subject, 'body': '${object.description}'},
|
||||
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': -1,
|
||||
@@ -389,27 +413,16 @@ class test_mail(common.TransactionCase):
|
||||
# Post the comment, get created message
|
||||
mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id]})
|
||||
group_pigs.refresh()
|
||||
msg = group_pigs.message_ids[0]
|
||||
|
||||
message = group_pigs.message_ids[0]
|
||||
# Test: last message on Pigs = last created message
|
||||
test_msg = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [], limit=1))[0]
|
||||
self.assertEqual(msg.id, test_msg.id, 'Pigs did not receive its mass mailing message')
|
||||
self.assertEqual(message.id, test_msg.id, 'Pigs did not receive its mass mailing message')
|
||||
# Test: mail.message: subject, body
|
||||
self.assertEqual(msg.subject, _subject, 'mail.message subject is incorrect')
|
||||
self.assertEqual(msg.body, group_pigs.description, 'mail.message body is incorrect')
|
||||
|
||||
self.assertEqual(message.subject, _subject, 'mail.message subject is incorrect')
|
||||
self.assertEqual(message.body, group_pigs.description, 'mail.message body is incorrect')
|
||||
|
||||
def test_30_message_read(self):
|
||||
""" Tests designed for message_read. """
|
||||
def _simplify_struct(read_dict):
|
||||
res = []
|
||||
for val in read_dict:
|
||||
current = {'_id': val['id']}
|
||||
if val.get('child_ids'):
|
||||
current['child_ids'] = _simplify_struct(val.get('child_ids'))
|
||||
res.append(current)
|
||||
return res
|
||||
|
||||
# TDE NOTE: this test is not finished, as the message_read method is not fully specified.
|
||||
# It wil be updated as soon as we have fixed specs !
|
||||
cr, uid = self.cr, self.uid
|
||||
@@ -417,38 +430,31 @@ class test_mail(common.TransactionCase):
|
||||
|
||||
# Test message_read_tree_flatten that flattens a thread according to a given thread_level
|
||||
import copy
|
||||
tree = [
|
||||
{'id': 1, 'child_ids':[
|
||||
{'id': 3, 'child_ids': [] },
|
||||
{'id': 4, 'child_ids': [
|
||||
{'id': 5, 'child_ids': []},
|
||||
{'id': 12, 'child_ids': []},
|
||||
tree = [{'id': 1, 'child_ids':[
|
||||
{'id': 3, 'child_ids': [] },
|
||||
{'id': 4, 'child_ids': [
|
||||
{'id': 5, 'child_ids': []},
|
||||
{'id': 12, 'child_ids': []},
|
||||
] },
|
||||
{'id': 8, 'child_ids': [
|
||||
{'id': 10, 'child_ids': []},
|
||||
] },
|
||||
] },
|
||||
{'id': 8, 'child_ids': [
|
||||
{'id': 10, 'child_ids': []},
|
||||
{'id': 2, 'child_ids': [
|
||||
{'id': 7, 'child_ids': [
|
||||
{'id': 9, 'child_ids': []},
|
||||
] },
|
||||
] },
|
||||
] },
|
||||
{'id': 2, 'child_ids': [
|
||||
{'id': 7, 'child_ids': [
|
||||
{'id': 9, 'child_ids': []},
|
||||
{'id': 6, 'child_ids': [
|
||||
{'id': 11, 'child_ids': [] },
|
||||
] },
|
||||
] },
|
||||
{'id': 6, 'child_ids': [
|
||||
{'id': 11, 'child_ids': [] },
|
||||
] },
|
||||
]
|
||||
]
|
||||
new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 0)
|
||||
# self.mail_message._debug_print_tree(new_tree)
|
||||
# print '-------------------'
|
||||
self.assertTrue(len(new_tree) == 12, 'Flattening wrongly produced')
|
||||
new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 1)
|
||||
# self.mail_message._debug_print_tree(new_tree)
|
||||
# print '-------------------'
|
||||
self.assertTrue(len(new_tree) == 3 and len(new_tree[0]['child_ids']) == 6 and len(new_tree[1]['child_ids']) == 2 and len(new_tree[2]['child_ids']) == 1,
|
||||
'Flattening wrongly produced')
|
||||
new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 2)
|
||||
# self.mail_message._debug_print_tree(new_tree)
|
||||
# print '-------------------'
|
||||
self.assertTrue(len(new_tree) == 3 and len(new_tree[0]['child_ids']) == 3 and len(new_tree[0]['child_ids'][1]) == 2,
|
||||
'Flattening wrongly produced')
|
||||
|
||||
@@ -468,12 +474,10 @@ class test_mail(common.TransactionCase):
|
||||
|
||||
# Second try: read with thread_level 1
|
||||
tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=1)
|
||||
# self.mail_message._debug_print_tree(tree)
|
||||
self.assertTrue(len(tree) == 2 and len(tree[1]['child_ids']) == 3, 'Incorrect number of child in message_read')
|
||||
|
||||
# Third try: read with thread_level 2
|
||||
tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=2)
|
||||
# self.mail_message._debug_print_tree(tree)
|
||||
self.assertTrue(len(tree) == 2 and len(tree[1]['child_ids']) == 2 and len(tree[1]['child_ids'][0]['child_ids']) == 1, 'Incorrect number of child in message_read')
|
||||
|
||||
def test_40_needaction(self):
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import base64
|
||||
import re
|
||||
import tools
|
||||
|
||||
@@ -71,12 +72,12 @@ class mail_compose_message(osv.TransientModel):
|
||||
composition_mode = context.get('default_composition_mode', context.get('mail.compose.message.mode'))
|
||||
model = context.get('default_model', context.get('active_model'))
|
||||
res_id = context.get('default_res_id', context.get('active_id'))
|
||||
active_id = context.get('active_id')
|
||||
message_id = context.get('default_parent_id', context.get('message_id', context.get('active_id')))
|
||||
active_ids = context.get('active_ids')
|
||||
|
||||
# get default values according to the composition mode
|
||||
if composition_mode == 'reply':
|
||||
vals = self.get_message_data(cr, uid, active_id, context=context)
|
||||
vals = self.get_message_data(cr, uid, message_id, context=context)
|
||||
elif composition_mode == 'comment' and model and res_id:
|
||||
vals = self.get_record_data(cr, uid, model, res_id, context=context)
|
||||
elif composition_mode == 'mass_mail' and model and active_ids:
|
||||
@@ -154,7 +155,7 @@ class mail_compose_message(osv.TransientModel):
|
||||
message_data = self.pool.get('mail.message').browse(cr, uid, message_id, context=context)
|
||||
|
||||
# create subject
|
||||
re_prefix = _("Re:")
|
||||
re_prefix = _('Re:')
|
||||
reply_subject = tools.ustr(message_data.subject or '')
|
||||
if not (reply_subject.startswith('Re:') or reply_subject.startswith(re_prefix)):
|
||||
reply_subject = "%s %s" % (re_prefix, reply_subject)
|
||||
@@ -162,7 +163,7 @@ class mail_compose_message(osv.TransientModel):
|
||||
reply_header = _('On %(date)s, %(sender_name)s wrote:') % {
|
||||
'date': message_data.date if message_data.date else '',
|
||||
'sender_name': message_data.author_id.name }
|
||||
reply_body = '<div>%s<blockquote>%s</blockquote></div>%s' % (reply_header, message_data.body, current_user.signature)
|
||||
reply_body = '<div>%s<blockquote>%s</blockquote></div>' % (reply_header, message_data.body)
|
||||
# get partner_ids from original message
|
||||
partner_ids = [partner.id for partner in message_data.partner_ids] if message_data.partner_ids else []
|
||||
|
||||
@@ -223,6 +224,22 @@ class mail_compose_message(osv.TransientModel):
|
||||
res.update(self._verify_partner_email(cr, uid, value[0][2], context=context))
|
||||
return res
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# Cascade delete all attachments, as they are owned by the composition wizard
|
||||
for wizard in self.read(cr, uid, ids, ['attachment_ids'], context=context):
|
||||
self.pool.get('ir.attachment').unlink(cr, uid, wizard['attachment_ids'], context=context)
|
||||
return super(mail_compose_message,self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def dummy(self, cr, uid, ids, context=None):
|
||||
""" TDE: defined to have buttons that do basically nothing. It is
|
||||
currently impossible to have buttons that do nothing special
|
||||
in views (if type not specified, considered as 'object'). """
|
||||
return True
|
||||
|
||||
#------------------------------------------------------
|
||||
# Wizard validation and send
|
||||
#------------------------------------------------------
|
||||
|
||||
def send_mail(self, cr, uid, ids, context=None):
|
||||
""" Process the wizard content and proceed with sending the related
|
||||
email(s), rendering any template patterns on the fly if needed. """
|
||||
@@ -242,19 +259,18 @@ class mail_compose_message(osv.TransientModel):
|
||||
'subject': wizard.subject if wizard.content_subtype == 'html' else False,
|
||||
'body': wizard.body if wizard.content_subtype == 'html' else '<pre>%s</pre>' % tools.ustr(wizard.body_text),
|
||||
'partner_ids': [(4, partner.id) for partner in wizard.partner_ids],
|
||||
'attachments': [(attach.datas_fname, attach.datas) for attach in wizard.attachment_ids],
|
||||
'attachments': [(attach.name or attach.datas_fname, base64.b64decode(attach.datas)) for attach in wizard.attachment_ids],
|
||||
}
|
||||
# mass mailing: render and override default values
|
||||
if mass_mail_mode and wizard.model:
|
||||
email_dict = self.render_message(cr, uid, wizard, wizard.model, res_id, context=context)
|
||||
post_values['subject'] = email_dict.get('subject', False)
|
||||
post_values['body'] = email_dict.get('body', '')
|
||||
if email_dict.get('partner_ids'):
|
||||
post_values['partner_ids'] += [(4, id) for id in email_dict.get('partner_ids')]
|
||||
if email_dict.get('attachments'):
|
||||
post_values['attachments'] += [(attach.datas_fname, attach.datas) for attach in email_dict.get('attachments')]
|
||||
new_partner_ids = email_dict.pop('partner_ids', [])
|
||||
post_values['partner_ids'] += new_partner_ids
|
||||
new_attachments = email_dict.pop('attachments', [])
|
||||
post_values['attachments'] += new_attachments
|
||||
post_values.update(email_dict)
|
||||
# post the message
|
||||
active_model_pool.message_post(cr, uid, res_ids, msg_type='comment', context=context, **post_values)
|
||||
active_model_pool.message_post(cr, uid, [res_id], msg_type='comment', context=context, **post_values)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -263,20 +279,9 @@ class mail_compose_message(osv.TransientModel):
|
||||
This method is meant to be inherited by email_template that will
|
||||
produce a more complete dictionary, with email_to, ...
|
||||
"""
|
||||
# TDE: TODO: to move into mail.compose.message in email template
|
||||
# mails = tools.email_split(email_dict.get('email_to', '')) + tools.email_split(email_dict.get('email_cc', ''))
|
||||
# for mail in mails:
|
||||
# partner_search_ids = self.pool.get('res.partner').search(cr, uid, [('email', 'ilike', email)], context=context)
|
||||
# if partner_search_ids:
|
||||
# partner_ids.append((4, 0, partner_search_ids[0]))
|
||||
# else:
|
||||
# partner_id = self.pool.get('res.partner').name_create(cr, uid, values['email_to'], context=context)
|
||||
# partner_ids.append((4, 0, partner_id))
|
||||
return {
|
||||
'subject': self.render_template(cr, uid, wizard.subject, model, res_id, context),
|
||||
'body': self.render_template(cr, uid, wizard.body, model, res_id, context),
|
||||
'partner_ids': [],
|
||||
'attachment_ids': [],
|
||||
}
|
||||
|
||||
def render_template(self, cr, uid, template, model, res_id, context=None):
|
||||
@@ -297,25 +302,10 @@ class mail_compose_message(osv.TransientModel):
|
||||
context = {}
|
||||
def merge(match):
|
||||
exp = str(match.group()[2:-1]).strip()
|
||||
result = eval(exp,
|
||||
{
|
||||
'user' : self.pool.get('res.users').browse(cr, uid, uid, context=context),
|
||||
'object' : self.pool.get(model).browse(cr, uid, res_id, context=context),
|
||||
'context': dict(context), # copy context to prevent side-effects of eval
|
||||
})
|
||||
if result in (None, False):
|
||||
return ""
|
||||
return tools.ustr(result)
|
||||
result = eval(exp, {
|
||||
'user' : self.pool.get('res.users').browse(cr, uid, uid, context=context),
|
||||
'object' : self.pool.get(model).browse(cr, uid, res_id, context=context),
|
||||
'context': dict(context), # copy context to prevent side-effects of eval
|
||||
})
|
||||
return result and tools.ustr(result) or ''
|
||||
return template and EXPRESSION_PATTERN.sub(merge, template)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# Cascade delete all attachments, as they are owned by the composition wizard
|
||||
for wizard in self.read(cr, uid, ids, ['attachment_ids'], context=context):
|
||||
self.pool.get('ir.attachment').unlink(cr, uid, wizard['attachment_ids'], context=context)
|
||||
return super(mail_compose_message,self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def dummy(self, cr, uid, ids, context=None):
|
||||
""" TDE: defined to have buttons that do basically nothing. It is
|
||||
currently impossible to have buttons that do nothing special
|
||||
in views (if type not specified, considered as 'object'). """
|
||||
return True
|
||||
|
||||
+5
-5
@@ -1047,27 +1047,27 @@ class mrp_production(osv.osv):
|
||||
# ---------------------------------------------------
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Manufacturing order has been <b>created</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Manufacturing order has been <b>created</b>."), subtype="new", context=context)
|
||||
return True
|
||||
|
||||
def action_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Manufacturing order has been <b>canceled</b>.")
|
||||
self.message_post(cr, uid, ids, body=message, context=context)
|
||||
self.message_post(cr, uid, ids, body=message, subtype="cancelled", context=context)
|
||||
return True
|
||||
|
||||
def action_ready_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Manufacturing order is <b>ready to produce</b>.")
|
||||
self.message_post(cr, uid, ids, body=message, context=context)
|
||||
self.message_post(cr, uid, ids, body=message, subtype="ready", context=context)
|
||||
return True
|
||||
|
||||
def action_in_production_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Manufacturing order is <b>in production</b>.")
|
||||
self.message_post(cr, uid, ids, body=message, context=context)
|
||||
self.message_post(cr, uid, ids, body=message, subtype="production", context=context)
|
||||
return True
|
||||
|
||||
def action_done_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Manufacturing order has been <b>done</b>.")
|
||||
self.message_post(cr, uid, ids, body=message, context=context)
|
||||
self.message_post(cr, uid, ids, body=message, subtype="closed", context=context)
|
||||
return True
|
||||
|
||||
def action_confirm_send_note(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -27,5 +27,38 @@ From the Manufacturing Settings, you can choose to compute production schedules
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="name">new</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_ready" model="mail.message.subtype">
|
||||
<field name="name">ready</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_production" model="mail.message.subtype">
|
||||
<field name="name">production</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="name">cancelled</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_closed" model="mail.message.subtype">
|
||||
<field name="name">closed</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp.model_mrp_production'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -30,5 +30,39 @@
|
||||
<field name="start_stop">done</field>
|
||||
</record>
|
||||
|
||||
<!-- SUBTYPE -->
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="name">new</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_started" model="mail.message.subtype">
|
||||
<field name="name">started</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_pending" model="mail.message.subtype">
|
||||
<field name="name">pending</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="name">cancelled</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_closed" model="mail.message.subtype">
|
||||
<field name="name">closed</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp_operations.model_mrp_production_workcenter_line'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -224,7 +224,7 @@ class mrp_production_workcenter_line(osv.osv):
|
||||
for workorder in self.browse(cr, uid, ids):
|
||||
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
|
||||
message = _("Work order has been <b>created</b> for production order <em>%s</em>.") % (prod.id.name)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, subtype="new", context=context)
|
||||
return True
|
||||
|
||||
def action_start_send_note(self, cr, uid, ids, context=None):
|
||||
@@ -232,7 +232,7 @@ class mrp_production_workcenter_line(osv.osv):
|
||||
for workorder in self.browse(cr, uid, ids):
|
||||
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
|
||||
message = _("Work order has been <b>started</b> for production order <em>%s</em>.") % (prod.id.name)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, subtype="started", context=context)
|
||||
return True
|
||||
|
||||
def action_done_send_note(self, cr, uid, ids, context=None):
|
||||
@@ -240,7 +240,7 @@ class mrp_production_workcenter_line(osv.osv):
|
||||
for workorder in self.browse(cr, uid, ids):
|
||||
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
|
||||
message = _("Work order has been <b>done</b> for production order <em>%s</em>.") % (prod.id.name)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, subtype="closed", context=context)
|
||||
return True
|
||||
|
||||
def action_pending_send_note(self, cr, uid, ids, context=None):
|
||||
@@ -248,7 +248,7 @@ class mrp_production_workcenter_line(osv.osv):
|
||||
for workorder in self.browse(cr, uid, ids):
|
||||
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
|
||||
message = _("Work order is <b>pending</b> for production order <em>%s</em>.") % (prod.id.name)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, subtype="pending", context=context)
|
||||
return True
|
||||
|
||||
def action_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
@@ -256,7 +256,7 @@ class mrp_production_workcenter_line(osv.osv):
|
||||
for workorder in self.browse(cr, uid, ids):
|
||||
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
|
||||
message = _("Work order has been <b>cancelled</b> for production order <em>%s</em>.") % (prod.id.name)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [workorder.id], body=message, subtype="cancelled", context=context)
|
||||
return True
|
||||
|
||||
mrp_production_workcenter_line()
|
||||
|
||||
@@ -43,6 +43,7 @@ The following topics should be covered by this module:
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'security/mrp_repair_security.xml',
|
||||
'mrp_repair_data.xml',
|
||||
'mrp_repair_sequence.xml',
|
||||
'wizard/mrp_repair_cancel_view.xml',
|
||||
'wizard/mrp_repair_make_invoice_view.xml',
|
||||
|
||||
@@ -571,40 +571,40 @@ class mrp_repair(osv.osv):
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for repair in self.browse(cr, uid, ids, context):
|
||||
message = _("Repair Order for <em>%s</em> has been <b>created</b>." % (repair.product_id.name))
|
||||
self.message_post(cr, uid, [repair.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [repair.id], body=message, subtype="new", context=context)
|
||||
return True
|
||||
|
||||
def set_start_send_note(self, cr, uid, ids, context=None):
|
||||
for repair in self.browse(cr, uid, ids, context):
|
||||
message = _("Repair Order for <em>%s</em> has been <b>started</b>." % (repair.product_id.name))
|
||||
self.message_post(cr, uid, [repair.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [repair.id], body=message, subtype="started", context=context)
|
||||
return True
|
||||
|
||||
def set_toinvoiced_send_note(self, cr, uid, ids, context=None):
|
||||
for repair in self.browse(cr, uid, ids, context):
|
||||
message = _("Draft Invoice of %s %s <b>waiting for validation</b>.") % (repair.invoice_id.amount_total, repair.invoice_id.currency_id.symbol)
|
||||
self.message_post(cr, uid, [repair.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [repair.id], body=message, subtype="pending", context=context)
|
||||
return True
|
||||
|
||||
def set_confirm_send_note(self, cr, uid, ids, context=None):
|
||||
for repair in self.browse(cr, uid, ids, context):
|
||||
message = _( "Repair Order for <em>%s</em> has been <b>accepted</b>." % (repair.product_id.name))
|
||||
self.message_post(cr, uid, [repair.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [repair.id], body=message, subtype="accepted", context=context)
|
||||
return True
|
||||
|
||||
def set_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Repair has been <b>cancelled</b>.")
|
||||
self.message_post(cr, uid, ids, body=message, context=context)
|
||||
self.message_post(cr, uid, ids, body=message, subtype="cancelled", context=context)
|
||||
return True
|
||||
|
||||
def set_ready_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Repair Order is now <b>ready</b> to repair.")
|
||||
self.message_post(cr, uid, ids, body=message, context=context)
|
||||
self.message_post(cr, uid, ids, body=message, subtype="ready", context=context)
|
||||
return True
|
||||
|
||||
def set_done_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Repair Order is <b>closed</b>.")
|
||||
self.message_post(cr, uid, ids, body=message, context=context)
|
||||
self.message_post(cr, uid, ids, body=message, subtype="closed", context=context)
|
||||
return True
|
||||
|
||||
mrp_repair()
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="name">new</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_started" model="mail.message.subtype">
|
||||
<field name="name">started</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_ready" model="mail.message.subtype">
|
||||
<field name="name">ready</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_pending" model="mail.message.subtype">
|
||||
<field name="name">pending</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_accepted" model="mail.message.subtype">
|
||||
<field name="name">accepted</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="name">cancelled</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_closed" model="mail.message.subtype">
|
||||
<field name="name">closed</field>
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('mrp_repair.model_mrp_repair'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,10 @@ class pos_session_opening(osv.osv_memory):
|
||||
'pos_state' : fields.selection(pos_session.POS_SESSION_STATE,
|
||||
'Session State', readonly=True),
|
||||
'show_config' : fields.boolean('Show Config', readonly=True),
|
||||
'pos_session_name' : fields.related('pos_session_id', 'name',
|
||||
type='char', size=64, readonly=True),
|
||||
'pos_session_username' : fields.related('pos_session_id', 'user_id', 'name',
|
||||
type='char', size=64, readonly=True)
|
||||
}
|
||||
|
||||
def open_ui(self, cr, uid, ids, context=None):
|
||||
@@ -66,7 +70,9 @@ class pos_session_opening(osv.osv_memory):
|
||||
def on_change_config(self, cr, uid, ids, config_id, context=None):
|
||||
result = {
|
||||
'pos_session_id': False,
|
||||
'pos_state': False
|
||||
'pos_state': False,
|
||||
'pos_session_username' : False,
|
||||
'pos_session_name' : False,
|
||||
}
|
||||
if not config_id:
|
||||
return {'value': result}
|
||||
@@ -76,8 +82,11 @@ class pos_session_opening(osv.osv_memory):
|
||||
('config_id', '=', config_id),
|
||||
], context=context)
|
||||
if session_ids:
|
||||
result['pos_state'] = proxy.browse(cr, uid, session_ids[0], context=context).state
|
||||
result['pos_session_id'] = session_ids[0]
|
||||
session = proxy.browse(cr, uid, session_ids[0], context=context)
|
||||
result['pos_state'] = session.state
|
||||
result['pos_session_id'] = session.id
|
||||
result['pos_session_name'] = session.name
|
||||
result['pos_session_username'] = session.user_id.name
|
||||
return {'value' : result}
|
||||
|
||||
def default_get(self, cr, uid, fieldnames, context=None):
|
||||
|
||||
@@ -44,6 +44,15 @@
|
||||
interface.
|
||||
</p>
|
||||
</div>
|
||||
<div attrs="{'invisible' : [('pos_state', '!=', 'opened')]}" class="oe_view_nocontent">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to continue the session.
|
||||
</p>
|
||||
<p>
|
||||
The session <field name="pos_session_name" class="oe_inline" /> (<field name="pos_session_username" class="oe_inline" />) is "<b><field name="pos_state" class="oe_inline" /></b>"<br/>
|
||||
You can continue sales from the touchscreen interface by clicking on "<b>Settings</b>" or close the cash register session ?
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -496,22 +496,22 @@ class procurement_order(osv.osv):
|
||||
return obj_id
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>created</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>created</b>."), subtype="new", context=context)
|
||||
|
||||
def confirm_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>confirmed</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>confirmed</b>."), subtype="confirmed", context=context)
|
||||
|
||||
def running_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been set to <b>running</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been set to <b>running</b>."), subtype="running", context=context)
|
||||
|
||||
def ready_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been set to <b>ready</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been set to <b>ready</b>."), subtype="ready", context=context)
|
||||
|
||||
def cancel_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>cancelled</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>cancelled</b>."), subtype="cancelled", context=context)
|
||||
|
||||
def done_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>done</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>done</b>."), subtype="closed", context=context)
|
||||
|
||||
procurement_order()
|
||||
|
||||
|
||||
@@ -28,5 +28,40 @@
|
||||
<field name="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Mail: mail.message.subtype
|
||||
-->
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_confirmed" model="mail.message.subtype">
|
||||
<field name="name">confirmed</field>
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_ready" model="mail.message.subtype">
|
||||
<field name="name">ready</field>
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_running" model="mail.message.subtype">
|
||||
<field name="name">running</field>
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_closed" model="mail.message.subtype">
|
||||
<field name="name">closed</field>
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('procurement.model_procurement_order'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -26,6 +26,7 @@ from osv import fields, osv
|
||||
from openerp.addons.resource.faces import task as Task
|
||||
import time
|
||||
from tools.translate import _
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
_TASK_STATE = [('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')]
|
||||
|
||||
@@ -853,7 +854,7 @@ class task(base_stage, osv.osv):
|
||||
if context is None: context = {}
|
||||
# read uom as admin to avoid access rights issues, e.g. for portal/share users,
|
||||
# this should be safe (no context passed to avoid side-effects)
|
||||
obj_tm = users_obj.browse(cr, 1, uid, context=context).company_id.project_time_mode_id
|
||||
obj_tm = users_obj.browse(cr, SUPERUSER_ID, uid, context=context).company_id.project_time_mode_id
|
||||
tm = obj_tm and obj_tm.name or 'Hours'
|
||||
|
||||
res = super(task, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu=submenu)
|
||||
|
||||
@@ -735,7 +735,7 @@ class purchase_order(osv.osv):
|
||||
return [('state','=','draft')]
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
return self.message_post(cr, uid, ids, body=_("Request for quotation <b>created</b>."), context=context)
|
||||
return self.message_post(cr, uid, ids, body=_("Request for quotation <b>created</b>."), subtype="new", context=context)
|
||||
|
||||
def confirm_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
@@ -753,20 +753,20 @@ class purchase_order(osv.osv):
|
||||
def invoice_send_note(self, cr, uid, ids, invoice_id, context=None):
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
for invoice in (inv for inv in order.invoice_ids if inv.id == invoice_id):
|
||||
self.message_post(cr, uid, [order.id], body=_("Draft Invoice of %s %s is <b>waiting for validation</b>.") % (invoice.amount_total, invoice.currency_id.symbol), context=context)
|
||||
self.message_post(cr, uid, [order.id], body=_("Draft Invoice of %s %s is <b>waiting for validation</b>.") % (invoice.amount_total, invoice.currency_id.symbol), subtype="pending", context=context)
|
||||
|
||||
def shipment_done_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("""Shipment <b>received</b>."""), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("""Shipment <b>received</b>."""), subtype="received", context=context)
|
||||
|
||||
def invoice_done_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Invoice <b>paid</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Invoice <b>paid</b>."), subtype="paid", context=context)
|
||||
|
||||
def draft_send_note(self, cr, uid, ids, context=None):
|
||||
return self.message_post(cr, uid, ids, body=_("Purchase Order has been set to <b>draft</b>."), context=context)
|
||||
|
||||
def cancel_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("Purchase Order for <em>%s</em> <b>cancelled</b>.") % (obj.partner_id.name), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("Purchase Order for <em>%s</em> <b>cancelled</b>.") % (obj.partner_id.name), subtype="cancelled", context=context)
|
||||
|
||||
purchase_order()
|
||||
|
||||
|
||||
@@ -49,5 +49,37 @@ You can also manage purchase requisitions, see also the Purchase Settings.</fiel
|
||||
model="ir.values"
|
||||
name="set"/>
|
||||
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="name">new</field>
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_paid" model="mail.message.subtype">
|
||||
<field name="name">paid</field>
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_pending" model="mail.message.subtype">
|
||||
<field name="name">pending</field>
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_received" model="mail.message.subtype">
|
||||
<field name="name">received</field>
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="name">cancelled</field>
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase.model_purchase_order'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -94,13 +94,13 @@ class purchase_requisition(osv.osv):
|
||||
self.message_post(cr, uid, ids, body=_("Draft Requisition has been <b>sent to suppliers</b>."), context=context)
|
||||
|
||||
def reset_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been set to <b>draft</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been set to <b>draft</b>."), subtype="new", context=context)
|
||||
|
||||
def done_to_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>done</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>done</b>."), subtype="closed", context=context)
|
||||
|
||||
def cancel_send_note(self, cr, uid, ids, context=None):
|
||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>cancelled</b>."), context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>cancelled</b>."), subtype="cancelled", context=context)
|
||||
|
||||
def _planned_date(self, requisition, delay=0.0):
|
||||
company = requisition.company_id
|
||||
@@ -184,7 +184,7 @@ class purchase_requisition(osv.osv):
|
||||
return res
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
return self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>created</b>."), context=context)
|
||||
return self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>created</b>."), subtype="new", context=context)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
requisition = super(purchase_requisition, self).create(cr, uid, vals, context=context)
|
||||
|
||||
@@ -1,10 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<function
|
||||
<function
|
||||
eval="('default',False,'warehouse_id', [('purchase.requisition', False)], ref('stock.warehouse0'), True, False, False, False, True)"
|
||||
id="purchase_default_set"
|
||||
model="ir.values"
|
||||
name="set"/>
|
||||
<!-- SUBTYPE -->
|
||||
<record id="mail.mail_subtype_closed" model="mail.message.subtype">
|
||||
<field name="name">closed</field>
|
||||
<field name="model_ids" eval="[(4,ref('purchase_requisition.model_purchase_requisition'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase_requisition.model_purchase_requisition'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase_requisition.model_purchase_requisition'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase_requisition.model_purchase_requisition'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase_requisition.model_purchase_requisition'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('purchase_requisition.model_purchase_requisition'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -55,7 +55,7 @@ If you need to manage your sales pipeline (leads, opportunities, phonecalls), yo
|
||||
<field name="model_ids" eval="[(4,ref('sale.model_sale_order'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancel" model="mail.message.subtype">
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="name">cancelled</field>
|
||||
<field name="model_ids" eval="[(4,ref('sale.model_sale_order'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
|
||||
@@ -7,30 +7,30 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 6.0dev\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-02-08 00:37+0000\n"
|
||||
"PO-Revision-Date: 2012-08-18 17:40+0000\n"
|
||||
"Last-Translator: Heling Yao <Unknown>\n"
|
||||
"PO-Revision-Date: 2012-08-31 14:59+0000\n"
|
||||
"Last-Translator: ccdos <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: 2012-08-28 06:07+0000\n"
|
||||
"X-Generator: Launchpad (build 15864)\n"
|
||||
"X-Launchpad-Export-Date: 2012-09-01 04:55+0000\n"
|
||||
"X-Generator: Launchpad (build 15890)\n"
|
||||
|
||||
#. module: sale_crm
|
||||
#: field:sale.order,categ_id:0
|
||||
msgid "Category"
|
||||
msgstr ""
|
||||
msgstr "分类"
|
||||
|
||||
#. module: sale_crm
|
||||
#: sql_constraint:sale.order:0
|
||||
msgid "Order Reference must be unique per Company!"
|
||||
msgstr ""
|
||||
msgstr "订单号必须在一个公司范围内唯一"
|
||||
|
||||
#. module: sale_crm
|
||||
#: code:addons/sale_crm/wizard/crm_make_sale.py:112
|
||||
#, python-format
|
||||
msgid "Converted to Sales Quotation(%s)."
|
||||
msgstr ""
|
||||
msgstr "转换为销售报价单(%s)。"
|
||||
|
||||
#. module: sale_crm
|
||||
#: view:crm.make.sale:0
|
||||
@@ -73,7 +73,7 @@ msgstr "在生成销售订单后检查是否关闭商机。"
|
||||
#. module: sale_crm
|
||||
#: view:board.board:0
|
||||
msgid "My Opportunities"
|
||||
msgstr ""
|
||||
msgstr "我的商机"
|
||||
|
||||
#. module: sale_crm
|
||||
#: view:crm.lead:0
|
||||
@@ -104,13 +104,13 @@ msgstr "关闭商机"
|
||||
#. module: sale_crm
|
||||
#: view:board.board:0
|
||||
msgid "My Planned Revenues by Stage"
|
||||
msgstr ""
|
||||
msgstr "这阶段我的计划收入"
|
||||
|
||||
#. module: sale_crm
|
||||
#: code:addons/sale_crm/wizard/crm_make_sale.py:110
|
||||
#, python-format
|
||||
msgid "Opportunity '%s' is converted to Quotation."
|
||||
msgstr ""
|
||||
msgstr "商机 '%s' 被转换为报价单"
|
||||
|
||||
#. module: sale_crm
|
||||
#: view:sale.order:0
|
||||
|
||||
@@ -8,14 +8,14 @@ msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-08 00:37+0000\n"
|
||||
"PO-Revision-Date: 2011-06-28 05:04+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"PO-Revision-Date: 2012-08-31 14:59+0000\n"
|
||||
"Last-Translator: ccdos <Unknown>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-08-28 06:34+0000\n"
|
||||
"X-Generator: Launchpad (build 15864)\n"
|
||||
"X-Launchpad-Export-Date: 2012-09-01 04:55+0000\n"
|
||||
"X-Generator: Launchpad (build 15890)\n"
|
||||
|
||||
#. module: sale_mrp
|
||||
#: help:mrp.production,sale_ref:0
|
||||
@@ -40,12 +40,12 @@ msgstr "销售名称"
|
||||
#. module: sale_mrp
|
||||
#: sql_constraint:mrp.production:0
|
||||
msgid "Reference must be unique per Company!"
|
||||
msgstr ""
|
||||
msgstr "编号必须在公司内唯一!"
|
||||
|
||||
#. module: sale_mrp
|
||||
#: constraint:mrp.production:0
|
||||
msgid "Order quantity cannot be negative or zero!"
|
||||
msgstr ""
|
||||
msgstr "订单数量不能是负数或者0!"
|
||||
|
||||
#. module: sale_mrp
|
||||
#: help:mrp.production,sale_name:0
|
||||
|
||||
@@ -23,6 +23,7 @@ import random
|
||||
import time
|
||||
from urllib import quote_plus
|
||||
import uuid
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
import simplejson
|
||||
|
||||
@@ -545,7 +546,7 @@ class share_wizard(osv.TransientModel):
|
||||
_logger.debug("Copying rule %s (%s) on model %s with domain: %s", rule.name, rule.id, model.model, rule.domain_force)
|
||||
else:
|
||||
# otherwise we can simply link the rule to keep it dynamic
|
||||
rule_obj.write(cr, 1, [rule.id], {
|
||||
rule_obj.write(cr, SUPERUSER_ID, [rule.id], {
|
||||
'groups': [(4,group_id)]
|
||||
})
|
||||
_logger.debug("Linking rule %s (%s) on model %s with domain: %s", rule.name, rule.id, model.model, rule.domain_force)
|
||||
|
||||
@@ -1379,13 +1379,13 @@ class stock_picking(osv.osv):
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s has been <b>created</b>.") % (self._get_document_type(obj.type)), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s has been <b>created</b>.") % (self._get_document_type(obj.type)), subtype="new", context=context)
|
||||
|
||||
def scrap_send_note(self, cr, uid, ids, quantity, uom, name, context=None):
|
||||
return self.message_post(cr, uid, ids, body= _("%s %s %s has been <b>moved to</b> scrap.") % (quantity, uom, name), context=context)
|
||||
return self.message_post(cr, uid, ids, body= _("%s %s %s has been <b>moved to</b> scrap.") % (quantity, uom, name), subtype="moved", context=context)
|
||||
|
||||
def back_order_send_note(self, cr, uid, ids, back_name, context=None):
|
||||
return self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_name), context=context)
|
||||
return self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_name), subtype="new", context=context)
|
||||
|
||||
def ship_done_send_note(self, cr, uid, ids, context=None):
|
||||
type_dict = {
|
||||
@@ -1394,11 +1394,11 @@ class stock_picking(osv.osv):
|
||||
'internal': 'moved',
|
||||
}
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("Products have been <b>%s</b>.") % (type_dict.get(obj.type, 'move done')), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("Products have been <b>%s</b>.") % (type_dict.get(obj.type, 'move done')), subtype=type_dict.get(obj.type), context=context)
|
||||
|
||||
def ship_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s has been <b>cancelled</b>.") % (self._get_document_type(obj.type)), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s has been <b>cancelled</b>.") % (self._get_document_type(obj.type)), subtype="cancelled", context=context)
|
||||
|
||||
|
||||
stock_picking()
|
||||
|
||||
@@ -166,5 +166,34 @@ watch your stock valuation, and track production lots upstream and downstream (b
|
||||
<field name="lot_stock_id" ref="stock_location_stock"/>
|
||||
<field name="lot_output_id" ref="stock_location_output"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Mail: mail.message.subtype
|
||||
-->
|
||||
<record id="mail.mail_subtype_new" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('stock.model_stock_picking_in')),(4,ref('stock.model_stock_picking_out'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_delivered" model="mail.message.subtype">
|
||||
<field name="name">delivered</field>
|
||||
<field name="model_ids" eval="[(4,ref('stock.model_stock_picking_out'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_received" model="mail.message.subtype">
|
||||
<field name="name">received</field>
|
||||
<field name="model_ids" eval="[(4,ref('stock.model_stock_picking_in'))]"/>
|
||||
<field name="default" eval="False"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_cancelled" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('stock.model_stock_picking_in')),(4,ref('stock.model_stock_picking_out'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_email" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('stock.model_stock_picking_in')),(4,ref('stock.model_stock_picking_out'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_comment" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('stock.model_stock_picking_in')),(4,ref('stock.model_stock_picking_out'))]"/>
|
||||
</record>
|
||||
<record id="mail.mail_subtype_other" model="mail.message.subtype">
|
||||
<field name="model_ids" eval="[(4,ref('stock.model_stock_picking_in')),(4,ref('stock.model_stock_picking_out'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
Reference in New Issue
Block a user