diff options
| author | Sanjay Gohel (Open ERP) <sgo@tinyerp.com> | 2012-09-04 15:02:50 +0530 |
|---|---|---|
| committer | Sanjay Gohel (Open ERP) <sgo@tinyerp.com> | 2012-09-04 15:02:50 +0530 |
| commit | 92b707c11697a67d2d09bbcdbd7f0a60e171e6bf (patch) | |
| tree | da4d1ed756576e437d4565e07e5a59d66e09225e | |
| parent | 93f5c6b6a9265e30c7b7addb7eceeef57dbb7fb6 (diff) | |
| parent | d19d95fb185cbe077fa7043c78b7e9cdf5d596cc (diff) | |
[MERGE]merge with parent branch
bzr revid: sgo@tinyerp.com-20120904093250-fwawd23g26064wnl
75 files changed, 5019 insertions, 731 deletions
diff --git a/addons/account/account.py b/addons/account/account.py index 31fe7dbfb12..e11479e4dc0 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -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) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 42bcb785d61..5f81cbfe857 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -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): diff --git a/addons/account/data/account_data.xml b/addons/account/data/account_data.xml index e8899d0348a..bf3b3152552 100644 --- a/addons/account/data/account_data.xml +++ b/addons/account/data/account_data.xml @@ -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> diff --git a/addons/account_analytic_plans/i18n/nb.po b/addons/account_analytic_plans/i18n/nb.po new file mode 100644 index 00000000000..27a6c0d9e24 --- /dev/null +++ b/addons/account_analytic_plans/i18n/nb.po @@ -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 "" diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index f75cda8cdde..9d656c7607d 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -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() diff --git a/addons/account_voucher/account_voucher_data.xml b/addons/account_voucher/account_voucher_data.xml index 656d2c2cd91..a99a8735842 100644 --- a/addons/account_voucher/account_voucher_data.xml +++ b/addons/account_voucher/account_voucher_data.xml @@ -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> diff --git a/addons/analytic/analytic.py b/addons/analytic/analytic.py index d90e2006a71..2e6e5089c88 100644 --- a/addons/analytic/analytic.py +++ b/addons/analytic/analytic.py @@ -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() diff --git a/addons/audittrail/audittrail.py b/addons/audittrail/audittrail.py index aee9fbd9305..3dff7c1cb00 100644 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@ -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 diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py index 2959fa45db1..5d939f19db1 100644 --- a/addons/auth_oauth/controllers/main.py +++ b/addons/auth_oauth/controllers/main.py @@ -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: diff --git a/addons/auth_oauth/res_users.py b/addons/auth_oauth/res_users.py index 3dbab849942..b4f62612746 100644 --- a/addons/auth_oauth/res_users.py +++ b/addons/auth_oauth/res_users.py @@ -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 diff --git a/addons/auth_openid/controllers/main.py b/addons/auth_openid/controllers/main.py index eba711dae7a..ebcaab4bf25 100644 --- a/addons/auth_openid/controllers/main.py +++ b/addons/auth_openid/controllers/main.py @@ -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() diff --git a/addons/auth_reset_password/auth_reset_password.py b/addons/auth_reset_password/auth_reset_password.py index 3d1bcbbfa7b..ff208c89b9c 100644 --- a/addons/auth_reset_password/auth_reset_password.py +++ b/addons/auth_reset_password/auth_reset_password.py @@ -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') diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py index 0ed2151d12b..821ef44f459 100644 --- a/addons/auth_signup/controllers/main.py +++ b/addons/auth_signup/controllers/main.py @@ -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: diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py index 1d77a3f9473..5f6463508b6 100644 --- a/addons/auth_signup/res_users.py +++ b/addons/auth_signup/res_users.py @@ -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) diff --git a/addons/base_gengo/__init__.py b/addons/base_gengo/__init__.py new file mode 100644 index 00000000000..133fa90dc51 --- /dev/null +++ b/addons/base_gengo/__init__.py @@ -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: diff --git a/addons/base_gengo/__openerp__.py b/addons/base_gengo/__openerp__.py new file mode 100644 index 00000000000..ae61ad8f13c --- /dev/null +++ b/addons/base_gengo/__openerp__.py @@ -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: diff --git a/addons/base_gengo/gengo_sync_schedular_data.xml b/addons/base_gengo/gengo_sync_schedular_data.xml new file mode 100644 index 00000000000..823ca8f14db --- /dev/null +++ b/addons/base_gengo/gengo_sync_schedular_data.xml @@ -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> diff --git a/addons/base_gengo/ir_translation.py b/addons/base_gengo/ir_translation.py new file mode 100644 index 00000000000..7b864aba8ce --- /dev/null +++ b/addons/base_gengo/ir_translation.py @@ -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']) + ] diff --git a/addons/base_gengo/ir_translation.xml b/addons/base_gengo/ir_translation.xml new file mode 100644 index 00000000000..ba9667d979e --- /dev/null +++ b/addons/base_gengo/ir_translation.xml @@ -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> diff --git a/addons/base_gengo/res_company.py b/addons/base_gengo/res_company.py new file mode 100644 index 00000000000..22d7b343939 --- /dev/null +++ b/addons/base_gengo/res_company.py @@ -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, + } diff --git a/addons/base_gengo/res_company_view.xml b/addons/base_gengo/res_company_view.xml new file mode 100644 index 00000000000..0f99efc8ad0 --- /dev/null +++ b/addons/base_gengo/res_company_view.xml @@ -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> diff --git a/addons/base_gengo/wizard/__init__.py b/addons/base_gengo/wizard/__init__.py new file mode 100644 index 00000000000..f5dd71be01c --- /dev/null +++ b/addons/base_gengo/wizard/__init__.py @@ -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: diff --git a/addons/base_gengo/wizard/base_gengo_translations.py b/addons/base_gengo/wizard/base_gengo_translations.py new file mode 100644 index 00000000000..d8a96a2ced9 --- /dev/null +++ b/addons/base_gengo/wizard/base_gengo_translations.py @@ -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: diff --git a/addons/base_gengo/wizard/base_gengo_translations_view.xml b/addons/base_gengo/wizard/base_gengo_translations_view.xml new file mode 100644 index 00000000000..09c3a77b1d5 --- /dev/null +++ b/addons/base_gengo/wizard/base_gengo_translations_view.xml @@ -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> diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index b725a4ad988..801895885b2 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -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) diff --git a/addons/decimal_precision/decimal_precision.py b/addons/decimal_precision/decimal_precision.py index d9f6aa7b8db..93d69eb3093 100644 --- a/addons/decimal_precision/decimal_precision.py +++ b/addons/decimal_precision/decimal_precision.py @@ -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 diff --git a/addons/document_webdav/nodes.py b/addons/document_webdav/nodes.py index d6ceca458cd..a8fedee4fe3 100644 --- a/addons/document_webdav/nodes.py +++ b/addons/document_webdav/nodes.py @@ -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 diff --git a/addons/document_webdav/test_davclient.py b/addons/document_webdav/test_davclient.py index f1f2e58c835..0f66363c553 100755 --- a/addons/document_webdav/test_davclient.py +++ b/addons/document_webdav/test_davclient.py @@ -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'] diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py index d540971c3b4..73dc5ed2754 100644 --- a/addons/email_template/email_template.py +++ b/addons/email_template/email_template.py @@ -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, + 'subject': fields.char('Subject', translate=True, help="Subject (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('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, + '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, + '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)"), - '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)"), + '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 diff --git a/addons/email_template/email_template_view.xml b/addons/email_template/email_template_view.xml index cd75a719197..448655a3121 100644 --- a/addons/email_template/email_template_view.xml +++ b/addons/email_template/email_template_view.xml @@ -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"/> + </page> + <page string="Advanced"> + <group> + <field name="lang"/> <field name="mail_server_id"/> - <field name="track_campaign_item"/> - <field name="message_id"/> <field name="auto_delete"/> - <field name="lang"/> + <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"/> diff --git a/addons/email_template/security/ir.model.access.csv b/addons/email_template/security/ir.model.access.csv index d2d6adf3bf3..adce0420793 100644 --- a/addons/email_template/security/ir.model.access.csv +++ b/addons/email_template/security/ir.model.access.csv @@ -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
diff --git a/addons/email_template/tests/test_mail.py b/addons/email_template/tests/test_mail.py index db2168a75d5..5ca608e6b81 100644 --- a/addons/email_template/tests/test_mail.py +++ b/addons/email_template/tests/test_mail.py @@ -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')
\ No newline at end of file + # 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')
\ No newline at end of file diff --git a/addons/email_template/wizard/email_template_preview.py b/addons/email_template/wizard/email_template_preview.py index 2c1866a53c4..862c34cc426 100644 --- a/addons/email_template/wizard/email_template_preview.py +++ b/addons/email_template/wizard/email_template_preview.py @@ -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: diff --git a/addons/email_template/wizard/email_template_preview_view.xml b/addons/email_template/wizard/email_template_preview_view.xml index 708ca2b0406..f4f75567a42 100644 --- a/addons/email_template/wizard/email_template_preview_view.xml +++ b/addons/email_template/wizard/email_template_preview_view.xml @@ -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> diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py index 11e726c537b..71586649f37 100644 --- a/addons/email_template/wizard/mail_compose_message.py +++ b/addons/email_template/wizard/mail_compose_message.py @@ -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: diff --git a/addons/email_template/wizard/mail_compose_message_view.xml b/addons/email_template/wizard/mail_compose_message_view.xml index f54ee0d3723..228dcc2745a 100644 --- a/addons/email_template/wizard/mail_compose_message_view.xml +++ b/addons/email_template/wizard/mail_compose_message_view.xml @@ -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" diff --git a/addons/google_docs/static/src/js/gdocs.js b/addons/google_docs/static/src/js/gdocs.js index 8f41a9d7b21..694f5736c72 100644 --- a/addons/google_docs/static/src/js/gdocs.js +++ b/addons/google_docs/static/src/js/gdocs.js @@ -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 diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 75487983738..759170224bd 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -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" diff --git a/addons/hr_holidays/hr_holidays_demo.xml b/addons/hr_holidays/hr_holidays_demo.xml index 6ad5a442a38..4c9d18683c7 100644 --- a/addons/hr_holidays/hr_holidays_demo.xml +++ b/addons/hr_holidays/hr_holidays_demo.xml @@ -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> diff --git a/addons/hr_holidays/hr_holidays_view.xml b/addons/hr_holidays/hr_holidays_view.xml index 89ce641b271..699c08bd636 100644 --- a/addons/hr_holidays/hr_holidays_view.xml +++ b/addons/hr_holidays/hr_holidays_view.xml @@ -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> diff --git a/addons/hr_holidays/hr_holidays_workflow.xml b/addons/hr_holidays/hr_holidays_workflow.xml index 7013d62a5ed..a2e1d54f96c 100644 --- a/addons/hr_holidays/hr_holidays_workflow.xml +++ b/addons/hr_holidays/hr_holidays_workflow.xml @@ -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">True</field> + <field name="condition">not double_validation</field> <field name="group_id" ref="base.group_hr_user"/> </record> - <record model="workflow.transition" id="t3"> + <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">holidays_refuse('first_approval')</field> + <field name="condition">True</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> diff --git a/addons/hr_holidays/security/ir.model.access.csv b/addons/hr_holidays/security/ir.model.access.csv index b21b6ca64e4..0375a17ac53 100644 --- a/addons/hr_holidays/security/ir.model.access.csv +++ b/addons/hr_holidays/security/ir.model.access.csv @@ -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
diff --git a/addons/hr_holidays/security/ir_rule.xml b/addons/hr_holidays/security/ir_rule.xml index 8e8c97bf7ea..ff0270026a4 100644 --- a/addons/hr_holidays/security/ir_rule.xml +++ b/addons/hr_holidays/security/ir_rule.xml @@ -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> diff --git a/addons/import_google/i18n/mn.po b/addons/import_google/i18n/mn.po new file mode 100644 index 00000000000..9b0376c0d98 --- /dev/null +++ b/addons/import_google/i18n/mn.po @@ -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 "" diff --git a/addons/l10n_br/account.py b/addons/l10n_br/account.py index 6e38aaa690f..64d3c2cda79 100644 --- a/addons/l10n_br/account.py +++ b/addons/l10n_br/account.py @@ -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 diff --git a/addons/mail/mail_alias.py b/addons/mail/mail_alias.py index 5bcce0b8927..27eb29051b9 100644 --- a/addons/mail/mail_alias.py +++ b/addons/mail/mail_alias.py @@ -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 = [ diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index e7d6d0b7f0c..c813eaa5dc0 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -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, diff --git a/addons/mail/mail_mail_view.xml b/addons/mail/mail_mail_view.xml index dc4f68b22c7..f6846954ec0 100644 --- a/addons/mail/mail_mail_view.xml +++ b/addons/mail/mail_mail_view.xml @@ -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> diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index f324a0e2e8d..4a25a8aa0c9 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -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 #------------------------------------------------------ diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 241e6674b17..c7b4f333ebf 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -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))) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index c27b3c6f68e..6622930fbd2 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -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') - - def test_21_message_post_attachments(self): - """ Tests designed for attachments. """ - - def test_22_message_compose_wizard(self): + # 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_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): diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index e5748a723e6..d141b3cf1e0 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -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 diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index c667daadbec..a9f6290c58a 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -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): diff --git a/addons/mrp/mrp_data.xml b/addons/mrp/mrp_data.xml index 0bbf2d3b64c..6ee7cc82dd2 100644 --- a/addons/mrp/mrp_data.xml +++ b/addons/mrp/mrp_data.xml @@ -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> diff --git a/addons/mrp_operations/mrp_operation_data.xml b/addons/mrp_operations/mrp_operation_data.xml index ff83fdc7e8b..e2d7f9f0a56 100644 --- a/addons/mrp_operations/mrp_operation_data.xml +++ b/addons/mrp_operations/mrp_operation_data.xml @@ -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> diff --git a/addons/mrp_operations/mrp_operations.py b/addons/mrp_operations/mrp_operations.py index ee2547bc7df..a18eb4141ba 100644 --- a/addons/mrp_operations/mrp_operations.py +++ b/addons/mrp_operations/mrp_operations.py @@ -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() diff --git a/addons/mrp_repair/__openerp__.py b/addons/mrp_repair/__openerp__.py index da4070d6210..13a6e81e141 100644 --- a/addons/mrp_repair/__openerp__.py +++ b/addons/mrp_repair/__openerp__.py @@ -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', diff --git a/addons/mrp_repair/mrp_repair.py b/addons/mrp_repair/mrp_repair.py index c1ac8f809ce..44624044090 100644 --- a/addons/mrp_repair/mrp_repair.py +++ b/addons/mrp_repair/mrp_repair.py @@ -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() diff --git a/addons/mrp_repair/mrp_repair_data.xml b/addons/mrp_repair/mrp_repair_data.xml new file mode 100644 index 00000000000..337a4113382 --- /dev/null +++ b/addons/mrp_repair/mrp_repair_data.xml @@ -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> diff --git a/addons/point_of_sale/i18n/nb.po b/addons/point_of_sale/i18n/nb.po new file mode 100644 index 00000000000..42e5832b237 --- /dev/null +++ b/addons/point_of_sale/i18n/nb.po @@ -0,0 +1,2720 @@ +# 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 01:37+0100\n" +"PO-Revision-Date: 2012-08-31 07:48+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-01 04:55+0000\n" +"X-Generator: Launchpad (build 15890)\n" + +#. module: point_of_sale +#: field:report.transaction.pos,product_nb:0 +msgid "Product Nb." +msgstr "Produkt Nb" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_trans_pos_tree_today +msgid "Sales by day" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_open_statement.py:49 +#, python-format +msgid "" +"You must define which payment method must be available through the point of " +"sale by reusing existing bank and cash through \"Accounting > Configuration " +"> Financial Accounting > Journals\". Select a journal and check the field " +"\"PoS Payment Method\" from the \"Point of Sale\" tab. You can also create " +"new payment methods directly from menu \"PoS Backend > Configuration > " +"Payment Methods\"." +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 view:report.pos.order:0 +msgid "Today" +msgstr "I dag" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.plain_water +msgid "Plain Water" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Year from Creation date of cash register" +msgstr "" + +#. module: point_of_sale +#: view:pos.confirm:0 +msgid "Post All Orders" +msgstr "Poster Alle Ordre" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_2l_product_template +msgid "Spa Reine 2L" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_box_out +msgid "Pos Box Out" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_cash_register_all +#: model:ir.ui.menu,name:point_of_sale.menu_report_cash_register_all +msgid "Register Analysis" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_lines_detail +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Details of Sales" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 field:report.cash.register,day:0 +#: view:report.pos.order:0 field:report.pos.order,day:0 +msgid "Day" +msgstr "Dag" + +#. module: point_of_sale +#: view:pos.make.payment:0 +msgid "Add payment :" +msgstr "" + +#. module: point_of_sale +#: field:pos.box.out,name:0 +msgid "Description / Reason" +msgstr "Beskrivelse / Årsak" + +#. module: point_of_sale +#: field:report.sales.by.margin.pos,product_name:0 +#: field:report.sales.by.margin.pos.month,product_name:0 +msgid "Product Name" +msgstr "Produktnavn" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Month from Creation date of cash register" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 field:pos.box.entries,amount:0 +#: field:pos.box.out,amount:0 report:pos.invoice:0 +#: field:pos.make.payment,amount:0 report:pos.user.product:0 +#: field:report.transaction.pos,amount:0 +msgid "Amount" +msgstr "" + +#. module: point_of_sale +#: constraint:account.journal:0 +msgid "" +"Configuration error! The currency chosen should be shared by the default " +"accounts too." +msgstr "Konfigurasjonsfeil ! Valgt valuta må settes opp i kontoplan" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.pos_category_action +#: model:ir.ui.menu,name:point_of_sale.menu_pos_category view:pos.category:0 +msgid "PoS Categories" +msgstr "PoS Kategorier" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_box_out +#: model:ir.ui.menu,name:point_of_sale.menu_wizard_enter_jrnl2 +msgid "Take Money Out" +msgstr "" + +#. module: point_of_sale +#: report:pos.lines:0 +msgid "VAT" +msgstr "MVA" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Origin" +msgstr "Opphav" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Tax" +msgstr "MVA" + +#. module: point_of_sale +#: report:pos.user.product:0 +msgid "Starting Date" +msgstr "Startdato" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_box_entries.py:46 +#, python-format +msgid "" +"You do not have any open cash register. You must create a payment method or " +"open a cash register." +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 field:report.pos.order,partner_id:0 +msgid "Partner" +msgstr "Partner" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Total of the day" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 field:report.pos.order,average_price:0 +msgid "Average Price" +msgstr "Gjennomsnittspris" + +#. module: point_of_sale +#: report:pos.lines:0 +msgid "Disc. (%)" +msgstr "Rab. (%)" + +#. module: point_of_sale +#: model:ir.ui.menu,name:point_of_sale.menu_point_open_config +msgid "Cash Register Management" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_naturel_45g_product_template +msgid "Lays Naturel 45g" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Accounting Information" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_regular_2l_product_template +msgid "Coca-Cola Regular 2L" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_trans_pos_tree_month +msgid "Sales by month" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.soda_orange +msgid "Orange" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_sales_by_user_pos_today +#: view:report.sales.by.user.pos:0 view:report.sales.by.user.pos.month:0 +msgid "Sales by User" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Disc.(%)" +msgstr "Rab.(%)" + +#. module: point_of_sale +#: field:pos.box.entries,ref:0 +msgid "Ref" +msgstr "Ref" + +#. module: point_of_sale +#: view:report.pos.order:0 field:report.pos.order,price_total:0 +msgid "Total Price" +msgstr "Totalpris" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.leffe_brune_33cl_product_template +msgid "Leffe Brune 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_sales_user +#: report:pos.sales.user:0 +msgid "Sales Report" +msgstr "Salgsrapport" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.beverage +msgid "Beverages" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.stella_50cl_product_template +msgid "Stella Artois 50cl" +msgstr "" + +#. module: point_of_sale +#: view:pos.details:0 +msgid "Dates" +msgstr "Datoer" + +#. module: point_of_sale +#: field:pos.category,parent_id:0 +msgid "Parent Category" +msgstr "Overordnet kategori" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.lines:0 report:pos.payment.report.user:0 +#: report:pos.user.product:0 +msgid "[" +msgstr "" + +#. module: point_of_sale +#: field:report.sales.by.margin.pos,total:0 +#: field:report.sales.by.margin.pos.month,total:0 +msgid "Margin" +msgstr "Margin" + +#. module: point_of_sale +#: field:pos.discount,discount:0 field:pos.order.line,discount:0 +msgid "Discount (%)" +msgstr "Rabatt (%)" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_speciale_product_template +msgid "Dr. Oetker Ristorante Speciale" +msgstr "" + +#. module: point_of_sale +#: view:pos.order.line:0 +msgid "Total qty" +msgstr "Total ant" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.fanta_orange_33cl_product_template +msgid "Fanta Orange 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_sales_by_user_pos_month +msgid "Sales by User Monthly" +msgstr "" + +#. module: point_of_sale +#: report:all.closed.cashbox.of.the.day:0 +msgid "Today's Closed Cashbox" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Day from Creation date of cash register" +msgstr "" + +#. module: point_of_sale +#: model:ir.ui.menu,name:point_of_sale.menu_point_of_sale +msgid "Daily Operations" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:285 +#, python-format +msgid "Configuration Error !" +msgstr "Konfigurasjonsfeil!" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.sparkling_water +msgid "Sparkling Water" +msgstr "" + +#. module: point_of_sale +#: view:pos.box.entries:0 +msgid "Fill in this form if you put money in the cash register:" +msgstr "" + +#. module: point_of_sale +#: view:account.bank.statement:0 +msgid "Search Cash Statements" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "August" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.pepsi_max_lemon_33cl_product_template +msgid "Pepsi Max Cool Lemon 33cl" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "June" +msgstr "" + +#. module: point_of_sale +#: view:pos.order.line:0 +msgid "POS Order line" +msgstr "POS Ordre linje" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.fanta_orange_50cl_product_template +msgid "Fanta Orange 50cl" +msgstr "" + +#. module: point_of_sale +#: field:pos.category,child_id:0 +msgid "Children Categories" +msgstr "Underordnede Kategorier" + +#. module: point_of_sale +#: field:pos.make.payment,payment_date:0 +msgid "Payment Date" +msgstr "Betalingsdato" + +#. module: point_of_sale +#: help:product.product,pos_categ_id:0 +msgid "" +"If you want to sell this product through the point of sale, select the " +"category it belongs to." +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 report:all.closed.cashbox.of.the.day:0 +msgid "Closing Date" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "October" +msgstr "Oktober" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_1l_product_template +msgid "Coca-Cola Light 1L" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Summary" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chaudfontaine_50cl_product_template +msgid "Chaudfontaine 50cl" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 report:pos.lines:0 field:pos.order.line,qty:0 +#: field:report.sales.by.user.pos,qty:0 +#: field:report.sales.by.user.pos.month,qty:0 +msgid "Quantity" +msgstr "Antall" + +#. module: point_of_sale +#: field:pos.order.line,name:0 +msgid "Line No" +msgstr "" + +#. module: point_of_sale +#: view:account.bank.statement:0 +msgid "Period" +msgstr "Periode" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_open_statement.py:49 +#, python-format +msgid "No Cash Register Defined !" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Net Total:" +msgstr "Netto total:" + +#. module: point_of_sale +#: field:pos.make.payment,payment_name:0 +msgid "Payment Reference" +msgstr "Betalingsreferanse" + +#. module: point_of_sale +#: report:pos.details_summary:0 +msgid "Mode of Payment" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_confirm +msgid "Post POS Journal Entries" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:408 +#, python-format +msgid "Customer Invoice" +msgstr "Kundefaktura" + +#. module: point_of_sale +#: view:pos.box.out:0 +msgid "Output Operation" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 field:report.pos.order,total_discount:0 +msgid "Total Discount" +msgstr "Rabatt totalt" + +#. module: point_of_sale +#: view:pos.details:0 view:pos.payment.report:0 view:pos.payment.report.user:0 +#: view:pos.sale.user:0 +msgid "Print Report" +msgstr "Skriv ut rapport" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_bolognese_product_template +msgid "Dr. Oetker Ristorante Bolognese" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_box_entries.py:105 +#, python-format +msgid "Please check that income account is set to %s" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.pizza +msgid "Pizza" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_return.py:85 +#: code:addons/point_of_sale/wizard/pos_return.py:240 +#, python-format +msgid "Add Product" +msgstr "Legg til produkt" + +#. module: point_of_sale +#: field:report.transaction.pos,invoice_am:0 +msgid "Invoice Amount" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.coke +msgid "Coke" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Tel. :" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_confirm +#: model:ir.ui.menu,name:point_of_sale.menu_wizard_pos_confirm +msgid "Create Sale Entries" +msgstr "" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: model:ir.actions.act_window,name:point_of_sale.action_pos_payment +#: report:pos.details:0 view:pos.order:0 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:87 +msgid "Payment" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Cash Analysis created in current month" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 report:all.closed.cashbox.of.the.day:0 +msgid "Ending Balance" +msgstr "Sluttbalanse" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.pepsi_max_50cl_product_template +msgid "Pepsi Max 50cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.san_pellegrino_1l_product_template +msgid "San Pellegrino 1L" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Post Entries" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_1l_product_template +msgid "Spa Reine 1L" +msgstr "" + +#. module: point_of_sale +#: report:pos.details_summary:0 +msgid "Mode of Taxes" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_close_statement.py:50 +#, python-format +msgid "Cash registers are already closed." +msgstr "" + +#. module: point_of_sale +#: constraint:product.product:0 +msgid "Error: Invalid ean code" +msgstr "Feil: Ugyldig ean kode" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_open_statement +#: view:pos.open.statement:0 +msgid "Open Statements" +msgstr "" + +#. module: point_of_sale +#: field:pos.details,date_end:0 field:pos.sale.user,date_end:0 +msgid "Date End" +msgstr "Sluttdato" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "POS ordered created during current year" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_pos_form +#: model:ir.ui.menu,name:point_of_sale.menu_point_ofsale view:pos.order:0 +msgid "PoS Orders" +msgstr "POS Ordre" + +#. module: point_of_sale +#: report:pos.details:0 +msgid "Sales total(Revenue)" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Total paid" +msgstr "" + +#. module: point_of_sale +#: model:ir.ui.menu,name:point_of_sale.menu_all_menu_all_register +msgid "List of Cash Registers" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.maes_50cl_product_template +msgid "Maes 50cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_report_transaction_pos +msgid "transaction for the pos" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "Not Invoiced" +msgstr "Ikke fakturert" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "March" +msgstr "Mars" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_users_product_re +#: report:pos.user.product:0 +msgid "User's Product" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:641 +#, python-format +msgid "" +"You have to select a pricelist in the sale form !\n" +"Please set one before choosing a product." +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.fanta_orange_2l_product_template +msgid "Fanta Orange 2L" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_33cl_product_template +msgid "Spa Reine 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_discount +msgid "Add a Global Discount" +msgstr "" + +#. module: point_of_sale +#: field:pos.order.line,price_subtotal_incl:0 +msgid "Subtotal" +msgstr "Subtotal" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_prosciutto_product_template +msgid "Dr. Oetker Ristorante Prosciutto" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_light_paprika_170g_product_template +#: model:product.template,name:point_of_sale.lays_paprika_170g_product_template +msgid "Lays Light Paprika 170g" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_lemon_50cl_product_template +msgid "Coca-Cola Light Lemon 50cl" +msgstr "" + +#. module: point_of_sale +#: field:report.cash.register,balance_end_real:0 +msgid "Closing Balance" +msgstr "Sluttsaldo" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.act_pos_open_statement +#: model:ir.model,name:point_of_sale.model_pos_close_statement +msgid "Close Statements" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.croky_naturel_45g_product_template +msgid "Croky Naturel 45g" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.product_product_putmoneyforchange1_product_template +msgid "Cash Out" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 report:all.closed.cashbox.of.the.day:0 +msgid "Starting Balance" +msgstr "Inngående saldo" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_category +#: field:product.product,pos_categ_id:0 +msgid "PoS Category" +msgstr "PoS Kategori" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chimay_bleu_75cl_product_template +msgid "Chimay Bleu 75cl" +msgstr "" + +#. module: point_of_sale +#: report:pos.payment.report.user:0 +msgid "Payment By User" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 field:report.pos.order,nbr:0 +msgid "# of Lines" +msgstr "# linjer" + +#. module: point_of_sale +#: help:account.journal,check_dtls:0 +msgid "" +"This field authorize Validation of Cashbox without controlling the closing " +"balance." +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_pos_details +#: model:ir.ui.menu,name:point_of_sale.menu_pos_details +msgid "Sale Details" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.pils +msgid "Pils" +msgstr "" + +#. module: point_of_sale +#: report:all.closed.cashbox.of.the.day:0 +msgid "St.Name" +msgstr "" + +#. module: point_of_sale +#: report:pos.details_summary:0 +msgid "Sales total" +msgstr "" + +#. module: point_of_sale +#: view:pos.order.line:0 +msgid "Sum of subtotals" +msgstr "Sum av subtotaler" + +#. module: point_of_sale +#: field:pos.order,lines:0 +msgid "Order Lines" +msgstr "Ordrelinjer" + +#. module: point_of_sale +#: view:report.transaction.pos:0 +msgid "Total Transaction" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chaudfontaine_petillante_50cl_product_template +msgid "Chaudfontaine Petillante 50cl" +msgstr "" + +#. module: point_of_sale +#: field:pos.order.line,create_date:0 +msgid "Creation Date" +msgstr "Opprettet, dato:" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_sales_user_today +msgid "Today's Sales" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_naturel_300g_product_template +msgid "Lays Naturel XXL 300g" +msgstr "" + +#. module: point_of_sale +#: view:report.sales.by.margin.pos:0 view:report.sales.by.margin.pos.month:0 +#: view:report.sales.by.user.pos:0 view:report.sales.by.user.pos.month:0 +#: view:report.transaction.pos:0 +msgid "POS " +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 report:pos.user.product:0 +msgid "Total :" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 view:report.pos.order:0 +msgid "My Sales" +msgstr "Mine salg" + +#. module: point_of_sale +#: field:pos.order,pricelist_id:0 +msgid "Pricelist" +msgstr "Prisliste" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Total invoiced" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 field:report.pos.order,product_qty:0 +msgid "# of Qty" +msgstr "# av Ant" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_report_sales_by_margin_pos_month +msgid "Sales by margin monthly" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 field:report.sales.by.margin.pos,date_order:0 +#: field:report.sales.by.margin.pos.month,date_order:0 +#: field:report.sales.by.user.pos,date_order:0 +#: field:report.sales.by.user.pos.month,date_order:0 +msgid "Order Date" +msgstr "Ordredato" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.stella_33cl_product_template +msgid "Stella Artois 33cl" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Cash Analysis created during this year" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Draft Invoice" +msgstr "Fakturakladd" + +#. module: point_of_sale +#: 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: point_of_sale +#: report:pos.invoice:0 +msgid "Fiscal Position Remark :" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.evian_2l_product_template +msgid "Evian 2L" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "September" +msgstr "September" + +#. module: point_of_sale +#: report:account.statement:0 report:all.closed.cashbox.of.the.day:0 +msgid "Opening Date" +msgstr "" + +#. module: point_of_sale +#: report:pos.lines:0 +msgid "Taxes :" +msgstr "Mva" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_2l_product_template +msgid "Coca-Cola Light 2L" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_funghi_product_template +msgid "Dr. Oetker Ristorante Funghi" +msgstr "" + +#. module: point_of_sale +#: field:report.transaction.pos,disc:0 +msgid "Disc." +msgstr "Rab." + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lindemans_kriek_37,5cl_product_template +msgid "Lindemans Kriek 37.5cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_zero_33cl_product_template +msgid "Coca-Cola Zero 33cl" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "VAT :" +msgstr "MVA:" + +#. module: point_of_sale +#: view:pos.order.line:0 +msgid "POS Order lines" +msgstr "POS Ordre linjer" + +#. module: point_of_sale +#: view:pos.receipt:0 +msgid "Receipt :" +msgstr "Kvittering" + +#. module: point_of_sale +#: field:account.bank.statement.line,pos_statement_id:0 +#: field:pos.order,amount_return:0 +msgid "unknown" +msgstr "ukjent" + +#. module: point_of_sale +#: report:pos.details:0 field:report.transaction.pos,date_create:0 +msgid "Date" +msgstr "Dato" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_discount +#: view:pos.discount:0 +msgid "Apply Discount" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 report:all.closed.cashbox.of.the.day:0 +#: view:pos.details:0 report:pos.sales.user:0 report:pos.sales.user.today:0 +#: report:pos.user.product:0 view:report.cash.register:0 +#: field:report.cash.register,user_id:0 +#: field:report.sales.by.margin.pos,user_id:0 +#: field:report.sales.by.margin.pos.month,user_id:0 +#: field:report.sales.by.user.pos,user_id:0 +#: field:report.sales.by.user.pos.month,user_id:0 +#: field:report.transaction.pos,user_id:0 +#: model:res.groups,name:point_of_sale.group_pos_user +msgid "User" +msgstr "Bruker" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_33cl_product_template +msgid "Coca-Cola Light 33cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.perrier_1l_product_template +msgid "Perrier 1L" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Total discount" +msgstr "Total rabatt" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_box_entries +msgid "Pos Box Entries" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.boon_framboise_37,5cl_product_template +msgid "Boon Framboise 37.5cl" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "November" +msgstr "November" + +#. module: point_of_sale +#: field:pos.config.journal,code:0 +msgid "Code" +msgstr "Engelsk" + +#. module: point_of_sale +#: view:account.bank.statement:0 report:account.statement:0 +#: report:all.closed.cashbox.of.the.day:0 +#: model:ir.model,name:point_of_sale.model_account_journal +#: field:pos.config.journal,journal_id:0 field:pos.order,sale_journal:0 +#: view:report.cash.register:0 field:report.cash.register,journal_id:0 +#: field:report.pos.order,journal_id:0 +msgid "Journal" +msgstr "Journal" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.timmermans_faro_37,5cl_product_template +msgid "Timmermans Faro 37.5cl" +msgstr "" + +#. module: point_of_sale +#: view:account.bank.statement:0 view:pos.order:0 field:pos.order,state:0 +#: report:pos.sales.user:0 report:pos.sales.user.today:0 +#: field:report.cash.register,state:0 field:report.pos.order,state:0 +msgid "State" +msgstr "" + +#. module: point_of_sale +#: field:report.transaction.pos,no_trans:0 +msgid "Number of Transaction" +msgstr "Antall transaksjoner" + +#. module: point_of_sale +#: view:pos.box.entries:0 view:pos.box.out:0 view:pos.confirm:0 +#: view:pos.make.payment:0 view:pos.open.statement:0 view:pos.receipt:0 +msgid "Cancel" +msgstr "Avbryt" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_details_summary +msgid "Sales (summary)" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.timmermans_kriek_37,5cl_product_template +msgid "Timmermans Kriek 37.5cl" +msgstr "" + +#. module: point_of_sale +#: field:account.journal,check_dtls:0 +msgid "Control Balance Before Closing" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_order_line +msgid "Lines of Point of Sale" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 view:report.transaction.pos:0 +msgid "Amount total" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_new_bank_statement_all_tree +msgid "Cash Registers" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 +msgid "Users" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.food +msgid "Food" +msgstr "Mat" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: report:pos.details:0 report:pos.invoice:0 report:pos.lines:0 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:30 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:69 +msgid "Price" +msgstr "Pris" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.ijsboerke_stracciatella_2,5l_product_template +msgid "ijsboerke Stracciatella 2.5L" +msgstr "" + +#. module: point_of_sale +#: field:account.journal,journal_user:0 +msgid "PoS Payment Method" +msgstr "" + +#. module: point_of_sale +#: help:product.product,expense_pdt:0 +msgid "" +"This is a product you can use to take cash from a statement for the point of " +"sale backend, exemple: money lost, transfer to bank, etc." +msgstr "" + +#. module: point_of_sale +#: field:report.cash.register,date:0 +msgid "Create Date" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_regular_33cl_product_template +msgid "Coca-Cola Regular 33cl" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:65 +#, python-format +msgid "Unable to Delete !" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_paprika_oven_150g_product_template +msgid "Lays Paprika Oven Baked 150g" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Start Period" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 field:pos.category,complete_name:0 +#: field:pos.category,name:0 report:pos.sales.user:0 +#: report:pos.sales.user.today:0 +msgid "Name" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_gazeuse_33cl_product_template +msgid "Spa Barisart 33cl" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:284 +#, python-format +msgid "" +"There is no receivable account defined to make payment for the partner: " +"\"%s\" (id:%d)" +msgstr "" + +#. module: point_of_sale +#: view:pos.confirm:0 +msgid "" +"Generate all sale journal entries for non invoiced orders linked to a closed " +"cash register or statement." +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:293 +#: code:addons/point_of_sale/point_of_sale.py:472 +#: code:addons/point_of_sale/report/pos_invoice.py:46 +#: code:addons/point_of_sale/wizard/pos_box_entries.py:46 +#: code:addons/point_of_sale/wizard/pos_box_entries.py:100 +#: code:addons/point_of_sale/wizard/pos_box_entries.py:105 +#: code:addons/point_of_sale/wizard/pos_box_out.py:86 +#: code:addons/point_of_sale/wizard/pos_box_out.py:88 +#, python-format +msgid "Error !" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.lines:0 report:pos.payment.report.user:0 +#: report:pos.user.product:0 +msgid "]" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_account_bank_statement +msgid "Bank Statement" +msgstr "" + +#. module: point_of_sale +#: sql_constraint:account.journal:0 +msgid "The name of the journal must be unique per company !" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_light_naturel_170g_product_template +#: model:product.template,name:point_of_sale.lays_naturel_170g_product_template +msgid "Lays Light Naturel 170g" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 report:pos.lines:0 +#: report:pos.payment.report.user:0 report:pos.sales.user:0 +#: report:pos.sales.user.today:0 report:pos.user.product:0 +msgid "Print Date" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:282 +#, python-format +msgid "There is no receivable account defined to make payment" +msgstr "" + +#. module: point_of_sale +#: view:pos.open.statement:0 +msgid "Do you want to open cash registers?" +msgstr "" + +#. module: point_of_sale +#: help:pos.category,sequence:0 +msgid "" +"Gives the sequence order when displaying a list of product categories." +msgstr "" + +#. module: point_of_sale +#: field:product.product,expense_pdt:0 +msgid "PoS Cash Output" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.soda +msgid "Soda" +msgstr "" + +#. module: point_of_sale +#: view:account.bank.statement:0 view:pos.order:0 view:report.cash.register:0 +#: view:report.pos.order:0 +msgid "Group By..." +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "POS Orders" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.all_closed_cashbox_of_the_day +msgid "All Closed CashBox" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:640 +#, python-format +msgid "No Pricelist !" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Update" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Base" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.categ_others +msgid "Others" +msgstr "" + +#. module: point_of_sale +#: view:product.product:0 +msgid "Point-of-Sale" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.evian_50cl_product_template +msgid "Evian 50cl" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Notes" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Sale Order" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_lemon_2l_product_template +msgid "Coca-Cola Light Lemon 2L" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.invoice:0 field:pos.order,amount_tax:0 +msgid "Taxes" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_order_line +#: model:ir.actions.act_window,name:point_of_sale.action_pos_order_line_day +#: model:ir.actions.act_window,name:point_of_sale.action_pos_order_line_form +msgid "Sale line" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_naturel_oven_150g_product_template +msgid "Lays Naturel Oven Baked 150g" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_decaf_33cl_product_template +msgid "Coca-Cola Light Decaf 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.product_normal_action +#: model:ir.ui.menu,name:point_of_sale.menu_point_of_sale_product +#: model:ir.ui.menu,name:point_of_sale.menu_pos_products +msgid "Products" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_4formaggi_product_template +msgid "Dr. Oetker Ristorante Quattro Formaggi" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_zero_1l_product_template +msgid "Coca-Cola Zero 1L" +msgstr "" + +#. module: point_of_sale +#: report:pos.sales.user:0 report:pos.sales.user.today:0 +#: field:report.pos.order,date:0 +msgid "Date Order" +msgstr "" + +#. module: point_of_sale +#: view:report.sales.by.margin.pos:0 view:report.sales.by.margin.pos.month:0 +#: view:report.sales.by.user.pos:0 view:report.sales.by.user.pos.month:0 +#: view:report.transaction.pos:0 +msgid "POS" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_product_output +#: model:ir.ui.menu,name:point_of_sale.products_for_output_operations +msgid "Products 'Put Money In'" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.croky_bolognaise_250g_product_template +msgid "Croky Bolognaise 250g" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Extra Info" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Fax :" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,user_id:0 +msgid "Connected Salesman" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_sale_all +#: model:ir.ui.menu,name:point_of_sale.menu_point_ofsale_all +msgid "All Sales Orders" +msgstr "" + +#. module: point_of_sale +#: help:product.product,income_pdt:0 +msgid "" +"This is a product you can use to put cash into a statement for the point of " +"sale backend." +msgstr "" + +#. module: point_of_sale +#: view:pos.receipt:0 +msgid "Print the Receipt of the Sale" +msgstr "" + +#. module: point_of_sale +#: field:pos.make.payment,journal:0 +msgid "Payment Mode" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_paprika_45g_product_template +msgid "Lays Paprika 45g" +msgstr "" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: report:pos.details:0 report:pos.payment.report.user:0 +#: report:pos.user.product:0 field:report.sales.by.margin.pos,qty:0 +#: field:report.sales.by.margin.pos.month,qty:0 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:32 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:59 +msgid "Qty" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 view:report.pos.order:0 +msgid "Month -1" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_pos_sale_user +#: model:ir.model,name:point_of_sale.model_pos_sale_user +#: view:pos.payment.report.user:0 +msgid "Sale by User" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.evian_1l_product_template +msgid "Evian 1L" +msgstr "" + +#. module: point_of_sale +#: model:ir.ui.menu,name:point_of_sale.menu_open_statement +msgid "Open Cash Registers" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.water +msgid "Water" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "state" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "July" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_poivre_sel_oven_150g_product_template +msgid "Lays Sel et Poivre Oven Baked 150g" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "Qty of product" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chimay_rouge_33cl_product_template +msgid "Chimay Rouge 33cl" +msgstr "" + +#. module: point_of_sale +#: field:report.pos.order,delay_validation:0 +msgid "Delay Validation" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,nb_print:0 +msgid "Number of Print" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_make_payment +msgid "Point of Sale Payment" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_50cl_product_template +msgid "Coca-Cola Light 50cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.jupiler_50cl_product_template +msgid "Jupiler 50cl" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.details_summary:0 +msgid "End Period" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_light_lemon_33cl_product_template +msgid "Coca-Cola Light Lemon 33cl" +msgstr "" + +#. module: point_of_sale +#: field:account.journal,auto_cash:0 +msgid "Automatic Opening" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_ketchup_250g_product_template +msgid "Lays Ketchup 250g" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.perrier_50cl_product_template +msgid "Perrier 50cl" +msgstr "" + +#. module: point_of_sale +#: selection:report.pos.order,state:0 +msgid "Synchronized" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 field:report.cash.register,month:0 +#: view:report.pos.order:0 field:report.pos.order,month:0 +msgid "Month" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 +msgid "Statement Name" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "Year of order date" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_new_bank_statement_tree +#: field:pos.box.entries,journal_id:0 field:pos.box.out,journal_id:0 +msgid "Cash Register" +msgstr "" + +#. module: point_of_sale +#: view:pos.close.statement:0 +msgid "Yes" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_receipt +msgid "Point of sale receipt" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_sales_by_margin_pos_today +msgid "Sales by User Daily margin" +msgstr "" + +#. module: point_of_sale +#: view:pos.open.statement:0 +msgid "Open Registers" +msgstr "" + +#. module: point_of_sale +#: field:report.transaction.pos,journal_id:0 +msgid "Sales Journal" +msgstr "" + +#. module: point_of_sale +#: field:report.cash.register,balance_start:0 +msgid "Opening Balance" +msgstr "" + +#. module: point_of_sale +#: view:account.bank.statement:0 selection:report.pos.order,state:0 +msgid "Closed" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_vegetale_product_template +msgid "Dr. Oetker Ristorante Vegetale" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "POS ordered created by today" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_zero_2l_product_template +msgid "Coca-Cola Zero 2L" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,amount_paid:0 selection:pos.order,state:0 +msgid "Paid" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_all_sales_lines +msgid "All sales lines" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Discount" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Cash Analysis created in last month" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.beers +msgid "Beers" +msgstr "" + +#. module: point_of_sale +#: view:pos.close.statement:0 +msgid "" +"OpenERP will close all cash registers he can close automatically without " +"validation. He will also open all cash registers for which you have to " +"control the ending belance before closing manually." +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Cash Analysis created by today" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,state:0 +msgid "Quotation" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.product_product_putmoneyforchange0_product_template +msgid "Cash In" +msgstr "" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: report:all.closed.cashbox.of.the.day:0 report:pos.invoice:0 +#: report:pos.lines:0 report:pos.payment.report.user:0 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:49 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:93 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:271 +msgid "Total:" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_report_sales_by_margin_pos +msgid "Sales by margin" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_config_journal +msgid "Journal Configuration" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Statement lines" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.croky_paprika_45g_product_template +msgid "Croky Paprika 45g" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Reprint" +msgstr "" + +#. module: point_of_sale +#: help:pos.order,user_id:0 +msgid "" +"Person who uses the the cash register. It could be a reliever, a student or " +"an interim employee." +msgstr "" + +#. module: point_of_sale +#: field:report.transaction.pos,invoice_id:0 +msgid "Nbr Invoice" +msgstr "" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: model:ir.actions.act_window,name:point_of_sale.action_report_pos_receipt +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:231 +msgid "Receipt" +msgstr "" + +#. module: point_of_sale +#: view:pos.open.statement:0 +msgid "" +"The system will open all cash registers, so that you can start recording " +"payments. We suggest you to control the opening balance of each register, " +"using their CashBox tab." +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 report:pos.lines:0 field:pos.order.line,price_unit:0 +#: report:pos.payment.report.user:0 +msgid "Unit Price" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Done" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_invoice_report +#: report:pos.invoice:0 view:pos.order:0 field:pos.order,invoice_id:0 +msgid "Invoice" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.rochefort_8_33cl_product_template +msgid "Rochefort \"8\" 33cl" +msgstr "" + +#. module: point_of_sale +#: view:account.bank.statement:0 selection:report.cash.register,state:0 +msgid "Open" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,name:0 field:pos.order.line,order_id:0 +msgid "Order Ref" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.timmermans_geuze_37,5cl_product_template +msgid "Timmermans Geuze 37.5cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_pickles_250g_product_template +msgid "Lays Pickels 250g" +msgstr "" + +#. module: point_of_sale +#: field:report.sales.by.margin.pos,net_margin_per_qty:0 +#: field:report.sales.by.margin.pos.month,net_margin_per_qty:0 +msgid "Net margin per Qty" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_report_sales_by_user_pos_month +msgid "Sales by user monthly" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_et_fruit_50cl_product_template +msgid "Spa et Fruit Orange 50cl" +msgstr "" + +#. module: point_of_sale +#: view:report.sales.by.margin.pos:0 view:report.sales.by.margin.pos.month:0 +msgid "Sales by User Margin" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_payment.py:59 +#, python-format +msgid "Paiement" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Taxes:" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.pepsi_max_33cl_product_template +msgid "Pepsi Max 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_report_pos_order +msgid "Point of Sale Orders Statistics" +msgstr "" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: model:ir.model,name:point_of_sale.model_product_product +#: report:pos.details:0 field:pos.order.line,product_id:0 +#: report:pos.payment.report.user:0 report:pos.user.product:0 +#: view:report.pos.order:0 field:report.pos.order,product_id:0 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:29 +msgid "Product" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_pollo_product_template +msgid "Dr. Oetker Ristorante Pollo" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_lines_report +msgid "Pos Lines" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.grisette_cerise_25cl_product_template +msgid "Grisette Cerise 25cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chaudfontaine_33cl_product_template +msgid "Chaudfontaine 33cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_margherita_product_template +msgid "Dr. Oetker La Margherita" +msgstr "" + +#. module: point_of_sale +#: model:ir.ui.menu,name:point_of_sale.menu_point_root +msgid "PoS Backend" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 selection:pos.order,state:0 +msgid "Posted" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,date_order:0 +msgid "Date Ordered" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_pos_payment_report_user +#: model:ir.model,name:point_of_sale.model_pos_payment_report_user +msgid "Sales lines by Users" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.pepsi_2l_product_template +msgid "Pepsi 2L" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 +msgid "Order" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:472 +#, python-format +msgid "There is no income account defined for this product: \"%s\" (id:%d)" +msgstr "" + +#. module: point_of_sale +#: view:pos.details:0 +msgid "POS Details" +msgstr "" + +#. module: point_of_sale +#: field:pos.details,user_ids:0 +msgid "Salesmen" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_report_cash_register +#: view:report.cash.register:0 +msgid "Point of Sale Cash Register Analysis" +msgstr "" + +#. module: point_of_sale +#: report:pos.lines:0 +msgid "Net Total :" +msgstr "" + +#. module: point_of_sale +#: model:res.groups,name:point_of_sale.group_pos_manager +msgid "Manager" +msgstr "" + +#. module: point_of_sale +#: field:pos.details,date_start:0 field:pos.sale.user,date_start:0 +msgid "Date Start" +msgstr "" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: field:pos.order,amount_total:0 report:pos.payment.report.user:0 +#: field:report.sales.by.user.pos,amount:0 +#: field:report.sales.by.user.pos.month,amount:0 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:33 +msgid "Total" +msgstr "" + +#. module: point_of_sale +#: view:pos.sale.user:0 +msgid "Sale By User" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_open_statement +msgid "Open Cash Register" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lindemans_pecheresse_37,5cl_product_template +msgid "Lindemans Pecheresse 37.5cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.pepsi_33cl_product_template +msgid "Pepsi 33cl" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 +#: model:ir.actions.report.xml,name:point_of_sale.account_statement +msgid "Statement" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_payment_report +#: model:ir.model,name:point_of_sale.model_pos_payment_report +#: view:pos.payment.report:0 +msgid "Payment Report" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.fanta_orange_25cl_product_template +msgid "Fanta Orange 25cl" +msgstr "" + +#. module: point_of_sale +#: view:pos.confirm:0 +msgid "Generate Journal Entries" +msgstr "" + +#. module: point_of_sale +#: report:account.statement:0 report:all.closed.cashbox.of.the.day:0 +#: report:pos.details:0 report:pos.details_summary:0 report:pos.lines:0 +#: field:pos.order,company_id:0 field:pos.order.line,company_id:0 +#: report:pos.payment.report.user:0 report:pos.sales.user:0 +#: report:pos.sales.user.today:0 report:pos.user.product:0 +#: field:report.pos.order,company_id:0 +msgid "Company" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Invoice Date" +msgstr "" + +#. module: point_of_sale +#: field:pos.box.entries,name:0 +msgid "Reason" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.orangina_33cl_product_template +msgid "Orangina 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_product_input +#: model:ir.ui.menu,name:point_of_sale.products_for_input_operations +msgid "Products 'Take Money Out'" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chimay_bleu_33cl_product_template +msgid "Chimay Bleu 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_account_journal_form +#: model:ir.ui.menu,name:point_of_sale.menu_action_account_journal_form_open +msgid "Payment Methods" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.chips +msgid "Chips" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_spinaci_product_template +msgid "Dr. Oetker Ristorante Spinaci" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:293 +#: code:addons/point_of_sale/wizard/pos_box_entries.py:100 +#: code:addons/point_of_sale/wizard/pos_box_out.py:88 +#, python-format +msgid "You have to open at least one cashbox" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.report.xml,name:point_of_sale.pos_payment_report_user +msgid "Today's Payment By User" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_box_entries +#: model:ir.ui.menu,name:point_of_sale.menu_wizard_enter_jrnl +msgid "Put Money In" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:238 +#: code:addons/point_of_sale/point_of_sale.py:253 +#, python-format +msgid "Error!" +msgstr "" + +#. module: point_of_sale +#: report:pos.lines:0 +msgid "No. Of Articles" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.ijsboerke_vanille_2,5l_product_template +msgid "ijsboerke Vanille 2.5L" +msgstr "" + +#. module: point_of_sale +#: selection:pos.order,state:0 selection:report.pos.order,state:0 +msgid "Cancelled" +msgstr "" + +#. module: point_of_sale +#: report:pos.user.product:0 +msgid "Ending Date" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.orangina_1,5l_product_template +msgid "Orangina 1.5L" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,picking_id:0 +msgid "Picking" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.ice_cream +msgid "Ice Cream" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,shop_id:0 field:report.pos.order,shop_id:0 +msgid "Shop" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.belle_vue_kriek_25cl_product_template +msgid "Belle-Vue Kriek 25cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chaudfontaine_petillante_1,5l_product_template +msgid "Chaudfontaine Petillante 1.5l" +msgstr "" + +#. module: point_of_sale +#: view:report.sales.by.user.pos:0 view:report.sales.by.user.pos.month:0 +#: view:report.transaction.pos:0 +msgid "POS Report" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chaudfontaine_1,5l_product_template +msgid "Chaudfontaine 1.5l" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_close_statement +msgid "Close Cash Register" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:65 +#, python-format +msgid "In order to delete a sale, it must be new or cancelled." +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_regular_50cl_product_template +msgid "Coca-Cola Regular 50cl" +msgstr "" + +#. module: point_of_sale +#: view:pos.confirm:0 +msgid "Generate Entries" +msgstr "" + +#. module: point_of_sale +#: field:pos.box.entries,product_id:0 field:pos.box.out,product_id:0 +msgid "Operation" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,account_move:0 +msgid "Journal Entry" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,state:0 +msgid "Confirmed" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Cancelled Invoice" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Confirm" +msgstr "" + +#. module: point_of_sale +#: help:account.journal,auto_cash:0 +msgid "" +"This field authorize the automatic creation of the cashbox, without control " +"of the initial balance." +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_zero_50cl_product_template +msgid "Coca-Cola Zero 50cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_tonno_product_template +msgid "Dr. Oetker Ristorante Tonno" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Supplier Invoice" +msgstr "" + +#. module: point_of_sale +#: constraint:account.bank.statement:0 +msgid "The journal and period chosen have to belong to the same company." +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 selection:pos.order,state:0 +#: selection:report.pos.order,state:0 +msgid "New" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:238 +#, python-format +msgid "In order to set to draft a sale, it must be cancelled." +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.fanta_zero_orange_33cl_product_template +msgid "Fanta Zero Orange 33cl" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "Day of order date" +msgstr "" + +#. module: point_of_sale +#: model:ir.ui.menu,name:point_of_sale.menu_point_rep +msgid "Reporting" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.maes_33cl_product_template +msgid "Maes 33cl" +msgstr "" + +#. module: point_of_sale +#: view:pos.box.entries:0 +msgid "Put Money" +msgstr "" + +#. module: point_of_sale +#: sql_constraint:account.journal:0 +msgid "The code of the journal must be unique per company !" +msgstr "" + +#. module: point_of_sale +#: model:ir.ui.menu,name:point_of_sale.menu_point_config_product +msgid "Configuration" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.orval_33cl_product_template +msgid "Orval 33cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_regular_1l_product_template +msgid "Coca-Cola Regular 1L" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:253 +#, python-format +msgid "Unable to cancel the picking." +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "POS ordered created during current month" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "POS ordered created last month" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_pos_invoice +msgid "Invoices" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "December" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_gazeuse_1,5l_product_template +msgid "Spa Barisart 1.5l" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:329 view:pos.order:0 +#, python-format +msgid "Return Products" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.jupiler_33cl_product_template +msgid "Jupiler 33cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.ijsboerke_chocolat_2,5l_product_template +msgid "ijsboerke Chocolat 2.5L" +msgstr "" + +#. module: point_of_sale +#: view:pos.box.out:0 +msgid "Take Money" +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_details +msgid "Sales Details" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_close_statement.py:50 +#, python-format +msgid "Message" +msgstr "" + +#. module: point_of_sale +#: view:account.journal:0 model:ir.model,name:point_of_sale.model_pos_order +#: model:ir.ui.menu,name:point_of_sale.menu_point_root_touchscreen +#: view:product.product:0 +msgid "Point of Sale" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 field:pos.payment.report.user,user_id:0 +#: field:pos.sale.user,user_id:0 field:pos.sales.user.today,user_id:0 +#: view:report.pos.order:0 field:report.pos.order,user_id:0 +msgid "Salesman" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 view:pos.order:0 selection:pos.order,state:0 +#: view:report.pos.order:0 selection:report.pos.order,state:0 +msgid "Invoiced" +msgstr "" + +#. module: point_of_sale +#: view:pos.close.statement:0 +msgid "No" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_gazeuse_50cl_product_template +msgid "Spa Barisart 50cl" +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.special_beers +msgid "Special Beers" +msgstr "" + +#. module: point_of_sale +#: field:pos.order.line,notice:0 +msgid "Discount Notice" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Re-Print" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid "Draft" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.fanta_zero_orange_1,5l_product_template +msgid "Fanta Zero Orange 1.5L" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "PRO-FORMA" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:358 +#, python-format +msgid "Please provide a partner for the sale." +msgstr "" + +#. module: point_of_sale +#: model:pos.category,name:point_of_sale.fruity_beers +msgid "Fruity Beers" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.ijsboerke_dame_blanche_2,5l_product_template +msgid "ijsboerke Dame Blanche 2.5L" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.ijsboerke_moka_2,5l_product_template +msgid "ijsboerke Moka 2.5L" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Search Sales Order" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,help:point_of_sale.action_account_journal_form +msgid "" +"Payment methods are defined by accounting journals having the field Payment " +"Method checked." +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_trans_pos_tree +#: model:ir.model,name:point_of_sale.model_report_sales_by_user_pos +msgid "Sales by user" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_hawaii_product_template +msgid "Dr. Oetker Ristorante Hawaii" +msgstr "" + +#. module: point_of_sale +#: view:pos.receipt:0 +msgid "Print Receipt" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "January" +msgstr "" + +#. module: point_of_sale +#: view:pos.order.line:0 +msgid "POS Orders lines" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.chaudfontaine_petillante_33cl_product_template +msgid "Chaudfontaine Petillante 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,help:point_of_sale.product_normal_action +msgid "" +"You must define a Product for everything you buy or sell. Products can be " +"raw materials, stockable products, consumables or services. The Product form " +"contains detailed information about your products related to procurement " +"logistics, sales price, product category, suppliers and so on." +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.pepsi_max_2l_product_template +msgid "Pepsi Max 2L" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/point_of_sale.py:358 +#, python-format +msgid "Error" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.lays_paprika_300g_product_template +msgid "Lays Paprika XXL 300g" +msgstr "" + +#. module: point_of_sale +#: view:pos.close.statement:0 +msgid "Do you want to close your cash registers?" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Refund" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/report/pos_invoice.py:46 +#, python-format +msgid "Please create an invoice for this sale." +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.oetker_mozzarella_product_template +msgid "Dr. Oetker Ristorante Mozzarella" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_close_statement.py:66 +#: model:ir.ui.menu,name:point_of_sale.menu_close_statement +#: view:pos.close.statement:0 +#, python-format +msgid "Close Cash Registers" +msgstr "" + +#. module: point_of_sale +#: report:pos.details:0 report:pos.payment.report.user:0 +msgid "Disc(%)" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "General Information" +msgstr "" + +#. #-#-#-#-# point_of_sale.pot (OpenERP Server 6.1rc1) #-#-#-#-# +#. module: point_of_sale +#. #-#-#-#-# point_of_sale.pot.web (PROJECT VERSION) #-#-#-#-# +#. openerp-web +#: view:pos.details:0 view:pos.discount:0 view:pos.payment.report:0 +#: view:pos.payment.report.user:0 view:pos.sale.user:0 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:13 +msgid "Close" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Order lines" +msgstr "" + +#. module: point_of_sale +#: view:account.journal:0 +msgid "Extended Configuration" +msgstr "" + +#. module: point_of_sale +#: field:pos.order.line,price_subtotal:0 +msgid "Subtotal w/o Tax" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.spa_50cl_product_template +msgid "Spa Reine 50cl" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.leffe_blonde_33cl_product_template +msgid "Leffe Blonde 33cl" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_pos_payment +msgid "Pyament Report" +msgstr "" + +#. module: point_of_sale +#: field:report.transaction.pos,jl_id:0 +msgid "Cash Journals" +msgstr "" + +#. module: point_of_sale +#: report:pos.sales.user.today:0 +msgid "Today's Sales By User" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Customer Code" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_box_out.py:86 +#, python-format +msgid "please check that account is set to %s" +msgstr "" + +#. module: point_of_sale +#: field:pos.config.journal,name:0 report:pos.invoice:0 report:pos.lines:0 +msgid "Description" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "May" +msgstr "" + +#. module: point_of_sale +#: report:pos.lines:0 +msgid "Sales lines" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 +msgid "Yesterday" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,note:0 +msgid "Internal Notes" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.coca_zero_decaf_33cl_product_template +msgid "Coca-Cola Zero Decaf 33cl" +msgstr "" + +#. module: point_of_sale +#: view:pos.box.out:0 +msgid "Describe why you take money from the cash register:" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_pos_order_all +#: model:ir.ui.menu,name:point_of_sale.menu_report_pos_order_all +#: view:report.pos.order:0 +msgid "Point of Sale Analysis" +msgstr "" + +#. module: point_of_sale +#: view:pos.order:0 field:pos.order,partner_id:0 view:report.pos.order:0 +msgid "Customer" +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "February" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 +msgid " Today " +msgstr "" + +#. module: point_of_sale +#: selection:report.cash.register,month:0 selection:report.pos.order,month:0 +msgid "April" +msgstr "" + +#. module: point_of_sale +#: field:pos.order,statement_ids:0 +msgid "Payments" +msgstr "" + +#. module: point_of_sale +#: report:pos.invoice:0 +msgid "Supplier Refund" +msgstr "" + +#. module: point_of_sale +#: model:ir.actions.act_window,name:point_of_sale.action_report_sales_by_margin_pos_month +msgid "Sales by User Monthly margin" +msgstr "" + +#. module: point_of_sale +#: model:product.template,name:point_of_sale.leffe_9_33cl_product_template +msgid "Leffe Brune \"9\" 33cl" +msgstr "" + +#. module: point_of_sale +#: help:account.journal,journal_user:0 +msgid "" +"Check this box if this journal define a payment method that can be used in " +"point of sales." +msgstr "" + +#. module: point_of_sale +#: field:pos.category,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: point_of_sale +#: code:addons/point_of_sale/wizard/pos_return.py:316 view:pos.make.payment:0 +#, python-format +msgid "Make Payment" +msgstr "" + +#. module: point_of_sale +#: constraint:pos.category:0 +msgid "Error ! You cannot create recursive categories." +msgstr "" + +#. module: point_of_sale +#: model:ir.model,name:point_of_sale.model_pos_sales_user_today +msgid "Sales User Today" +msgstr "" + +#. module: point_of_sale +#: view:report.pos.order:0 +msgid "Month of order date" +msgstr "" + +#. module: point_of_sale +#: field:product.product,income_pdt:0 +msgid "PoS Cash Input" +msgstr "" + +#. module: point_of_sale +#: view:report.cash.register:0 field:report.cash.register,year:0 +#: view:report.pos.order:0 field:report.pos.order,year:0 +msgid "Year" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:31 +msgid "Disc (%)" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:41 +msgid "Subtotal:" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:45 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:268 +msgid "Tax:" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:64 +msgid "Disc" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:71 +msgid "+/-" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:105 +msgid "Paid:" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:113 +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:288 +msgid "Change:" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:124 +msgid "Back to Products" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:127 +msgid "Validate" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:140 +msgid "pending orders" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:145 +msgid "" +"There are pending operations that could not be saved into the database, are " +"you sure you want to exit?" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:236 +msgid "Print" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:238 +msgid "Next Order" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:248 +msgid "Phone:" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:249 +msgid "User:" +msgstr "" + +#. openerp-web +#: /home/odo/repositories/addons/trunk/point_of_sale/static/src/xml/pos.xml:250 +msgid "Shop:" +msgstr "" diff --git a/addons/point_of_sale/wizard/pos_session_opening.py b/addons/point_of_sale/wizard/pos_session_opening.py index d3b6ea28b17..4364998b6a4 100644 --- a/addons/point_of_sale/wizard/pos_session_opening.py +++ b/addons/point_of_sale/wizard/pos_session_opening.py @@ -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): diff --git a/addons/point_of_sale/wizard/pos_session_opening.xml b/addons/point_of_sale/wizard/pos_session_opening.xml index 948f1db8c61..9279d5fce45 100644 --- a/addons/point_of_sale/wizard/pos_session_opening.xml +++ b/addons/point_of_sale/wizard/pos_session_opening.xml @@ -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> diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index db50ebd94fd..94d83675df1 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -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() diff --git a/addons/procurement/procurement_data.xml b/addons/procurement/procurement_data.xml index 6a83d525c68..1f60977c4dd 100644 --- a/addons/procurement/procurement_data.xml +++ b/addons/procurement/procurement_data.xml @@ -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>
\ No newline at end of file diff --git a/addons/project/project.py b/addons/project/project.py index f2e0fb7b18c..ae70dcc1dd4 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -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) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index b1a5631e59e..16b827c1323 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -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() diff --git a/addons/purchase/purchase_data.xml b/addons/purchase/purchase_data.xml index 693d18eb1ba..a84564b2360 100644 --- a/addons/purchase/purchase_data.xml +++ b/addons/purchase/purchase_data.xml @@ -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> diff --git a/addons/purchase_requisition/purchase_requisition.py b/addons/purchase_requisition/purchase_requisition.py index 90a5244e66f..a3df366381d 100644 --- a/addons/purchase_requisition/purchase_requisition.py +++ b/addons/purchase_requisition/purchase_requisition.py @@ -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) diff --git a/addons/purchase_requisition/purchase_requisition_data.xml b/addons/purchase_requisition/purchase_requisition_data.xml index 98591535f91..2b22c2057a1 100644 --- a/addons/purchase_requisition/purchase_requisition_data.xml +++ b/addons/purchase_requisition/purchase_requisition_data.xml @@ -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>
\ No newline at end of file diff --git a/addons/sale/sale_data.xml b/addons/sale/sale_data.xml index a23ab401dbd..2f4b81b27f4 100644 --- a/addons/sale/sale_data.xml +++ b/addons/sale/sale_data.xml @@ -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"/> diff --git a/addons/sale_crm/i18n/zh_CN.po b/addons/sale_crm/i18n/zh_CN.po index bbae3770541..6678287c01e 100644 --- a/addons/sale_crm/i18n/zh_CN.po +++ b/addons/sale_crm/i18n/zh_CN.po @@ -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 diff --git a/addons/sale_mrp/i18n/zh_CN.po b/addons/sale_mrp/i18n/zh_CN.po index 86105255a19..bb04533ef97 100644 --- a/addons/sale_mrp/i18n/zh_CN.po +++ b/addons/sale_mrp/i18n/zh_CN.po @@ -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 diff --git a/addons/share/wizard/share_wizard.py b/addons/share/wizard/share_wizard.py index e41f6828351..a0489c9c017 100644 --- a/addons/share/wizard/share_wizard.py +++ b/addons/share/wizard/share_wizard.py @@ -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) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 006af587c1f..ed20bbec2c5 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -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() diff --git a/addons/stock/stock_data.xml b/addons/stock/stock_data.xml index 77c82989a21..f83b0ada388 100644 --- a/addons/stock/stock_data.xml +++ b/addons/stock/stock_data.xml @@ -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> |
