[MERGE] Sync with trunk
authorOlivier Dony <odo@openerp.com>
Wed, 24 Oct 2012 09:06:15 +0000 (11:06 +0200)
committerOlivier Dony <odo@openerp.com>
Wed, 24 Oct 2012 09:06:15 +0000 (11:06 +0200)
bzr revid: odo@openerp.com-20121024090615-zuh7aub6fhcwhy82

122 files changed:
addons/account/account.py
addons/account/account_invoice.py
addons/account/account_invoice_view.xml
addons/account/account_move_line.py
addons/account/account_view.xml
addons/account/installer.py
addons/account/project/project_view.xml
addons/account/report/account_print_overdue.rml
addons/account/static/src/js/account_move_reconciliation.js
addons/account/test/account_validate_account_move.yml
addons/account_cancel/i18n/es_MX.po
addons/account_voucher/account_voucher.py
addons/account_voucher/test/account_voucher.yml
addons/account_voucher/test/sales_payment.yml
addons/account_voucher/test/sales_receipt.yml
addons/analytic/analytic.py
addons/anonymization/anonymization.py
addons/anonymization/anonymization_view.xml
addons/anonymization/i18n/mn.po [new file with mode: 0644]
addons/base_action_rule/base_action_rule.py
addons/base_action_rule/base_action_rule_view.xml
addons/base_calendar/base_calendar_view.xml
addons/base_calendar/crm_meeting_view.xml
addons/base_crypt/crypt.py
addons/base_import/static/src/js/import.js
addons/base_status/base_stage.py
addons/crm/__openerp__.py
addons/crm/crm_action_rule.py
addons/crm/crm_action_rule_demo.xml [new file with mode: 0644]
addons/crm/crm_action_rule_view.xml
addons/crm/crm_lead_view.xml
addons/crm/crm_meeting_view.xml [deleted file]
addons/crm/crm_phonecall_menu.xml
addons/crm/crm_phonecall_view.xml
addons/crm/wizard/crm_phonecall_to_phonecall.py
addons/crm_claim/crm_claim.py
addons/crm_claim/crm_claim_view.xml
addons/crm_claim/i18n/ru.po
addons/event/event_view.xml
addons/event_sale/event_sale.py
addons/hr/hr.py
addons/hr/i18n/lt.po
addons/hr_attendance/report/attendance_by_month.py
addons/hr_attendance/report/timesheet.py
addons/hr_attendance/wizard/hr_attendance_byweek.py
addons/hr_evaluation/hr_evaluation_view.xml
addons/hr_expense/hr_expense_installer_view.xml
addons/hr_holidays/hr_holidays_view.xml
addons/hr_recruitment/board_hr_recruitment_statistical_view.xml
addons/hr_recruitment/hr_recruitment_data.xml
addons/hr_recruitment/hr_recruitment_demo.yml
addons/hr_recruitment/hr_recruitment_view.xml
addons/hr_timesheet/i18n/mk.po [new file with mode: 0644]
addons/hr_timesheet/test/test_hr_timesheet.yml
addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py
addons/hr_timesheet_invoice/hr_timesheet_invoice.py
addons/hr_timesheet_invoice/hr_timesheet_invoice_view.xml
addons/hr_timesheet_sheet/hr_timesheet_sheet.py
addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
addons/hr_timesheet_sheet/i18n/mk.po [new file with mode: 0644]
addons/hr_timesheet_sheet/report/timesheet_report.py
addons/l10n_be/l10n_be_wizard.yml
addons/l10n_mx/i18n/es_MX.po
addons/mail/__init__.py
addons/mail/__openerp__.py
addons/mail/mail_favorite.py [new file with mode: 0644]
addons/mail/mail_favorite_view.xml [new file with mode: 0644]
addons/mail/mail_group_menu.py
addons/mail/mail_message.py
addons/mail/mail_message_view.xml
addons/mail/mail_thread.py
addons/mail/mail_thread_view.xml
addons/mail/res_users.py
addons/mail/security/mail_security.xml
addons/mail/static/src/css/mail.css
addons/mail/static/src/css/mail_compose_message.css
addons/mail/static/src/js/mail.js
addons/mail/static/src/js/mail_followers.js
addons/mail/static/src/xml/mail.xml
addons/mail/tests/test_mail.py
addons/mail/update.py
addons/mail/wizard/mail_compose_message_view.xml
addons/mrp/mrp_view.xml
addons/mrp/procurement.py
addons/mrp/security/ir.model.access.csv
addons/point_of_sale/report/pos_payment_report_user.rml
addons/point_of_sale/static/src/js/screens.js
addons/point_of_sale/static/src/js/widgets.js
addons/portal_claim/security/portal_security.xml
addons/portal_project/security/portal_security.xml
addons/portal_project_issue/security/portal_security.xml
addons/portal_sale/portal_sale_view.xml
addons/portal_sale/security/portal_security.xml
addons/process/static/src/js/process.js
addons/process/static/src/xml/process.xml
addons/product/i18n/es_EC.po
addons/product/pricelist.py
addons/product/pricelist_view.xml
addons/product/product_view.xml
addons/project/project.py
addons/project/project_view.xml
addons/project_issue/project_issue.py
addons/project_issue/project_issue_view.xml
addons/project_timesheet/project_timesheet.py
addons/project_timesheet/project_timesheet_view.xml
addons/purchase/purchase_view.xml
addons/resource/i18n/ru.po
addons/sale/i18n/hu.po
addons/sale/i18n/lt.po
addons/sale/i18n/ru.po
addons/sale/res_partner_view.xml
addons/sale/sale.py
addons/sale/sale_view.xml
addons/sale_stock/sale_stock.py
addons/sale_stock/sale_stock_view.xml
addons/stock/security/stock_security.xml
addons/stock/stock_view.xml
addons/survey/survey.py
addons/survey/survey_view.xml
addons/survey/wizard/survey_answer.py
addons/survey/wizard/survey_send_invitation.py
addons/survey/wizard/survey_send_invitation.xml

index fa2b10a..3e07f15 100644 (file)
@@ -1431,6 +1431,9 @@ class account_move(osv.osv):
         if 'line_id' in vals:
             c = context.copy()
             c['novalidate'] = True
+            c['period_id'] = vals['period_id']
+            c['journal_id'] = vals['journal_id']
+            c['date'] = vals['date']
             result = super(account_move, self).create(cr, uid, vals, c)
             self.validate(cr, uid, [result], context)
         else:
index 15f000c..1193891 100644 (file)
@@ -185,6 +185,7 @@ class account_invoice(osv.osv):
     _columns = {
         'name': fields.char('Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}),
         'origin': fields.char('Source Document', size=64, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}),
+        'supplier_invoice_number': fields.char('Supplier Invoice Number', size=64, help="The reference of this invoice as provided by the supplier.", readonly=True, states={'draft':[('readonly',False)]}),
         'type': fields.selection([
             ('out_invoice','Customer Invoice'),
             ('in_invoice','Supplier Invoice'),
index 8516fcd..5ed3734 100644 (file)
             <field name="arch" type="xml">
                 <form string="Supplier Invoice" version="7.0">
                 <header>
-                    <span groups="base.group_user">
-                        <button name="invoice_open" states="draft,proforma2" string="Validate" class="oe_highlight"/>
-                        <button name="%(action_account_invoice_refund)d" type='action' string='Ask Refund' states='open,paid' />
+                        <button name="invoice_open" states="draft,proforma2" string="Validate" class="oe_highlight" groups="account.group_account_invoice"/>
+                        <button name="%(action_account_invoice_refund)d" type='action' string='Ask Refund' states='open,paid' groups="account.group_account_invoice"/>
                         <button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" groups="base.group_no_one"/>
-                        <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object"/>
+                        <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" groups="account.group_account_invoice"/>
                         <button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','&lt;&gt;','paid'), ('reconciled', '=', True)]}" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/>
-                    </span>
                     <field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
                 </header>
                 <sheet string="Supplier Invoice">
                               context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"
                               domain="[('supplier', '=', True)]"/>
                             <field name="fiscal_position" widget="selection"/>
-                            <field name="origin"/>
-                                       <label for="reference_type"/>
-                                       <div>
+                            <group>
+                                <field name="origin"/>
+                                <field name="supplier_invoice_number"/>
+                            </group>
+                            <label for="reference_type"/>
+                            <div>
                                 <field name="reference_type" class="oe_inline oe_edit_only"/>
                                 <field name="reference" class="oe_inline"/>
-                                       </div>
+                            </div>
                         </group>
                         <group>
                             <field name="date_invoice"/>
             <field name="arch" type="xml">
                 <form string="Invoice" version="7.0">
                 <header>
-                    <span groups="base.group_user">
-                        <button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight"/>
-                        <button name="invoice_print" string="Print Invoice" type="object" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight"/>
-                        <button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}"/>
-                        <button name="invoice_print" string="Print Invoice" type="object" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}"/>
-                        <button name="invoice_open" states="draft" string="Validate" class="oe_highlight"/>
-                        <button name="invoice_open" states="proforma2" string="Validate"/>
-                        <button name="invoice_proforma2" states="draft" string="PRO-FORMA" groups="account.group_proforma_invoices"/>
-                        <button name="%(action_account_invoice_refund)d" type='action' string='Refund Invoice' states='open,proforma2,paid'/>
-                        <button name="invoice_cancel" states="draft,proforma2,open" string="Cancel" groups="base.group_no_one"/>
-                        <button name="action_cancel_draft" states="cancel" string="Reset to Draft" type="object"/>
-                        <button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','&lt;&gt;','paid'), ('reconciled', '=', True)]}" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/>
-                        <!--button name="%(account_invoices)d" string="Print Invoice" type="action" states="open,paid,proforma,sale,proforma2"/-->
-                    </span>
+                    <button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight" groups="base.group_user"/>
+                    <button name="invoice_print" string="Print Invoice" type="object" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight" groups="base.group_user"/>
+                    <button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}" groups="base.group_user"/>
+                    <button name="invoice_print" string="Print Invoice" type="object" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}" groups="base.group_user"/>
+                    <button name="invoice_open" states="draft" string="Validate" class="oe_highlight" groups="base.group_user"/>
+                    <button name="invoice_open" states="proforma2" string="Validate" groups="base.group_user"/>
+                    <button name="invoice_proforma2" states="draft" string="PRO-FORMA" groups="account.group_proforma_invoices"/>
+                    <button name="%(action_account_invoice_refund)d" type='action' string='Refund Invoice' states='open,proforma2,paid' groups="base.group_user"/>
+                    <button name="invoice_cancel" states="draft,proforma2,open" string="Cancel" groups="base.group_no_one"/>
+                    <button name="action_cancel_draft" states="cancel" string="Reset to Draft" type="object" groups="base.group_user"/>
+                    <button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','&lt;&gt;','paid'), ('reconciled', '=', True)]}" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/>
+                    <!--button name="%(account_invoices)d" string="Print Invoice" type="action" states="open,paid,proforma,sale,proforma2"/-->
                     <field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
                 </header>
                 <sheet string="Invoice">
             <field name="model">account.invoice</field>
             <field name="arch" type="xml">
                 <search string="Search Invoice">
-                    <field name="number" string="Invoice" filter_domain="['|', ('number','ilike',self),('origin','ilike',self)]"/>
+                    <field name="number" string="Invoice" filter_domain="['|','|', ('number','ilike',self), ('origin','ilike',self), ('supplier_invoice_number', 'ilike', self)]"/>
                     <filter name="draft" icon="terp-document-new" string="Draft" domain="[('state','=','draft')]" help="Draft Invoices"/>
                     <filter name="proforma" icon="terp-gtk-media-pause" string="Proforma" domain="[('state','=','proforma2')]" help="Proforma Invoices" groups="account.group_proforma_invoices"/>
                     <filter name="invoices" icon="terp-dolar" string="Invoices" domain="[('state','not in',['draft','cancel'])]" help="Proforma/Open/Paid Invoices"/>
index f938870..67a55d8 100644 (file)
@@ -1234,16 +1234,16 @@ class account_move_line(osv.osv):
                 vals['company_id'] = company_id[0]
         if ('account_id' in vals) and not account_obj.read(cr, uid, vals['account_id'], ['active'])['active']:
             raise osv.except_osv(_('Bad Account!'), _('You cannot use an inactive account.'))
-        if 'journal_id' in vals:
+        if 'journal_id' in vals and vals['journal_id']:
             context['journal_id'] = vals['journal_id']
-        if 'period_id' in vals:
+        if 'period_id' in vals and vals['period_id']:
             context['period_id'] = vals['period_id']
         if ('journal_id' not in context) and ('move_id' in vals) and vals['move_id']:
             m = move_obj.browse(cr, uid, vals['move_id'])
             context['journal_id'] = m.journal_id.id
             context['period_id'] = m.period_id.id
         #we need to treat the case where a value is given in the context for period_id as a string
-        if 'period_id' not in context or not isinstance(context.get('period_id', ''), (int, long)):
+        if 'period_id' in context and not isinstance(context.get('period_id', ''), (int, long)):
             period_candidate_ids = self.pool.get('account.period').name_search(cr, uid, name=context.get('period_id',''))
             if len(period_candidate_ids) != 1:
                 raise osv.except_osv(_('Error!'), _('No period found or more than one period found for the given date.'))
@@ -1253,6 +1253,9 @@ class account_move_line(osv.osv):
         self._update_journal_check(cr, uid, context['journal_id'], context['period_id'], context)
         move_id = vals.get('move_id', False)
         journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
+        vals['journal_id'] = vals.get('journal_id') or context.get('journal_id')
+        vals['period_id'] = vals.get('period_id') or context.get('period_id')
+        vals['date'] = vals.get('date') or context.get('date')
         if not move_id:
             if journal.centralisation:
                 #Check for centralisation
index 1b614a1..7457954 100644 (file)
             <field name="view_mode">form</field>
             <field name="target">new</field>
         </record>
-        <record id="ir_actions_server_action_wizard_multi_chart" model="ir.actions.server">
-            <field name="type">ir.actions.server</field>
-            <field name="condition">True</field>
-            <field name="state">code</field>
-            <field name="model_id" ref="base.model_ir_actions_todo"/>
-            <field eval="5" name="sequence"/>
-            <field name="code">
-# check for unconfigured companies
-account_installer_obj = self.pool.get('account.installer')
-account_installer_obj.check_unconfigured_cmp(cr, uid, context=context)
-action_ids = []
-# fetch the act_window actions related to chart of account configuration
-# we use ir.actions.todo to enable the possibility for other modules to insert their own
-# wizards during the configuration process
-ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'action_wizard_multi_chart')
-if ref:
-    action_ids += [ref[1]]
-ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'action_account_configuration_installer')
-if ref:
-    action_ids += [ref[1]]
-todo_ids = pool.get('ir.actions.todo').search(cr, uid, [('action_id', 'in', action_ids)], context=context)
-pool.get('ir.actions.todo').write(cr, uid, todo_ids, {'state':'open'}, context=context)
-action = pool.get('res.config').next(cr, uid, [], context)
-</field>
-           <field name="name">New Company Financial Setting</field>
-        </record>
 
         <record id="account_account_graph" model="ir.ui.view">
             <field name="name">account.account.graph</field>
index 6173ea9..05a0f6b 100644 (file)
@@ -119,15 +119,6 @@ class account_installer(osv.osv_memory):
         self.execute_simple(cr, uid, ids, context)
         super(account_installer, self).execute(cr, uid, ids, context=context)
 
-    def action_next(self, cr, uid, ids, context=None):
-        next = self.execute(cr, uid, ids, context=context)
-        for installer in self.browse(cr, uid, ids, context=context):
-            if installer.charts == 'l10n_be':
-                return {'type': 'ir.actions.act_window_close'}
-            else :
-                if next : return next
-                return self.next(cr, uid, ids, context=context)
-
     def execute_simple(self, cr, uid, ids, context=None):
         if context is None:
             context = {}
index 70db954..d0813ed 100644 (file)
                             </div>
                         </group>
                         <group string="Product Information">
-                            <field name="product_id"/>
+                            <field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id, journal_id)"/>
                             <label for="unit_amount"/>
                             <div>
                                 <field name="unit_amount" class="oe_inline"/>
             <field name="name">account.analytic.line.tree</field>
             <field name="model">account.analytic.line</field>
             <field name="arch" type="xml">
-                <tree editable="top" string="Analytic Entries">
+                <tree string="Analytic Entries">
                     <field name="date"/>
                     <field name="ref" invisible="context.get('to_invoice', False)"/>
                     <field name="name"/>
index 8b82380..3e8b9b0 100644 (file)
         </td>
         <td>
           <para style="terp_default_9">[[ o.title.name or '' ]] [[ o.name ]]</para>
-          <para style="terp_default_9">[[ display_address(o.partner_id) ]]</para>
+          <para style="terp_default_9">[[ display_address(o) ]]</para>
           <para style="terp_default_9">
             <font color="white"> </font>
           </para>
index e8bf24f..8e72e24 100644 (file)
@@ -11,7 +11,7 @@ openerp.account = function (instance) {
             this._super.apply(this, arguments);
             var self = this;
             this.current_partner = null;
-            this.do_select.add(function() {
+            this.on('record_selected', this, function() {
                 if (self.get_selected_ids().length === 0) {
                     self.$(".oe_account_recon_reconcile").attr("disabled", "");
                 } else {
@@ -19,7 +19,7 @@ openerp.account = function (instance) {
                 }
             });
         },
-        on_loaded: function() {
+        load_list: function() {
             var self = this;
             var tmp = this._super.apply(this, arguments);
             if (this.partners) {
@@ -102,7 +102,6 @@ openerp.account = function (instance) {
                     action_id: result[1],
                     context: additional_context
                 }).then(function (result) {
-                    result = result.result;
                     result.context = _.extend(result.context || {}, additional_context);
                     result.flags = result.flags || {};
                     result.flags.new_window = true;
@@ -121,6 +120,10 @@ openerp.account = function (instance) {
                 self.do_search(self.last_domain, self.last_context, self.last_group_by);
             });
         },
+        do_select: function (ids, records) {
+            this.trigger('record_selected')
+            this._super.apply(this, arguments);
+        },
     });
     
 };
index 65ae287..df58da6 100644 (file)
 -
   !record {model: account.move, id: account_move_0}:
     date: !eval time.strftime('%Y-%m-%d')
+    period_id: account.period_6
     journal_id: account.bank_journal
     line_id:
       - account_id: account.cash
         amount_currency: 0.0
         credit: 2000.0
-        date: !eval time.strftime('%Y-%m-%d')
         debit: 0.0
-        journal_id: account.bank_journal
         name: Basic Computer
         partner_id: base.res_partner_12
-        period_id: account.period_6
         ref: '2011010'
         tax_amount: 0.0
     name: /
-    period_id: account.period_6
     ref: '2011010'
     state: draft
 -
     partial_reconcile = self.trans_rec_reconcile_partial_reconcile(cr, uid, [ref('account_move_line_reconcile0')], {'lang': u'en_US',
       'active_model': 'account.move.line', 'active_ids': ids, 'tz': False, 'active_id': ids[0]})
     move_line = move_line_obj.browse(cr, uid, ids)
-    assert move_line[0].reconcile_partial_id, "Partial reconcilation is not done"
\ No newline at end of file
+    assert move_line[0].reconcile_partial_id, "Partial reconcilation is not done"
index c3029cd..c176d3a 100644 (file)
@@ -1,38 +1,23 @@
-# Spanish translation for openobject-addons
-# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
+# Spanish (Mexico) 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>, 2010.
+# 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: 2011-01-11 11:14+0000\n"
-"PO-Revision-Date: 2010-11-23 09:43+0000\n"
-"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
-"<jesteve@zikzakmedia.com>\n"
-"Language-Team: Spanish <es@li.org>\n"
+"POT-Creation-Date: 2012-02-08 00:35+0000\n"
+"PO-Revision-Date: 2012-10-22 17:44+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: Spanish (Mexico) <es_MX@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: 2011-09-05 05:48+0000\n"
-"X-Generator: Launchpad (build 13830)\n"
+"X-Launchpad-Export-Date: 2012-10-23 04:48+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
 
 #. module: account_cancel
-#: model:ir.module.module,description:account_cancel.module_meta_information
-msgid ""
-"\n"
-"    Module adds 'Allow cancelling entries' field on form view of account "
-"journal. If set to true it allows user to cancel entries & invoices.\n"
-"    "
-msgstr ""
-"\n"
-"    Este módulo añade el campo 'Permitir la cancelación de asientos' en la "
-"vista de formulario de los diarios contables. Si está marcado, permite a los "
-"usuarios cancelar los asientos y las facturas.\n"
-"    "
-
-#. module: account_cancel
-#: model:ir.module.module,shortdesc:account_cancel.module_meta_information
-msgid "Account Cancel"
-msgstr "Cancelar asientos/facturas"
+#: view:account.invoice:0
+msgid "Cancel"
+msgstr "Cancelar"
index 6485764..3ae4213 100644 (file)
@@ -1422,7 +1422,7 @@ class account_voucher_line(osv.osv):
     }
 
     def onchange_reconcile(self, cr, uid, ids, reconcile, amount, amount_unreconciled, context=None):
-        vals = { 'amount': 0.0}
+        vals = {'amount': 0.0}
         if reconcile:
             vals = { 'amount': amount_unreconciled}
         return {'value': vals}
index f8e20f4..c9270dc 100644 (file)
@@ -53,7 +53,6 @@
     account_id: account.cash
     amount: 1000.0
     company_id: base.main_company
-    currency_id: base.EUR
     journal_id: account.bank_journal
     name: Voucher Axelor
     narration: PC Assemble SC234
index 88f10e5..b71e42a 100644 (file)
@@ -45,7 +45,6 @@
         'account_id': ref('account.cash'),
         'amount': 450.0,
         'company_id': ref('base.main_company'),
-        'currency_id': ref('base.EUR'),
         'journal_id': ref('account.bank_journal'),
         'partner_id': ref('base.res_partner_19'),
         'period_id': ref('account.period_8'),
     }
     if not res['value']['line_cr_ids']:
       res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
+    #clients aren't sending value of readonly fields in the view, and there is a good reason for that, so here the
+    #create should only use values of fields that are not readonly. That's why i'm removing some of these values
+    del(res['value']['line_cr_ids'][0]['date_original'])
+    del(res['value']['line_cr_ids'][0]['date_due'])
     res['value']['line_cr_ids'][0]['amount'] = 450.0
     vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
     id = self.create(cr, uid, vals)
index 7cd82ee..cf4bc5c 100644 (file)
@@ -53,7 +53,6 @@
         'account_id': ref('account.cash'),
         'amount': 30000.0,
         'company_id': ref('base.main_company'),
-        'currency_id': ref('base.EUR'),
         'journal_id': ref('account.bank_journal'),
         'partner_id': ref('base.res_partner_19'),
         'period_id': ref('account.period_8'),
index 1ce483a..5ea8c59 100644 (file)
@@ -255,27 +255,27 @@ class account_analytic_account(osv.osv):
         if context is None:
             context={}
         if context.get('current_model') == 'project.project':
-            cr.execute("select analytic_account_id from project_project")
-            project_ids = [x[0] for x in cr.fetchall()]
+            project_obj = self.pool.get("account.analytic.account")
+            project_ids = project_obj.search(cr, uid, args)
             return self.name_get(cr, uid, project_ids, context=context)
         if name:
-            account = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context)
-            if not account:
+            account_ids = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context)
+            if not account_ids:
                 names=map(lambda i : i.strip(),name.split('/'))
                 for i in range(len(names)):
                     dom=[('name', operator, names[i])]
                     if i>0:
-                        dom+=[('id','child_of',account)]
-                    account = self.search(cr, uid, dom, limit=limit, context=context)
-                newacc = account
+                        dom+=[('id','child_of',account_ids)]
+                    account_ids = self.search(cr, uid, dom, limit=limit, context=context)
+                newacc = account_ids
                 while newacc:
                     newacc = self.search(cr, uid, [('parent_id', 'in', newacc)], limit=limit, context=context)
-                    account += newacc
+                    account_ids += newacc
                 if args:
-                    account = self.search(cr, uid, [('id', 'in', account)] + args, limit=limit, context=context)
+                    account_ids = self.search(cr, uid, [('id', 'in', account_ids)] + args, limit=limit, context=context)
         else:
-            account = self.search(cr, uid, args, limit=limit, context=context)
-        return self.name_get(cr, uid, account, context=context)
+            account_ids = self.search(cr, uid, args, limit=limit, context=context)
+        return self.name_get(cr, uid, account_ids, context=context)
 
     def create(self, cr, uid, vals, context=None):
         contract =  super(account_analytic_account, self).create(cr, uid, vals, context=context)
index 8834645..2326a41 100644 (file)
@@ -32,13 +32,23 @@ import datetime
 from osv import fields, osv
 from tools.translate import _
 
+from itertools import groupby
+from operator import itemgetter
+
 
 FIELD_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('not_existing', 'Not Existing')]
 ANONYMIZATION_STATES = FIELD_STATES + [('unstable', 'Unstable')]
+WIZARD_ANONYMIZATION_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('unstable', 'Unstable')]
 ANONYMIZATION_HISTORY_STATE = [('started', 'Started'), ('done', 'Done'), ('in_exception', 'Exception occured')]
 ANONYMIZATION_DIRECTION = [('clear -> anonymized', 'clear -> anonymized'), ('anonymized -> clear', 'anonymized -> clear')]
 
 
+def group(lst, cols):
+    if isinstance(cols, basestring):
+        cols = [cols]
+    return dict((k, [v for v in itr]) for k, itr in groupby(sorted(lst, key=itemgetter(*cols)), itemgetter(*cols)))
+
+
 class ir_model_fields_anonymization(osv.osv):
     _name = 'ir.model.fields.anonymization'
     _rec_name = 'field_id'
@@ -207,8 +217,6 @@ class ir_model_fields_anonymization(osv.osv):
         'state': lambda *a: 'clear',
     }
 
-ir_model_fields_anonymization()
-
 
 class ir_model_fields_anonymization_history(osv.osv):
     _name = 'ir.model.fields.anonymization.history'
@@ -223,8 +231,6 @@ class ir_model_fields_anonymization_history(osv.osv):
         'filepath': fields.char(string='File path', size=256, readonly=True),
     }
 
-ir_model_fields_anonymization_history()
-
 
 class ir_model_fields_anonymize_wizard(osv.osv_memory):
     _name = 'ir.model.fields.anonymize.wizard'
@@ -250,8 +256,8 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
         'name': fields.char(size=64, string='File Name'),
         'summary': fields.function(_get_summary, type='text', string='Summary'),
         'file_export': fields.binary(string='Export'),
-        'file_import': fields.binary(string='Import'),
-        'state': fields.function(_get_state, string='Status', type='selection', selection=ANONYMIZATION_STATES, readonly=False),
+        'file_import': fields.binary(string='Import', help="This is the file created by the anonymization process. It should have the '.pickle' extention."),
+        'state': fields.function(_get_state, string='Status', type='selection', selection=WIZARD_ANONYMIZATION_STATES, readonly=False),
         'msg': fields.text(string='Message'),
     }
 
@@ -319,6 +325,7 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
                 # clicked in the menu and the fields are already anonymized
                 placeholder.addnext(etree.Element('newline'))
                 placeholder.addnext(etree.Element('field', {'name': 'file_import', 'required': "1"}))
+                placeholder.addnext(etree.Element('label', {'string': 'Anonymization file'}))
                 eview.remove(placeholder)
             elif step == 'just_anonymized':
                 # we just ran the anonymization process, we need the file export field
@@ -500,7 +507,6 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
 
     def reverse_anonymize_database(self, cr, uid, ids, context=None):
         """Set the 'clear' state to defined fields"""
-
         ir_model_fields_anonymization_model = self.pool.get('ir.model.fields.anonymization')
         anonymization_history_model = self.pool.get('ir.model.fields.anonymization.history')
 
@@ -524,23 +530,46 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
         wizards = self.browse(cr, uid, ids, context=context)
         for wizard in wizards:
             if not wizard.file_import:
-                msg = "It is not possible to reverse the anonymization process without supplying anonymization export file."
+                msg = "It is not possible to reverse the anonymization process without supplying the anonymization export file."
                 self._raise_after_history_update(cr, uid, history_id, 'Error !', msg)
 
             # reverse the anonymization:
             # load the pickle file content into a data structure:
             data = pickle.loads(base64.decodestring(wizard.file_import))
 
+            migration_fix_obj = self.pool.get('ir.model.fields.anonymization.migration.fix')
+            fix_ids = migration_fix_obj.search(cr, uid, [('target_version', '=', '7.0')])
+            fixes = migration_fix_obj.read(cr, uid, fix_ids, ['model_name', 'field_name', 'query', 'query_type', 'sequence'])
+            fixes = group(fixes, ('model_name', 'field_name'))
+
             for line in data:
                 table_name = self.pool.get(line['model_id'])._table
-                sql = "update %(table)s set %(field)s = %%(value)s where id = %%(id)s" % {
-                    'table': table_name,
-                    'field': line['field_id'],
-                }
-                cr.execute(sql, {
-                    'value': line['value'],
-                    'id': line['id']
-                })
+
+                # check if custom sql exists:
+                key = (line['model_id'], line['field_id'])
+                custom_updates =  fixes.get(key)
+                if custom_updates:
+                    custom_updates.sort(itemgetter('sequence'))
+                    queries = [(record['query'], record['query_type']) for record in custom_updates if record['query_type']]
+                else:
+                    queries = [("update %(table)s set %(field)s = %%(value)s where id = %%(id)s" % {
+                        'table': table_name,
+                        'field': line['field_id'],
+                    }, 'sql')]
+
+                for query in queries:
+                    if query[1] == 'sql':
+                        sql = query[0]
+                        cr.execute(sql, {
+                            'value': line['value'],
+                            'id': line['id']
+                        })
+                    elif query[1] == 'python':
+                        raw_code = query[0]
+                        code = raw_code % line
+                        eval(code)
+                    else:
+                        raise Exception("Unknown query type '%s'. Valid types are: sql, python." % (query['query_type'], ))
 
             # update the anonymization fields:
             ir_model_fields_anonymization_model = self.pool.get('ir.model.fields.anonymization')
@@ -589,7 +618,19 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
             res = None
         return res
 
-ir_model_fields_anonymize_wizard()
 
+class ir_model_fields_anonymization_migration_fix(osv.osv):
+    _name = 'ir.model.fields.anonymization.migration.fix'
+    _order = "sequence"
+
+    _columns = {
+        'target_version': fields.char('Target Version'),
+        'model_name': fields.char('Model'),
+        'field_name': fields.char('Field'),
+        'query': fields.text('Query'),
+        'query_type': fields.selection(string='Query', selection=[('sql', 'sql'), ('python', 'python')]),
+        'sequence': fields.integer('Sequence'),
+    }
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
index 1a6c6c3..fca112e 100644 (file)
@@ -14,7 +14,6 @@
                     <field name="model_id" on_change="onchange_model_id(model_id)" />
                     <field name="model_name" on_change="onchange_model_name(model_name)" />
                     <field name="field_id"
-                          
                            on_change="onchange_field_id(field_id, model_name)"
                            domain="[('model_id','=',model_id), ('ttype', 'not in', ['function', 'binary', 'many2many', 'many2one', 'one2many', 'reference'])]" />
                     <field name="field_name" on_change="onchange_field_name(field_name, model_name)" />
diff --git a/addons/anonymization/i18n/mn.po b/addons/anonymization/i18n/mn.po
new file mode 100644 (file)
index 0000000..3ba9787
--- /dev/null
@@ -0,0 +1,213 @@
+# 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:35+0000\n"
+"PO-Revision-Date: 2012-10-22 02:35+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-10-23 04:48+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymize_wizard
+msgid "ir.model.fields.anonymize.wizard"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,field_name:0
+msgid "Field Name"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,field_id:0
+msgid "Field"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,state:0
+#: field:ir.model.fields.anonymize.wizard,state:0
+msgid "State"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,file_import:0
+msgid "Import"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization
+msgid "ir.model.fields.anonymization"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,direction:0
+msgid "Direction"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_tree
+#: view:ir.model.fields.anonymization:0
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_fields
+msgid "Anonymized Fields"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization
+msgid "Database anonymization"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,direction:0
+msgid "clear -> anonymized"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Anonymized"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,state:0
+msgid "unknown"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,model_id:0
+msgid "Object"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,filepath:0
+msgid "File path"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,date:0
+msgid "Date"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,file_export:0
+msgid "Export"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Reverse the Database Anonymization"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Database Anonymization"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_wizard
+msgid "Anonymize database"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization.history:0
+#: field:ir.model.fields.anonymization.history,field_ids:0
+msgid "Fields"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Clear"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+#: field:ir.model.fields.anonymize.wizard,summary:0
+msgid "Summary"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization:0
+msgid "Anonymized Field"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Unstable"
+msgstr "Тогтмол биш"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Exception occured"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Not Existing"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,model_name:0
+msgid "Object Name"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_history_tree
+#: view:ir.model.fields.anonymization.history:0
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_history
+msgid "Anonymization History"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization_history
+msgid "ir.model.fields.anonymization.history"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymize_wizard
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Anonymize Database"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,name:0
+msgid "File Name"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,direction:0
+msgid "anonymized -> clear"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Started"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Done"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization.history:0
+#: field:ir.model.fields.anonymization.history,msg:0
+#: field:ir.model.fields.anonymize.wizard,msg:0
+msgid "Message"
+msgstr ""
+
+#. module: anonymization
+#: code:addons/anonymization/anonymization.py:55
+#: sql_constraint:ir.model.fields.anonymization:0
+#, python-format
+msgid "You cannot have two fields with the same name on the same object!"
+msgstr ""
index 7e9bbac..683a247 100644 (file)
 #
 ##############################################################################
 
-from osv import fields, osv, orm
-from tools.translate import _
 from datetime import datetime
 from datetime import timedelta
+import re
+import time
+
+from osv import fields, osv, orm
+from tools.translate import _
 from tools.safe_eval import safe_eval
 from tools import ustr
 import pooler
-import re
-import time
 import tools
 
 
@@ -48,32 +49,21 @@ class base_action_rule(osv.osv):
     _description = 'Action Rules'
 
     def _state_get(self, cr, uid, context=None):
-        """ Get State
-            @param self: The object pointer
-            @param cr: the current row, from the database cursor,
-            @param uid: the current user’s ID for security checks,
-            @param context: A standard dictionary for contextual values """
+        """ Get State """
         return self.state_get(cr, uid, context=context)
 
     def state_get(self, cr, uid, context=None):
-        """ Get State
-            @param self: The object pointer
-            @param cr: the current row, from the database cursor,
-            @param uid: the current user’s ID for security checks,
-            @param context: A standard dictionary for contextual values """
+        """ Get State """
         return [('', '')]
 
     def priority_get(self, cr, uid, context=None):
-        """ Get Priority
-            @param self: The object pointer
-            @param cr: the current row, from the database cursor,
-            @param uid: the current user’s ID for security checks,
-            @param context: A standard dictionary for contextual values """
+        """ Get Priority """
         return [('', '')]
 
     _columns = {
         'name':  fields.char('Rule Name', size=64, required=True),
-        'model_id': fields.many2one('ir.model', 'Object', required=True),
+        'model_id': fields.many2one('ir.model', 'Related Document Model', required=True, domain=[('osv_memory','=', False)]),
+        'model': fields.related('model_id', 'model', type="char", size=256, string='Model'),
         'create_date': fields.datetime('Create Date', readonly=1),
         'active': fields.boolean('Active', help="If the active field is set to False,\
  it will allow you to hide the rule without removing it."),
@@ -82,6 +72,7 @@ when displaying a list of rules."),
         'trg_date_type':  fields.selection([
             ('none', 'None'),
             ('create', 'Creation Date'),
+            ('write', 'Last Modified Date'),
             ('action_last', 'Last Action Date'),
             ('date', 'Date'),
             ('deadline', 'Deadline'),
@@ -98,78 +89,39 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
         'trg_state_from': fields.selection(_state_get, 'Status', size=16),
         'trg_state_to': fields.selection(_state_get, 'Button Pressed', size=16),
 
-        'act_method': fields.char('Call Object Method', size=64),
         'act_user_id': fields.many2one('res.users', 'Set Responsible to'),
         'act_state': fields.selection(_state_get, 'Set State to', size=16),
-        'act_email_cc': fields.char('Add Watchers (Cc)', size=250, help="\
-These people will receive a copy of the future communication between partner \
-and users by email"),
-        'act_remind_partner': fields.boolean('Remind Partner', help="Check \
-this if you want the rule to send a reminder by email to the partner."),
-        'act_remind_user': fields.boolean('Remind Responsible', help="Check \
-this if you want the rule to send a reminder by email to the user."),
-        'act_reply_to': fields.char('Reply-To', size=64),
-        'act_remind_attach': fields.boolean('Remind with Attachment', help="Check this if you want that all documents attached to the object be attached to the reminder email sent."),
-        'act_mail_to_user': fields.boolean('Mail to Responsible', help="Check\
- this if you want the rule to send an email to the responsible person."),
-        'act_mail_to_watchers': fields.boolean('Mail to Watchers (CC)',
-                                                help="Check this if you want \
-the rule to mark CC(mail to any other person defined in actions)."),
-        'act_mail_to_email': fields.char('Mail to these Emails', size=128, \
-        help="Email-id of the persons whom mail is to be sent"),
-        'act_mail_body': fields.text('Mail body', help="Content of mail"),
+        'act_followers': fields.many2many("res.partner", string="Set Followers"),
         'regex_name': fields.char('Regex on Resource Name', size=128, help="Regular expression for matching name of the resource\
 \ne.g.: 'urgent.*' will search for records having name starting with the string 'urgent'\
 \nNote: This is case sensitive search."),
-        'server_action_id': fields.many2one('ir.actions.server', 'Server Action', help="Describes the action name.\neg:on which object which action to be taken on basis of which condition"),
-        'filter_id':fields.many2one('ir.filters', 'Filter', required=False),
-        'act_email_from' : fields.char('Email From', size=64, required=False,
-                help="Use a python expression to specify the right field on which one than we will use for the 'From' field of the header"),
-        'act_email_to' : fields.char('Email To', size=64, required=False,
-                                     help="Use a python expression to specify the right field on which one than we will use for the 'To' field of the header"),
+        'server_action_ids': fields.one2many('ir.actions.server', 'action_rule_id', 'Server Action', help="Define Server actions.\neg:Email Reminders, Call Object Service, etc.."), #TODO: set domain [('model_id','=',model_id)]
+        'filter_id':fields.many2one('ir.filters', 'Filter', required=False), #TODO: set domain [('model_id','=',model_id.model)]
         'last_run': fields.datetime('Last Run', readonly=1),
     }
 
     _defaults = {
-        'active': lambda *a: True,
-        'trg_date_type': lambda *a: 'none',
-        'trg_date_range_type': lambda *a: 'day',
-        'act_mail_to_user': lambda *a: 0,
-        'act_remind_partner': lambda *a: 0,
-        'act_remind_user': lambda *a: 0,
-        'act_mail_to_watchers': lambda *a: 0,
+        'active': True,
+        'trg_date_type': 'none',
+        'trg_date_range_type': 'day',
     }
 
     _order = 'sequence'
 
-    def onchange_model_id(self, cr, uid, ids, name):
-        #This is not a good solution as it will affect the domain only on onchange
-        res = {'domain':{'filter_id':[]}}
-        if name:
-            model_name = self.pool.get('ir.model').read(cr, uid, [name], ['model'])
-            if model_name:
-                mod_name = model_name[0]['model']
-                res['domain'] = {'filter_id': [('model_id','=',mod_name)]}
-        else:
-            res['value'] = {'filter_id':False}
-        return res
 
     def post_action(self, cr, uid, ids, model, context=None):
         # Searching for action rules
         cr.execute("SELECT model.model, rule.id  FROM base_action_rule rule \
                         LEFT JOIN ir_model model on (model.id = rule.model_id) \
-                        WHERE active")
+                        WHERE active and model = %s", (model,))
         res = cr.fetchall()
         # Check if any rule matching with current object
         for obj_name, rule_id in res:
-            if not (model == obj_name):
-                continue # TODO add this condition in the WHERE clause above.
-            else:
-                obj = self.pool.get(obj_name)
-                # If the rule doesn't involve a time condition, run it immediately
-                # Otherwise we let the scheduler run the action
-                if self.browse(cr, uid, rule_id, context=context).trg_date_type == 'none':
-                    self._action(cr, uid, [rule_id], obj.browse(cr, uid, ids, context=context), context=context)
+            obj = self.pool.get(obj_name)
+            # If the rule doesn't involve a time condition, run it immediately
+            # Otherwise we let the scheduler run the action
+            if self.browse(cr, uid, rule_id, context=context).trg_date_type == 'none':
+                self._action(cr, uid, [rule_id], obj.browse(cr, uid, ids, context=context), context=context)
         return True
 
     def _create(self, old_create, model, context=None):
@@ -232,24 +184,30 @@ the rule to mark CC(mail to any other person defined in actions)."),
         """
         This Function is call by scheduler.
         """
-        rule_pool = self.pool.get('base.action.rule')
-        rule_ids = rule_pool.search(cr, uid, [], context=context)
+        rule_ids = self.search(cr, uid, [], context=context)
         self._register_hook(cr, uid, rule_ids, context=context)
-
-        rules = self.browse(cr, uid, rule_ids, context=context)
-        for rule in rules:
+        if context is None:
+            context = {}
+        for rule in self.browse(cr, uid, rule_ids, context=context):
             model = rule.model_id.model
             model_pool = self.pool.get(model)
             last_run = False
             if rule.last_run:
                 last_run = get_datetime(rule.last_run)
             now = datetime.now()
-            for obj_id in model_pool.search(cr, uid, [], context=context):
-                obj = model_pool.browse(cr, uid, obj_id, context=context)
+            ctx = dict(context)            
+            if rule.filter_id and rule.model_id.model == rule.filter_id.model_id:
+                ctx.update(eval(rule.filter_id.context))
+                obj_ids = model_pool.search(cr, uid, eval(rule.filter_id.domain), context=ctx)
+            else:
+                obj_ids = model_pool.search(cr, uid, [], context=ctx)
+            for obj in model_pool.browse(cr, uid, obj_ids, context=ctx):
                 # Calculate when this action should next occur for this object
                 base = False
                 if rule.trg_date_type=='create' and hasattr(obj, 'create_date'):
                     base = obj.create_date
+                elif rule.trg_date_type=='write' and hasattr(obj, 'write_date'):
+                    base = obj.write_date
                 elif (rule.trg_date_type=='action_last'
                         and hasattr(obj, 'create_date')):
                     if hasattr(obj, 'date_action_last') and obj.date_action_last:
@@ -275,73 +233,25 @@ the rule to mark CC(mail to any other person defined in actions)."),
                     delay = fnct[rule.trg_date_range_type](rule.trg_date_range)
                     action_date = base + delay
                     if (not last_run or (last_run <= action_date < now)):
-                        self._action(cr, uid, [rule.id], [obj], context=context)
-            rule_pool.write(cr, uid, [rule.id], {'last_run': now},
-                            context=context)
-
-    def format_body(self, body):
-        """ Foramat Action rule's body
-            @param self: The object pointer """
-        return body and tools.ustr(body) or ''
-
-    def format_mail(self, obj, body):
-        data = {
-            'object_id': obj.id,
-            'object_subject': hasattr(obj, 'name') and obj.name or False,
-            'object_date': hasattr(obj, 'date') and obj.date or False,
-            'object_description': hasattr(obj, 'description') and obj.description or False,
-            'object_user': hasattr(obj, 'user_id') and (obj.user_id and obj.user_id.name) or '/',
-            'object_user_email': hasattr(obj, 'user_id') and (obj.user_id and \
-                                     obj.user_id.email) or '/',
-            'object_user_phone': hasattr(obj, 'partner_address_id') and (obj.partner_address_id and \
-                                     obj.partner_address_id.phone) or '/',
-            'partner': hasattr(obj, 'partner_id') and (obj.partner_id and obj.partner_id.name) or '/',
-            'partner_email': hasattr(obj, 'partner_address_id') and (obj.partner_address_id and\
-                                         obj.partner_address_id.email) or '/',
-        }
-        return self.format_body(body % data)
-
-    def email_send(self, cr, uid, obj, emails, body, emailfrom=None, context=None):
-        if not emailfrom:
-            emailfrom = tools.config.get('email_from')
-        body = self.format_mail(obj, body)
-        if not emailfrom and hasattr(obj, 'user_id') and obj.user_id and obj.user_id.email:
-            emailfrom = obj.user_id.email
-        emailfrom = tools.ustr(emailfrom)
-        reply_to = emailfrom
-        if not emailfrom:
-            raise osv.except_osv(_('Error!'),
-                                 _("Missing default email address or missing email on responsible user"))
-        return self.pool.get('mail.mail').create(cr, uid,
-                {   'email_from': emailfrom,
-                    'email_to': emails.join(','),
-                    'reply_to': reply_to,
-                    'state': 'outgoing',
-                    'subject': '[%d] %s' % (obj.id, tools.ustr(obj.name)),
-                    'body_html': '<pre>%s</pre>' % body,
-                    'res_id': obj.id,
-                    'model': obj._table_name,
-                    'auto_delete': True
-                }, context=context)
-
+                        try:
+                            self._action(cr, uid, [rule.id], obj, context=ctx)
+                            self.write(cr, uid, [rule.id], {'last_run': now}, context=context)
+                        except Exception, e:
+                            import traceback
+                            print traceback.format_exc()
+                        
+                        
 
     def do_check(self, cr, uid, action, obj, context=None):
-        """ check Action
-            @param self: The object pointer
-            @param cr: the current row, from the database cursor,
-            @param uid: the current user’s ID for security checks,
-            @param context: A standard dictionary for contextual values """
+        """ check Action """
         if context is None:
             context = {}
         ok = True
-        if action.filter_id:
-            if action.model_id.model == action.filter_id.model_id:
-                context.update(eval(action.filter_id.context))
-                obj_ids = obj._table.search(cr, uid, eval(action.filter_id.domain), context=context)
-                if not obj.id in obj_ids:
-                    ok = False
-            else:
-                ok = False
+        if action.filter_id and action.model_id.model == action.filter_id.model_id:
+            ctx = dict(context)
+            ctx.update(eval(action.filter_id.context))
+            obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_id.domain), context=ctx)
+            ok = ok and obj.id in obj_ids
         if getattr(obj, 'user_id', False):
             ok = ok and (not action.trg_user_id.id or action.trg_user_id.id==obj.user_id.id)
         if getattr(obj, 'partner_id', False):
@@ -372,120 +282,62 @@ the rule to mark CC(mail to any other person defined in actions)."),
         ok = ok and regex_n
         return ok
 
-    def do_action(self, cr, uid, action, model_obj, obj, context=None):
-        """ Do Action
-            @param self: The object pointer
-            @param cr: the current row, from the database cursor,
-            @param uid: the current user’s ID for security checks,
-            @param action: pass action
-            @param model_obj: pass Model object
-            @param context: A standard dictionary for contextual values """
+    def do_action(self, cr, uid, action, obj, context=None):
+        """ Do Action """
         if context is None:
             context = {}
+        ctx = dict(context)
+        model_obj = self.pool.get(action.model_id.model)
+        action_server_obj = self.pool.get('ir.actions.server')
+        if action.server_action_ids:
+            ctx.update({'active_model': action.model_id.model, 'active_id':obj.id, 'active_ids':[obj.id]})
+            action_server_obj.run(cr, uid, [x.id for x in action.server_action_ids], context=ctx)
 
-        if action.server_action_id:
-            context.update({'active_id':obj.id, 'active_ids':[obj.id]})
-            self.pool.get('ir.actions.server').run(cr, uid, [action.server_action_id.id], context)
         write = {}
-
         if hasattr(obj, 'user_id') and action.act_user_id:
-            obj.user_id = action.act_user_id
             write['user_id'] = action.act_user_id.id
         if hasattr(obj, 'date_action_last'):
             write['date_action_last'] = time.strftime('%Y-%m-%d %H:%M:%S')
         if hasattr(obj, 'state') and action.act_state:
-            obj.state = action.act_state
             write['state'] = action.act_state
-
-        if hasattr(obj, 'categ_id') and action.act_categ_id:
-            obj.categ_id = action.act_categ_id
-            write['categ_id'] = action.act_categ_id.id
-
+        
         model_obj.write(cr, uid, [obj.id], write, context)
-
-        if hasattr(model_obj, 'remind_user') and action.act_remind_user:
-            model_obj.remind_user(cr, uid, [obj.id], context, attach=action.act_remind_attach)
-        if hasattr(model_obj, 'remind_partner') and action.act_remind_partner:
-            model_obj.remind_partner(cr, uid, [obj.id], context, attach=action.act_remind_attach)
-        if action.act_method:
-            getattr(model_obj, 'act_method')(cr, uid, [obj.id], action, context)
-
-        emails = []
-        if hasattr(obj, 'user_id') and action.act_mail_to_user:
-            if obj.user_id:
-                emails.append(obj.user_id.email)
-
-        if action.act_mail_to_watchers:
-            emails += (action.act_email_cc or '').split(',')
-        if action.act_mail_to_email:
-            emails += (action.act_mail_to_email or '').split(',')
-
-        locals_for_emails = {
-            'user' : self.pool.get('res.users').browse(cr, uid, uid, context=context),
-            'obj' : obj,
-        }
-
-        if action.act_email_to:
-            emails.append(safe_eval(action.act_email_to, {}, locals_for_emails))
-
-        emails = filter(None, emails)
-        if len(emails) and action.act_mail_body:
-            emails = list(set(emails))
-            email_from = safe_eval(action.act_email_from, {}, locals_for_emails)
-            emails = tools.email_split(','.join(filter(None, emails)))
-            email_froms = tools.email_split(email_from)
-            if email_froms:
-                self.email_send(cr, uid, obj, emails, action.act_mail_body, emailfrom=email_froms[0])
+        if hasattr(obj, 'state') and hasattr(obj, 'message_post') and action.act_state:
+            model_obj.message_post(cr, uid, [obj], _(action.act_state), context=context)
+        
+        if hasattr(obj, 'message_subscribe') and action.act_followers:
+            exits_followers = [x.id for x in obj.message_follower_ids]
+            new_followers = [x.id for x in action.act_followers if x.id not in exits_followers]
+            if new_followers:
+                model_obj.message_subscribe(cr, uid, [obj.id], new_followers, context=context)
         return True
 
     def _action(self, cr, uid, ids, objects, scrit=None, context=None):
-        """ Do Action
-            @param self: The object pointer
-            @param cr: the current row, from the database cursor,
-            @param uid: the current user’s ID for security checks,
-            @param ids: List of Basic Action Rule’s IDs,
-            @param objects: pass objects
-            @param context: A standard dictionary for contextual values """
+        """ Do Action """
         if context is None:
             context = {}
 
         context.update({'action': True})
         if not scrit:
             scrit = []
-
+        if not isinstance(objects, list):
+            objects = [objects]
         for action in self.browse(cr, uid, ids, context=context):
             for obj in objects:
                 if self.do_check(cr, uid, action, obj, context=context):
-                    model_obj = self.pool.get(action.model_id.model)
-                    self.do_action(cr, uid, action, model_obj, obj, context=context)
+                    self.do_action(cr, uid, action, obj, context=context)
 
         context.update({'action': False})
         return True
 
-    def _check_mail(self, cr, uid, ids, context=None):
-        """ Check Mail
-            @param self: The object pointer
-            @param cr: the current row, from the database cursor,
-            @param uid: the current user’s ID for security checks,
-            @param ids: List of Action Rule’s IDs
-            @param context: A standard dictionary for contextual values """
-
-        empty = orm.browse_null()
-        rule_obj = self.pool.get('base.action.rule')
-        for rule in self.browse(cr, uid, ids, context=context):
-            if rule.act_mail_body:
-                try:
-                    rule_obj.format_mail(empty, rule.act_mail_body)
-                except (ValueError, KeyError, TypeError):
-                    return False
-        return True
-
-    _constraints = [
-        (_check_mail, 'Error ! The mail is not well formated.', ['act_mail_body']),
-    ]
-
 base_action_rule()
 
+class actions_server(osv.osv):
+    _inherit = 'ir.actions.server'
+    _columns = {
+        'action_rule_id': fields.many2one("base.action.rule", string="Action Rule")
+    }
+actions_server()
 
 class ir_cron(osv.osv):
     _inherit = 'ir.cron'
index 0d26843..fe8ff9b 100644 (file)
@@ -15,8 +15,9 @@
                     <sheet>
                         <group col="4">
                             <field name="name"/>
-                            <field name="model_id" on_change="onchange_model_id(model_id)"/>
-                            <field name="filter_id" />
+                            <field name="model_id"/>
+                            <field name="model" invisible="1"/>
+                            <field name="filter_id" domain="[('model_id','=',model)]" context="{'default_model_id': model}"/>
                             <field name="sequence"/>
                             <field name="active"/>
                         </group>
                                         <field name="trg_partner_id"/>
                                         <field name="trg_partner_categ_id"/>
                                     </group>
-                                    <group string="Conditions on States">
+                                    <group name="state" string="Conditions on Status">
                                         <field name="trg_state_from"/>
                                         <field name="trg_state_to"/>
                                     </group>
-                                    <group string="Conditions on Timing">
+                                    <group name="timing" string="Conditions on Timing">
                                         <field name="trg_date_type"/>
-                                        <group attrs="{'invisible': [('trg_date_type', '=', 'none')]}">
-                                            <field name="trg_date_range" string="Delay After Trigger Date"/>
-                                            <field name="trg_date_range_type"/>
-                                        </group>
+                                        <field name="trg_date_range" string="Delay After Trigger Date" attrs="{'invisible': [('trg_date_type', '=', 'none')]}"/>
+                                        <field name="trg_date_range_type" attrs="{'invisible': [('trg_date_type', '=', 'none')]}"/>
                                     </group>
                                 </group>
-                                <separator string="Note"/>
-                                <label string="The rule uses the AND operator. The model must match all non-empty fields so that the rule executes the action described in the 'Actions' tab." />
+                                <group string="Note">
+                                    <label string="The rule uses the AND operator. The model must match all non-empty fields so that the rule executes the action  described in the 'Actions' tab." />
+                                </group>
                             </page>
                             <page string="Actions">
-                                <group string="Fields to Change" col="4">
+                                <group name="action_followers">
+                                    <field name="act_followers" widget="many2many_tags"/>
+                                </group>
+                                <group name="action_field" col="4" string="Fields to Change">
                                     <field name="act_user_id"/>
                                     <field name="act_state"/>
                                 </group>
-                                <group col="2" string="Server Action to be Triggered">
-                                    <field name="server_action_id"/>
-                                </group>
-                            </page>
-                            <page string="Email Actions">
-                                <group col="4">
-                                    <separator colspan="4" string="Email Reminders"/>
-                                    <field name="act_remind_partner"/>
-                                    <field name="act_remind_attach"/>
-                                    <field name="act_remind_user"/>
-                                    <group col="2" colspan="2" attrs="{'invisible': [('act_remind_user','=',False)]}">
-                                        <field name="act_reply_to" attrs="{'required':[('act_remind_user','=',True)]}"/>
-                                    </group>
-                                    <separator colspan="4" string="Email Information"/>
-                                    <field name="act_email_from" />
-                                    <field name="act_email_to" />
-                                    <field name="act_mail_to_user"/>
-                                    <field colspan="4" name="act_mail_to_email"/>
-                                    <field name="act_mail_to_watchers"/>
-                                    <field colspan="4" name="act_email_cc"/>
-                                    <separator colspan="4" string="Email Body"/>
-                                    <field colspan="4" name="act_mail_body" height="250"
-                                        nolabel="1" attrs="{'required':[('act_remind_user','=',True)]}" />
-                                    <separator colspan="4" string="Special Keywords to be Used in the Body"/>
-                                    <label align="0.0" string="%%(object_id)s = Object ID" colspan="2"/>
-                                    <label align="0.0" string="%%(object_subject)s = Object subject" colspan="2"/>
-                                    <label align="0.0" string="%%(object_description)s = Object description" colspan="2"/>
-                                    <label align="0.0" string="%%(object_date)s = Creation date" colspan="2"/>
-                                    <label align="0.0" string="%%(partner)s = Partner name" colspan="2"/>
-                                    <label align="0.0" string="%%(partner_email)s = Partner Email" colspan="2"/>
-                                    <label align="0.0" string="%%(object_user)s = Responsible name" colspan="2"/>
-                                    <label align="0.0" string="%%(object_user_email)s = Responsible Email" colspan="2"/>
-                                    <label align="0.0" string="%%(object_user_phone)s = Responsible phone" colspan="2"/>
+                                <group name="action_server" string="Server Actions to be Triggered (eg. Email Reminder, Call Object Method, etc...)" >
+                                    <field name="server_action_ids" domain="[('model_id','=', model_id)]" nolabel="1" context="{'default_model_id': model_id}">
+                                        <tree string="Server Actions">
+                                            <field name="sequence"/>
+                                            <field name="name"/>
+                                            <field name="state"/>
+                                        </tree>
+                                    </field>
                                 </group>
-                            </page>
-                        </notebook>
+                                
+                           </page>
+                       </notebook>
                     </sheet>
                 </form>
             </field>
index d5dc75d..a922521 100644 (file)
 <?xml version="1.0" encoding="utf-8"?>
 <openerp>
     <data>
-        <!-- Attendee form view -->
-        <record id="base_calendar_attendee_form_view" model="ir.ui.view">
-            <field name="name">calendar.attendee.form</field>
-            <field name="model">calendar.attendee</field>
-            <field name="arch" type="xml">
-                <form string="Invitation details" version="7.0">
-                    <header>
-                        <button name="do_tentative" states="needs-action,declined,accepted" string="Uncertain" type="object" class="oe_highlight"/>
-                        <button name="do_accept" string="Accept" states="needs-action,tentative,declined" type="object" class="oe_highlight"/>
-                        <button name="do_decline" string="Decline" states="needs-action,tentative,accepted" type="object" class="oe_highlight"/>
-                        <field name="state" widget="statusbar"
-                            statusbar_visible="tentative,needs-action,accepted" statusbar_colors='{"proforma":"blue"}'/>
-                    </header>
-                    <sheet>
-
-                        <div class="oe_title">
-                            <label for="email" string="Invitation To" class="oe_edit_only"/>
-                            <h1>
-                                <field name="email" class="oe_inline"/>
-                                (<field name="language" class="oe_inline"/>)
-                            </h1>
-
-                            <h2>
-                                From <field name="event_date" class="oe_inline"/>
-                                to <field name="event_end_date" class="oe_inline"/>
-                            </h2>
-                        </div>
-                        <group>
-                            <group>
-                                <field name="sent_by_uid" string="Invitation From"/>
-                                <field name="user_id" string="Invited User"/>
-                                <field name="partner_id" string="Contact"/>
-                            </group>
-                            <group>
-                                <field name="cutype" string="Invitation Type"/>
-                                <field name="role" string="Role"/>
-                                <field name="rsvp"/>
-                                <field name="ref" readonly="1"/>
-                            </group>
-                        </group>
-                        <group>
-                            <group string="Delegated From">
-                                <field name="parent_ids" readonly="1" nolabel="1"/>
-                            </group>
-                            <group string="Delegated To" >
-                                <field name="child_ids" readonly="1" nolabel="1"/>
-                            </group>
-                        </group>
-                    </sheet>
-                </form>
-            </field>
-        </record>
-
-        <!-- Attendee tree view -->
-        <record id="base_calendar_attendee_tree_view" model="ir.ui.view">
-            <field name="name">calendar.attendee.tree</field>
-            <field name="model">calendar.attendee</field>
-            <field name="arch" type="xml">
-                <tree string="Invitation details">
-                    <field name="sent_by_uid" string="Invitation From"/>
-                    <field name="role" string="My Role"/>
-                    <field name="user_id" invisible="1"/>
-                    <field name="partner_id" invisible="1"/>
-                    <field name="cutype" string="Invitation Type"/>
-                    <field name="state"/>
-                    <field name="rsvp" string="Required to Join"/>
-                </tree>
-            </field>
-        </record>
-
-        <!-- Attendee search view -->
-        <record id="base_calendar_attendee_search_view" model="ir.ui.view">
-            <field name="name">calendar.attendee.search</field>
-            <field name="model">calendar.attendee</field>
-            <field name="arch" type="xml">
-                <search string="Search Invitations">
-                    <field name="email" string="Email"/>
-                    <field name="event_date"/>
-                    <filter icon="terp-gtk-jump-to-ltr" name="toreview" string="To Review" domain="[('state','=', 'needs-action')]" help="Invitations To Review"/>
-                    <filter icon="terp-check" string="Accepted" domain="[('state','=', 'accepted')]" help="Accepted Invitations"/>
-                    <filter icon="terp-dialog-close" string="Declined" domain="[('state','=', 'declined')]" help="Declined Invitations"/>
-                    <filter icon="gtk-sort-descending" string="Delegated" domain="[('state','=', 'delegated')]" help="Delegated Invitations"/>
-                    <field name="user_id" string="Responsible"/>
-                    <field name="cutype" string="Invitation type"/>
-                    <group expand="0" string="Group By...">
-                        <filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
-                        <filter string="Contact" icon="terp-personal" domain="[]" context="{'group_by':'partner_id'}"/>
-                        <filter string="Type" icon="terp-stock_symbol-selection" help="Invitation Type" domain="[]" context="{'group_by':'cutype'}"/>
-                        <filter string="Role" icon="terp-gtk-select-all" domain="[]" context="{'group_by':'role'}"/>
-                        <filter string="Required Reply" icon="terp-mail-replied" domain="[]" context="{'group_by':'rsvp'}"/>
-                        <filter string="Status" icon="terp-stock_effects-object-colorize" help="Invitation Type"
-                            domain="[]" context="{'group_by':'state'}"/>
-                    </group>
-               </search>
-            </field>
-        </record>
-        <record id="action_view_attendee_form" model="ir.actions.act_window">
-             <field name="name">Event Invitations</field>
-             <field name="type">ir.actions.act_window</field>
-             <field name="res_model">calendar.attendee</field>
-             <field name="view_type">form</field>
-             <field name="view_mode">tree,form</field>
-             <field name="view_id" ref="base_calendar.base_calendar_attendee_tree_view"/>
-             <field name="context">{'default_sent_by_uid': uid}</field>
-         </record>
 
         <!-- Calendar's menu -->
         <menuitem id="base.menu_calendar_configuration" name="Calendar"
             parent="base.menu_base_config" sequence="50" groups="base.group_no_one"/>
 
-        <!-- Invitation menu -->
-         <menuitem id="menu_attendee_invitations"
-            parent="base.menu_calendar_configuration"
-            sequence="10" action="action_view_attendee_form"/>
-
         <!-- Alarm form view -->
         <record id="res_alarm_form_view" model="ir.ui.view">
             <field name="name">res.alarm.form</field>
index 4df0a8a..9dd37af 100644 (file)
@@ -10,7 +10,7 @@
         <field name="type">ir.actions.server</field>
         <field name="model_id" ref="model_crm_meeting"/>
         <field name="state">code</field>
-        <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+        <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
     </record>
     <record id="action_crm_meeting_read" model="ir.values">
         <field name="name">action_crm_meeting_read</field>
@@ -28,7 +28,7 @@
         <field name="type">ir.actions.server</field>
         <field name="model_id" ref="model_crm_meeting"/>
         <field name="state">code</field>
-        <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+        <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
     </record>
     <record id="action_crm_meeting_unread" model="ir.values">
         <field name="name">action_crm_meeting_unread</field>
index 81a60a5..14e029e 100644 (file)
@@ -140,18 +140,20 @@ class users(osv.osv):
     # Add handlers for 'input_pw' field.
 
     def set_pw(self, cr, uid, id, name, value, args, context):
-        if not value:
-            raise osv.except_osv(_('Error!'), _("You have to specify a password."))
+        if value:
+            obj = pooler.get_pool(cr.dbname).get('res.users')
+            if not hasattr(obj, "_salt_cache"):
+                obj._salt_cache = {}
 
-        obj = pooler.get_pool(cr.dbname).get('res.users')
-        if not hasattr(obj, "_salt_cache"):
-            obj._salt_cache = {}
+            salt = obj._salt_cache[id] = gen_salt()
+            encrypted = encrypt_md5(value, salt)
 
-        salt = obj._salt_cache[id] = gen_salt()
-        encrypted = encrypt_md5(value, salt)
+        else:
+            #setting a password to '' is allowed. It can be used to inactivate the classic log-in of the user
+            #while the access can still be granted by another login method (openid...)
+            encrypted = ''
         cr.execute('update res_users set password=%s where id=%s',
             (encrypted.encode('utf-8'), int(id)))
-        cr.commit()
         del value
 
     def get_pw( self, cr, uid, ids, name, args, context ):
index 043630a..407d38d 100644 (file)
@@ -38,7 +38,7 @@ openerp.base_import = function (instance) {
     // if true, the 'Import', 'Export', etc... buttons will be shown
     instance.web.ListView.prototype.defaults.import_enabled = true;
     instance.web.ListView.include({
-        on_loaded: function () {
+        load_list: function () {
             var self = this;
             var add_button = false;
             if (!this.$buttons) {
index 617af12..867b220 100644 (file)
@@ -302,50 +302,13 @@ class base_stage(object):
         rule_ids = rule_obj.search(cr, uid, [('model_id','=',model_ids[0])], context=context)
         return rule_obj._action(cr, uid, rule_ids, cases, scrit=scrit, context=context)
 
-    def remind_partner(self, cr, uid, ids, context=None, attach=False):
-        return self.remind_user(cr, uid, ids, context, attach,
-                destination=False)
-
-    def remind_user(self, cr, uid, ids, context=None, attach=False, destination=True):
-        if hasattr(self, 'message_post'):
-            for case in self.browse(cr, uid, ids, context=context):
-                if destination:
-                    recipient_id = case.user_id.partner_id.id
-                else:
-                    if not case.email_from:
-                        return False
-                    recipient_id = self.pool.get('res.partner').find_or_create(cr, uid, case.email_from, context=context)
-                
-                body = case.description or ""
-                for message in case.message_ids:
-                    if message.type == 'email' and message.body:
-                        body = message.body
-                        break
-                body = self.format_body(body)
-                attach_to_send = {}
-                if attach:
-                    attach_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', case.id)])
-                    attach_to_send = self.pool.get('ir.attachment').read(cr, uid, attach_ids, ['datas_fname', 'datas'])
-                    attach_to_send = dict(map(lambda x: (x['datas_fname'], x['datas'].decode('base64')), attach_to_send))
-                subject = "Reminder: [%s] %s" % (case.id, case.name)
-                self.message_post(cr, uid, case.id, body=body,
-                    subject=subject, attachments=attach_to_send, 
-                    partner_ids=[recipient_id], context=context)
-        return True
-
+    
     def _check(self, cr, uid, ids=False, context=None):
         """ Function called by the scheduler to process cases for date actions.
             Must be overriden by inheriting classes.
         """
         return True
 
-    def format_body(self, body):
-        return self.pool.get('base.action.rule').format_body(body)
-
-    def format_mail(self, obj, body):
-        return self.pool.get('base.action.rule').format_mail(obj, body)
-
     # ******************************
     # Notifications
     # ******************************
index dd36aa1..9a90a80 100644 (file)
@@ -85,7 +85,6 @@ Dashboard for CRM will include:
         'crm_lead_view.xml',
         'crm_lead_menu.xml',
 
-        'crm_meeting_view.xml',
         'crm_meeting_menu.xml',
         'crm_meeting_shortcut_data.xml',
 
@@ -107,6 +106,7 @@ Dashboard for CRM will include:
         'crm_demo.xml',
         'crm_lead_demo.xml',
         'crm_phonecall_demo.xml',
+        'crm_action_rule_demo.xml',
     ],
     'test': [
         'test/process/communication_with_customer.yml',
index 8b1ba65..910a1fc 100644 (file)
@@ -41,24 +41,15 @@ class base_action_rule(osv.osv):
         'regex_history' : fields.char('Regular Expression on Case History', size=128),
         'act_section_id': fields.many2one('crm.case.section', 'Set Team to'),
         'act_categ_id': fields.many2one('crm.case.categ', 'Set Category to'),
-        'act_mail_to_partner': fields.boolean('Mail to Partner',
-                                              help="Check this if you want the rule to send an email to the partner."),
     }
 
-    def email_send(self, cr, uid, obj, emails, body, emailfrom=tools.config.get('email_from', False), context=None):
-        mail_id = super(base_action_rule, self).email_send(cr, uid, obj, emails, body, emailfrom=emailfrom, context=context)
-        if mail_id and hasattr(obj, 'section_id') and obj.section_id and obj.section_id.alias_id:
-            reply_to = obj.section_id.alias_id.name_get()[0][1]
-            self.pool.get('mail.mail').write(cr, uid, [mail_id], {'reply_to': reply_to}, context=context)
-        return mail_id
-
     def do_check(self, cr, uid, action, obj, context=None):
         ok = super(base_action_rule, self).do_check(cr, uid, action, obj, context=context)
 
         if hasattr(obj, 'section_id'):
             ok = ok and (not action.trg_section_id or action.trg_section_id.id == obj.section_id.id)
-        if hasattr(obj, 'categ_id'):
-            ok = ok and (not action.trg_categ_id or action.trg_categ_id.id == obj.categ_id.id)
+        if hasattr(obj, 'categ_ids'):
+            ok = ok and (not action.trg_categ_id or action.trg_categ_id.id in [x.id for x in obj.categ_ids])
 
         #Cheking for history
         regex = action.regex_history
@@ -80,36 +71,18 @@ class base_action_rule(osv.osv):
             ok = ok and res_count
         return ok
 
-    def do_action(self, cr, uid, action, model_obj, obj, context=None):
+    def do_action(self, cr, uid, action, obj, context=None):
+        res = super(base_action_rule, self).do_action(cr, uid, action, obj, context=context)
+        model_obj = self.pool.get(action.model_id.model)
         write = {}
         if hasattr(action, 'act_section_id') and action.act_section_id:
-            obj.section_id = action.act_section_id
             write['section_id'] = action.act_section_id.id
 
-        if hasattr(obj, 'email_cc') and action.act_email_cc:
-            if '@' in (obj.email_cc or ''):
-                emails = obj.email_cc.split(",")
-                if  obj.act_email_cc not in emails:# and '<'+str(action.act_email_cc)+">" not in emails:
-                    write['email_cc'] = obj.email_cc + ',' + obj.act_email_cc
-            else:
-                write['email_cc'] = obj.act_email_cc
-
-        # Put state change by rule in communication history
-        if hasattr(obj, 'state') and hasattr(obj, 'message_post') and action.act_state:
-            model_obj.message_post(cr, uid, [obj], _(action.act_state), context=context)
+        if hasattr(action, 'act_categ_id') and action.act_categ_id:
+            write['categ_ids'] = [4, action.act_categ_id.id]                        
 
         model_obj.write(cr, uid, [obj.id], write, context)
-        super(base_action_rule, self).do_action(cr, uid, action, model_obj, obj, context=context)
-        emails = []
-
-        if hasattr(obj, 'email_from') and action.act_mail_to_partner:
-            emails.append(obj.email_from)
-        emails = filter(None, emails)
-        if len(emails) and action.act_mail_body:
-            emails = list(set(emails))
-            self.email_send(cr, uid, obj, emails, action.act_mail_body)
-        return True
-
+        return res
 
     def state_get(self, cr, uid, context=None):
         """Gets available states for crm"""
diff --git a/addons/crm/crm_action_rule_demo.xml b/addons/crm/crm_action_rule_demo.xml
new file mode 100644 (file)
index 0000000..85cb8de
--- /dev/null
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<openerp>
+    <data noupdate="1">
+        <!-- email server actions -->
+        <record id="action_email_reminder_lead" model="ir.actions.server">
+            <field name="name">Reminder to User</field>
+            <field name="model_id" ref="model_crm_lead"/>
+            <field name="condition">True</field>
+            <field name="type">ir.actions.server</field>
+            <field name="state">email</field>
+            <field name="email">object.user_id.email</field>
+            <field name="subject">Reminder on Lead: [[object.id ]] [[object.partner_id and 'of ' +object.partner_id.name or '']]</field>
+            <field name="message">Hello [[object.user_id.name]], 
+can you check following lead, it's not open since 5 days ?
+
+Lead: [[object.id ]]
+Description:
+
+    [[object.description]]
+
+Thanks,
+            </field>
+        </record>
+
+        <record id="action_email_reminder_customer_lead" model="ir.actions.server">
+            <field name="name">Reminder to Customer</field>
+            <field name="model_id" ref="model_crm_lead"/>
+            <field name="condition">True</field>
+            <field name="type">ir.actions.server</field>
+            <field name="state">email</field>
+            <field name="email">object.email_from</field>
+            <field name="subject">Reminder on Lead: [[object.id ]]</field>
+            <field name="message">Hello [[object.partner_id and object.partner_id.name or '']], 
+your following lead is not open since 5 days.
+
+Lead: [[object.id ]]
+Description:
+
+    [[object.description]]
+
+Thanks,
+            </field>
+        </record>
+
+        <record id="filter_draft_lead" model="ir.filters">
+            <field name="name">Filter on leads which are draft.</field>
+            <field name="model_id">crm.lead</field>
+            <field name="domain">[('state','=','draft')]</field>
+        </record>
+
+        <!-- automated actions -->
+        <record id="rule_set_reminder_lead" model="base.action.rule">
+            <field name="name">Set Auto Reminder on leads which are not open since 5 days.</field>
+            <field name="model_id" ref="model_crm_lead"/>
+            <field name="sequence">1</field>
+            <field name="filter_id" ref="filter_draft_lead"/>
+            <field name="trg_date_type">create</field>
+            <field name="trg_date_range">5</field>
+            <field name="trg_date_range_type">day</field>
+            <field name="server_action_ids" eval="[(6,0,[ref('action_email_reminder_customer_lead'), ref('action_email_reminder_lead')])]"/>
+        </record>
+
+        <record id="filter_usa_lead" model="ir.filters">
+            <field name="name">Filter on leads which come from USA.</field>
+            <field name="model_id">crm.lead</field>
+            <field name="domain">[('country_id','=','United States')]</field>
+        </record>
+
+        <record id="rule_set_followers_lead" model="base.action.rule">
+            <field name="name">Set Auto Followers on leads which are urgent and come from USA.</field>
+            <field name="model_id" ref="model_crm_lead"/>
+            <field name="sequence">2</field>
+            <field name="regex_name">urgent.*</field>
+            <field name="filter_id" ref="filter_usa_lead"/>
+            <field name="act_followers" eval="[(6,0,[ref('base.res_partner_4'), ref('base.res_partner_5'), ref('base.res_partner_6')])]"/>
+            <field name="act_user_id" ref="base.user_root"/>
+            <field name="act_section_id" ref="section_sales_department"/>
+            <field name="trg_date_type">create</field>
+            <field name="trg_date_range">0</field>
+            <field name="trg_date_range_type">minutes</field>
+        </record>
+    </data>
+</openerp>
index f2a5f57..e21b74d 100644 (file)
@@ -7,53 +7,21 @@
             <field name="model">base.action.rule</field>
             <field name="inherit_id" ref="base_action_rule.view_base_action_rule_form"/>
             <field name="arch" type="xml">
-                <group name="partner" position="after">
-                    <group col="2" colspan="2">
-                        <separator colspan="4" string="Condition on Communication History"/>
+                <xpath expr="//group[@name='partner']" position="after">
+                    <group name="case" string="Conditions on Case Fields">
+                        <field name="trg_section_id" widget="selection"/>
+                        <field name="trg_categ_id"/>
+                    </group>
+                    <group name="communication" string="Conditions on Communication History">
                         <field name="regex_history"/>
                         <field name="trg_max_history"/>
                     </group>
-                </group>
-            </field>
-       </record>
-
-       <record id="view_base_action_rule_line_form2" model="ir.ui.view">
-            <field name="name">base.action.rule.form2.inherit</field>
-            <field name="model">base.action.rule</field>
-            <field name="inherit_id" ref="base_action_rule.view_base_action_rule_form"/>
-            <field name="arch" type="xml">
-                <group name="partner" position="after">
-                    <group col="2" colspan="2">
-                        <separator colspan="4" string="Condition Case Fields"/>
-                        <field name="trg_section_id"  widget="selection"/>
-                        <field name="trg_categ_id"/>
-                    </group>
-                </group>
-            </field>
-       </record>
-
-       <record id="view_base_action_rule_line_form3" model="ir.ui.view">
-            <field name="name">base.action.rule.form3.inherit</field>
-            <field name="model">base.action.rule</field>
-            <field name="inherit_id" ref="base_action_rule.view_base_action_rule_form"/>
-            <field name="arch" type="xml">
-                <field name="act_user_id" position="after">
+                </xpath>
+                <xpath expr="//field[@name='act_user_id']" position="after">
                     <field name="act_section_id"/>
                     <field name="act_categ_id"/>
-                </field>
-            </field>
-       </record>
-       
-       <record id="view_base_action_rule_line_form4" model="ir.ui.view">
-            <field name="name">base.action.rule.form4.inherit</field>
-            <field name="model">base.action.rule</field>
-            <field name="inherit_id" ref="base_action_rule.view_base_action_rule_form"/>
-            <field name="arch" type="xml">
-                <field name="act_mail_to_user" position="after">
-                    <field name="act_mail_to_partner"/>
-                </field>
+                </xpath>
             </field>
        </record>
-
     </data>
 </openerp>
index cee80eb..a0dce6a 100644 (file)
@@ -9,7 +9,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_crm_lead"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_crm_lead_unread" model="ir.values">
             <field name="name">action_crm_lead_unread</field>
@@ -27,7 +27,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_crm_lead"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_crm_lead_read" model="ir.values">
             <field name="name">action_crm_lead_read</field>
diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml
deleted file mode 100644 (file)
index 068f7cf..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0"?>
-<openerp>
-    <data>
-
-        <!-- Calendar Attendee Form View -->
-        <record id="attendee_form_view_inherit" model="ir.ui.view">
-            <field name="name">calendar.attendee.form.inherit</field>
-            <field name="model">calendar.attendee</field>
-            <field name="inherit_id" ref="base_calendar.base_calendar_attendee_form_view"/>
-            <field name="arch" type="xml">
-                <field name="ref" position="after">
-                    <field name="categ_id" string="Event Type"/>
-                </field>
-            </field>
-        </record>
-
-    </data>
-</openerp>
index c359aa4..30303d4 100644 (file)
             OpenERP allows you to easily define all the calls to be done
             by your sales team and follow up based on their summary.
           </p><p>  
-            You can use the import feature to massicely import a new list of
+            You can use the import feature to massively import a new list of
             prospects to qualify.
           </p>
         </field>
index c610913..b6e2f09 100644 (file)
@@ -9,7 +9,7 @@
         <field name="type">ir.actions.server</field>
         <field name="model_id" ref="model_crm_phonecall"/>
         <field name="state">code</field>
-        <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+        <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
     </record>
     <record id="action_crm_phonecall_unread" model="ir.values">
         <field name="name">action_crm_phonecall_unread</field>
@@ -27,7 +27,7 @@
         <field name="type">ir.actions.server</field>
         <field name="model_id" ref="model_crm_phonecall"/>
         <field name="state">code</field>
-        <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+        <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
     </record>
     <record id="action_crm_phonecall_read" model="ir.values">
         <field name="name">action_crm_phonecall_read</field>
                 <field name="date"/>
                 <field name="name"/>
                 <field name="partner_id"/>
-                <field name="partner_phone"/>
-                <field name="user_id"/>
-                <field name="categ_id" invisible="1"/>
-                <field name="create_date" invisible="1"/>
-                <field name="opportunity_id" invisible="1"/>
+                <button string="Meeting"
+                    states="open,pending" icon="gtk-redo"
+                     name="action_make_meeting" type="object"/>
                 <button string="Convert to Opportunity"
                     name="%(phonecall2opportunity_act)d"
                     states="open,pending"
                     icon="gtk-index"
                     type="action" attrs="{'invisible':[('opportunity_id','!=',False)]}"/>
-                <button string="Meeting"
-                    states="open,pending" icon="gtk-redo"
-                     name="action_make_meeting" type="object"/>
+                <field name="partner_phone"/>
+                <field name="user_id"/>
+                <field name="categ_id" invisible="1"/>
+                <field name="create_date" invisible="1"/>
+                <field name="opportunity_id" invisible="1"/>
                 <field name="state"/>
                 <button name="case_open" string="Confirm" type="object"
                         states="draft,pending" icon="gtk-go-forward"/>
index d68591a..2cdfb03 100644 (file)
@@ -87,7 +87,7 @@ class crm_phonecall2phonecall(osv.osv_memory):
             if 'user_id' in fields:
                 res.update({'user_id': phonecall.user_id and phonecall.user_id.id or False})
             if 'date' in fields:
-                res.update({'date': phonecall.date})
+                res.update({'date': False})
             if 'section_id' in fields:
                 res.update({'section_id': phonecall.section_id and phonecall.section_id.id or False})
             if 'categ_id' in fields:
index c88b2fe..60cde56 100644 (file)
@@ -124,7 +124,8 @@ class crm_claim(base_stage, osv.osv):
         'date': fields.datetime.now,
         'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
         'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
-        'active': lambda *a: 1
+        'active': lambda *a: 1,
+        'stage_id':lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c)
     }
 
     def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
index 9643a56..0d9b5ad 100644 (file)
             <field name="arch" type="xml">
                 <form string="Claim" version="7.0">
                 <header>
-                    <span groups="base.group_user">
-                        <button name="case_open" string="Open" type="object" class="oe_highlight"
-                                states="draft,pending" />
-                        <button name="case_close" string="Done" type="object" class="oe_highlight"
-                                states="open,pending"/>
-                        <button name="case_refuse" string="Refuse" type="object" class="oe_highlight"
-                                states="draft,open,pending"/>
-                        <button name="stage_previous" string="Previous Stage" type="object"
-                                states="open,pending" icon="gtk-go-back" attrs="{'invisible': [('stage_id','=', False)]}"/>
-                        <button name="stage_next" string="Next Stage" type="object"
-                                states="open,pending" icon="gtk-go-forward" attrs="{'invisible': [('stage_id','=', False)]}"/>
-                        <button name="case_reset" string="Reset to Draft" type="object" 
-                                states="cancel,done"/>
-                        <button name="case_cancel" string="Cancel" type="object" 
-                                states="draft,open,pending"/>
-                    </span>
+                    <button name="case_open" string="Open" type="object" class="oe_highlight"
+                            states="draft,pending" groups="base.group_user"/>
+                    <button name="case_close" string="Done" type="object" class="oe_highlight"
+                            states="open,pending" groups="base.group_user"/>
+                    <button name="case_refuse" string="Refuse" type="object" class="oe_highlight"
+                            states="draft,open,pending" groups="base.group_user"/>
+                    <button name="stage_previous" string="Previous Stage" type="object" groups="base.group_user" 
+                            states="open,pending" icon="gtk-go-back" attrs="{'invisible': [('stage_id','=', False)]}"/>
+                    <button name="stage_next" string="Next Stage" type="object" groups="base.group_user"
+                            states="open,pending" icon="gtk-go-forward" attrs="{'invisible': [('stage_id','=', False)]}"/>
+                    <button name="case_reset" string="Reset to Draft" type="object" groups="base.group_user"
+                            states="cancel,done"/>
+                    <button name="case_cancel" string="Cancel" type="object"  groups="base.group_user"
+                            states="draft,open,pending"/>
                     <field name="stage_id" widget="statusbar"
                             on_change="onchange_stage_id(stage_id)"/>
                 </header>
index 8843596..cea6d33 100644 (file)
@@ -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:36+0000\n"
-"PO-Revision-Date: 2011-03-16 00:04+0000\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"PO-Revision-Date: 2012-10-24 04:51+0000\n"
+"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
 "Language-Team: Russian <ru@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-10-19 05:33+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-10-24 04:55+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
 
 #. module: crm_claim
 #: field:crm.claim.report,nbr:0
@@ -85,12 +85,12 @@ msgstr ""
 #: code:addons/crm_claim/crm_claim.py:132
 #, python-format
 msgid "The claim '%s' has been opened."
-msgstr ""
+msgstr "Претензия  '%s' была открыта"
 
 #. module: crm_claim
 #: view:crm.claim:0
 msgid "Date Closed"
-msgstr ""
+msgstr "Дата закрытия"
 
 #. module: crm_claim
 #: view:crm.claim.report:0
@@ -151,12 +151,12 @@ msgstr "Ссылка"
 #. module: crm_claim
 #: view:crm.claim.report:0
 msgid "Date of claim"
-msgstr ""
+msgstr "Дата претензии"
 
 #. module: crm_claim
 #: view:crm.claim:0
 msgid "All pending Claims"
-msgstr ""
+msgstr "Все ожидающие претензии"
 
 #. module: crm_claim
 #: view:crm.claim.report:0
@@ -187,7 +187,7 @@ msgstr "Контрагент"
 #. module: crm_claim
 #: view:crm.claim.report:0
 msgid "Month of claim"
-msgstr ""
+msgstr "Месяц претензии"
 
 #. module: crm_claim
 #: selection:crm.claim,type_action:0
@@ -227,7 +227,7 @@ msgstr "Отправить новое эл. письмо"
 #: selection:crm.claim,state:0
 #: view:crm.claim.report:0
 msgid "New"
-msgstr ""
+msgstr "Новый"
 
 #. module: crm_claim
 #: view:crm.claim:0
@@ -254,7 +254,7 @@ msgstr "Следующее действие"
 #. module: crm_claim
 #: view:crm.claim.report:0
 msgid "My Sales Team(s)"
-msgstr ""
+msgstr "Мои отделы продаж"
 
 #. module: crm_claim
 #: model:crm.case.stage,name:crm_claim.stage_claim3
@@ -321,7 +321,7 @@ msgstr "Контакт"
 #. module: crm_claim
 #: view:crm.claim.report:0
 msgid "Month-1"
-msgstr ""
+msgstr "Месяц-1"
 
 #. module: crm_claim
 #: model:ir.actions.act_window,name:crm_claim.action_report_crm_claim
@@ -380,7 +380,7 @@ msgstr "Дата изменения"
 #. module: crm_claim
 #: view:crm.claim.report:0
 msgid "Year of claim"
-msgstr ""
+msgstr "Год претензи"
 
 #. module: crm_claim
 #: view:crm.claim.report:0
@@ -402,7 +402,7 @@ msgstr "Значение претензии"
 #. module: crm_claim
 #: view:crm.claim:0
 msgid "Responsible User"
-msgstr ""
+msgstr "Ответственный пользователь"
 
 #. module: crm_claim
 #: help:crm.claim,email_cc:0
index ccac740..2b27589 100644 (file)
@@ -64,7 +64,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_event_event"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_event_event_unread" model="ir.values">
             <field name="name">action_event_event_unread</field>
@@ -82,7 +82,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_event_event"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_event_event_read" model="ir.values">
             <field name="name">action_event_event_read</field>
             <field name="arch" type="xml">
                 <form string="Events" version="7.0">
                     <header>
-                        <span groups="base.group_user">
-                            <button string="Confirm Event" name="button_confirm" states="draft" type="object" class="oe_highlight"/>
-                            <button string="Event Ended" name="button_done" states="confirm" type="object" class="oe_highlight"/>
-                            <button string="Set To Draft" name="button_draft" states="cancel,done" type="object" />
-                            <button string="Cancel Event" name="button_cancel" states="draft,confirm" type="object"/>
-                        </span>
+                        <button string="Confirm Event" name="button_confirm" states="draft" type="object" class="oe_highlight" groups="base.group_user"/>
+                        <button string="Event Ended" name="button_done" states="confirm" type="object" class="oe_highlight" groups="base.group_user"/>
+                        <button string="Set To Draft" name="button_draft" states="cancel,done" type="object" groups="base.group_user"/>
+                        <button string="Cancel Event" name="button_cancel" states="draft,confirm" type="object" groups="base.group_user"/>
                         <field name="state" widget="statusbar" statusbar_visible="draft,confirm,done"/>
                     </header>
                     <sheet>
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_event_registration"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_event_registration_unread" model="ir.values">
             <field name="name">action_event_registration_unread</field>
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_event_registration"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_event_registration_read" model="ir.values">
             <field name="name">action_event_registration_read</field>
index f37dea3..2dd40a7 100644 (file)
@@ -40,7 +40,7 @@ class sale_order_line(osv.osv):
         'event_id': fields.many2one('event.event', 'Event', help="Choose an event and it will automatically create a registration for this event."),
         #those 2 fields are used for dynamic domains and filled by onchange
         'event_type_id': fields.related('event_type_id', type='many2one', relation="event.type", string="Event Type"),
-        'event_ok': fields.related('event_ok', string='event_ok', type='boolean'),
+        'event_ok': fields.related('product_id', 'event_ok', string='event_ok', type='boolean'),
     }
 
     def product_id_change(self, cr, uid, ids,
index eafe5d0..d2214f5 100644 (file)
@@ -231,7 +231,7 @@ class hr_employee(osv.osv):
     def onchange_address_id(self, cr, uid, ids, address, context=None):
         if address:
             address = self.pool.get('res.partner').browse(cr, uid, address, context=context)
-            return {'value': {'work_email': address.email, 'work_phone': address.phone, 'mobile_phone': address.mobile}}
+            return {'value': {'work_phone': address.phone, 'mobile_phone': address.mobile}}
         return {'value': {}}
 
     def onchange_company(self, cr, uid, ids, company, context=None):
index 84a46bb..831a1fe 100644 (file)
@@ -7,14 +7,14 @@ msgstr ""
 "Project-Id-Version: OpenERP Server 6.0dev\n"
 "Report-Msgid-Bugs-To: support@openerp.com\n"
 "POT-Creation-Date: 2012-02-08 01:37+0100\n"
-"PO-Revision-Date: 2012-05-10 18:17+0000\n"
-"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
+"PO-Revision-Date: 2012-10-22 07:48+0000\n"
+"Last-Translator: nanothole <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-10-19 05:20+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-10-23 04:48+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
 
 #. module: hr
 #: model:process.node,name:hr.process_node_openerpuser0
@@ -56,7 +56,7 @@ msgstr ""
 #. module: hr
 #: model:ir.actions.act_window,name:hr.view_department_form_installer
 msgid "Create Your Departments"
-msgstr ""
+msgstr "Sukurkite padalinius"
 
 #. module: hr
 #: model:ir.actions.act_window,help:hr.action_hr_job
@@ -77,12 +77,12 @@ msgstr "Padalinys"
 #. module: hr
 #: view:hr.job:0
 msgid "Mark as Old"
-msgstr ""
+msgstr "Pažymeti kaip sena"
 
 #. module: hr
 #: view:hr.job:0
 msgid "Jobs"
-msgstr ""
+msgstr "Darbai"
 
 #. module: hr
 #: view:hr.job:0
@@ -103,7 +103,7 @@ msgstr ""
 #. module: hr
 #: model:ir.actions.todo.category,name:hr.category_hr_management_config
 msgid "HR Management"
-msgstr ""
+msgstr "Žmogiškųjų išteklių valdymas"
 
 #. module: hr
 #: help:hr.employee,partner_id:0
@@ -130,7 +130,7 @@ msgstr "Pastabos"
 #. module: hr
 #: selection:hr.employee,marital:0
 msgid "Married"
-msgstr ""
+msgstr "Vedęs"
 
 #. module: hr
 #: model:ir.actions.act_window,help:hr.action_create_hr_employee_installer
@@ -152,7 +152,7 @@ msgstr ""
 #. module: hr
 #: field:hr.employee,color:0
 msgid "Color Index"
-msgstr ""
+msgstr "Spalvos indeksas"
 
 #. module: hr
 #: model:process.transition,note:hr.process_transition_employeeuser0
@@ -169,7 +169,7 @@ msgstr ""
 #. module: hr
 #: field:hr.employee,identification_id:0
 msgid "Identification No"
-msgstr ""
+msgstr "Asmens kodas"
 
 #. module: hr
 #: selection:hr.employee,gender:0
@@ -185,12 +185,12 @@ msgstr ""
 #. module: hr
 #: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_new_config
 msgid "Attendance"
-msgstr ""
+msgstr "Lankomumas"
 
 #. module: hr
 #: view:hr.employee:0
 msgid "Social IDs"
-msgstr ""
+msgstr "SODRA Nr."
 
 #. module: hr
 #: field:hr.employee,work_phone:0
@@ -206,7 +206,7 @@ msgstr "Žemesniosios kategorijos"
 #: view:hr.job:0 field:hr.job,description:0
 #: model:ir.model,name:hr.model_hr_job
 msgid "Job Description"
-msgstr ""
+msgstr "Darbo aprašymas"
 
 #. module: hr
 #: field:hr.employee,work_location:0
@@ -227,7 +227,7 @@ msgstr "Darbuotojas"
 #. module: hr
 #: model:process.node,note:hr.process_node_employeecontact0
 msgid "Other information"
-msgstr ""
+msgstr "Kita informacija"
 
 #. module: hr
 #: field:hr.employee,work_email:0
@@ -237,7 +237,7 @@ msgstr "Darbo el. paštas"
 #. module: hr
 #: field:hr.employee,birthday:0
 msgid "Date of Birth"
-msgstr ""
+msgstr "Gimimo data"
 
 #. module: hr
 #: model:ir.ui.menu,name:hr.menu_hr_reporting
@@ -253,7 +253,7 @@ msgstr ""
 #. module: hr
 #: view:hr.employee:0 field:hr.employee,job_id:0 view:hr.job:0
 msgid "Job"
-msgstr ""
+msgstr "Darbas"
 
 #. module: hr
 #: field:hr.department,member_ids:0
@@ -268,7 +268,7 @@ msgstr "Nustatymai"
 #. module: hr
 #: view:hr.employee:0 field:hr.employee,category_ids:0
 msgid "Categories"
-msgstr ""
+msgstr "Kategorijos"
 
 #. module: hr
 #: field:hr.job,expected_employees:0
@@ -799,3 +799,6 @@ msgstr ""
 #~ msgstr ""
 #~ "Objekto pavadinimas turi prasidėti su x_ ir jame negali būti specialiųjų "
 #~ "ženklų!"
+
+#~ msgid "Work E-mail"
+#~ msgstr "Darbinis el. paštas"
index 17cf548..fe6d09a 100644 (file)
@@ -86,6 +86,8 @@ class report_custom(report_rml):
                     for att in attendences:
                         dt = datetime.strptime(att['name'], '%Y-%m-%d %H:%M:%S')
                         if ldt and att['action'] == 'sign_out':
+                            if dt.date() > ldt.date():
+                                dt = ldt
                             wh += (float((dt - ldt).seconds)/60/60)
                         else:
                             ldt = dt
index 900f982..326ffce 100644 (file)
@@ -38,7 +38,7 @@ class report_custom(report_rml):
 
     def create_xml(self, cr, uid, ids, datas, context=None):
         obj_emp = pooler.get_pool(cr.dbname).get('hr.employee')
-
+        ids = datas['active_ids']
         start_date = datetime.strptime(datas['form']['init_date'], '%Y-%m-%d')
         end_date = datetime.strptime(datas['form']['end_date'], '%Y-%m-%d')
         first_monday = start_date - relativedelta(days=start_date.date().weekday())
index 9ee69a9..454ba77 100644 (file)
@@ -37,6 +37,7 @@ class hr_attendance_byweek(osv.osv_memory):
     def print_report(self, cr, uid, ids, context=None):
         datas = {
              'ids': [],
+             'active_ids': context['active_ids'],
              'model': 'hr.employee',
              'form': self.read(cr, uid, ids)[0]
         }
index fb9d287..7164e7d 100644 (file)
                 <form string="Interview Appraisal" version="7.0">
                     <header>
                         <button string="Cancel" name="survey_req_cancel" type="object"
-                            states="draft,waiting_answer"/>
+                            states="draft,waiting_answer" class="oe_left"/>
                         <button string="Print Survey" name="action_print_survey"  type="object"
                             states="draft" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0}"
                             attrs="{'readonly':[('survey_id','=',False)]}" class="oe_highlight"/>
index 03a461a..b897673 100644 (file)
@@ -10,7 +10,7 @@
         <record id="product_expense_installer_tree_view" model="ir.ui.view">
             <field name="name">product.product.tree</field>
             <field name="model">product.product</field>
-            <field eval="7" name="priority"/>
+            <field eval="37" name="priority"/>
             <field name="arch" type="xml">
                 <tree editable="bottom" string="Products">
                     <field name="name"/>
index 6e3c9b2..1808e21 100644 (file)
@@ -8,7 +8,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_hr_holidays"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_holidays_unread" model="ir.values">
             <field name="name">action_holidays_unread</field>
@@ -26,7 +26,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_hr_holidays"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_holidays_read" model="ir.values">
             <field name="name">action_holidays_read</field>
index 461ccdf..79e0993 100644 (file)
@@ -6,12 +6,12 @@
         <field name="name">applicants.status.tree</field>
         <field name="model">hr.applicant</field>
         <field name="arch" type="xml">
-            <tree colors="blue:state == 'draft';black:state in ('open','pending','done','cancel');" string="Applicants Status">
+            <tree  string="Applicants Status">
                 <field name="create_date"/>
                 <field name="job_id"/>
                 <field name="partner_name"/>
                 <field name="stage_id"/>
-                <field name="state" groups="base.group_no_one"/>
+                <field name="user_id"/>
             </tree>
         </field>
     </record>
@@ -32,7 +32,7 @@
         <field name="inherit_id" ref="hr.board_hr_form"/>
         <field name="arch" type="xml">
             <xpath expr="/form/board/column[1]" position="inside">
-                <action name="%(action_applicants_status)d" string="Applicants To be Processed"/>
+                <action name="%(action_applicants_status)d" string="Applications to be Processed"/>
             </xpath>
         </field>
     </record>
index 288231a..330c866 100644 (file)
@@ -313,7 +313,7 @@ You can automatically receive job application though an email gateway, see the H
         <field eval="0" name="rating_allow_one_column_require"/>
         <field name="req_error_msg">This question requires an answer.</field>
         <field eval="3" name="sequence"/>
-        <field name="question">Exprience</field>
+        <field name="question">Experience</field>
         <field eval="0" name="is_require_answer"/>
         <field name="type">comment</field>
         <field name="comment_valid_err_msg">The comment you entered is in an invalid format.</field>
index 3f00c7e..2554c69 100644 (file)
@@ -17,7 +17,6 @@
     priority: '3'
     user_id: base.user_demo
     partner_name: 'Marie Justine'
-    state: 'open'
     partner_mobile: '9988774455'
     job_id: hr.job_developer
     stage_id: stage_job4
@@ -41,7 +40,6 @@
     type_id: degree_bac5
     user_id: base.user_root
     partner_name: 'Sandra Elvis'
-    state: 'cancel'
     stage_id: stage_job6
     name: 'More than 5 yrs Experience in PHP'
 -
@@ -50,7 +48,6 @@
     type_id: degree_licenced
     user_id: base.user_demo
     partner_name: 'John Bruno'
-    state: 'done'
     job_id: hr.job_developer
     color: 5
     stage_id: stage_job5
@@ -61,8 +58,6 @@
     type_id: degree_licenced
     priority: '4'
     partner_name: 'David Armstrong'
-    state: 'pending'
-    state: open
     partner_mobile: '9966332214'
     job_id: hr.job_developer
     stage_id: stage_job2
@@ -73,7 +68,6 @@
     date: !eval time.strftime('%Y-%m-12 17:49:19')
     type_id: degree_bac5
     partner_name: 'Tina Augustie'
-    state: 'open'
     partner_mobile: '9898745745'
     job_id: hr.job_developer
     stage_id: stage_job4
@@ -85,7 +79,6 @@
     date: !eval time.strftime('%Y-%m-12 17:49:19')
     type_id: degree_bac5
     partner_name: 'Shane Williams'
-    state: 'open'
     partner_mobile: '9812398524'
     stage_id: stage_job4
     name: 'Programmer'
index d6d04c1..12c552e 100644 (file)
@@ -42,7 +42,7 @@
         <field name="type">ir.actions.server</field>
         <field name="model_id" ref="model_hr_applicant"/>
         <field name="state">code</field>
-        <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+        <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
     </record>
     <record id="action_applicant_unread" model="ir.values">
         <field name="name">action_project_unread</field>
@@ -60,7 +60,7 @@
         <field name="type">ir.actions.server</field>
         <field name="model_id" ref="model_hr_applicant"/>
         <field name="state">code</field>
-        <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+        <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
     </record>
     <record id="action_applicant_read" model="ir.values">
         <field name="name">action_project_read</field>
diff --git a/addons/hr_timesheet/i18n/mk.po b/addons/hr_timesheet/i18n/mk.po
new file mode 100644 (file)
index 0000000..2192460
--- /dev/null
@@ -0,0 +1,642 @@
+# Macedonian 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-10-20 13:07+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: Macedonian <mk@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-10-21 04:41+0000\n"
+"X-Generator: Launchpad (build 16165)\n"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Wed"
+msgstr "Сре"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "(Keep empty for current_time)"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:132
+#, python-format
+msgid "No employee defined for your user !"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Group By..."
+msgstr "Групирај По..."
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,help:hr_timesheet.action_hr_timesheet_sign_in
+msgid ""
+"Employees can encode their time spent on the different projects. A project "
+"is an analytic account and the time spent on a project generate costs on the "
+"analytic account. This feature allows to record at the same time the "
+"attendance and the timesheet."
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Today"
+msgstr "Денес"
+
+#. module: hr_timesheet
+#: field:hr.employee,journal_id:0
+msgid "Analytic Journal"
+msgstr "Аналитичка картица"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "Stop Working"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_employee
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_timesheet_employee
+msgid "Employee Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Work done stats"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_reporting_timesheet
+msgid "Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Mon"
+msgstr "Пон"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "Sign in"
+msgstr "Најава"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Fri"
+msgstr "Пет"
+
+#. module: hr_timesheet
+#: field:hr.employee,uom_id:0
+msgid "UoM"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid ""
+"Employees can encode their time spent on the different projects they are "
+"assigned on. A  project is an analytic account and the time spent on a "
+"project generates costs on the analytic account. This feature allows to "
+"record at the same time the attendance and the timesheet."
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,analytic_amount:0
+msgid "Minimum Analytic Amount"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+msgid "Monthly Employee Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "Work done in the last period"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,state:0
+#: field:hr.sign.out.project,state:0
+msgid "Current state"
+msgstr "Тековен статус"
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,name:0
+#: field:hr.sign.out.project,name:0
+msgid "Employees name"
+msgstr "Име на Вработениот"
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,account_id:0
+msgid "Project / Analytic Account"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_analytical_timesheet_users
+msgid "Print Employees Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/hr_timesheet.py:175
+#: code:addons/hr_timesheet/hr_timesheet.py:177
+#, python-format
+msgid "Warning !"
+msgstr "Внимание !"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:77
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:132
+#, python-format
+msgid "UserError"
+msgstr "Корисничка Грешка"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:77
+#, python-format
+msgid "No cost unit defined for this employee !"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Tue"
+msgstr "Вто"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_print_employee.py:42
+#, python-format
+msgid "Warning"
+msgstr "Предупредување"
+
+#. module: hr_timesheet
+#: field:hr.analytic.timesheet,partner_id:0
+msgid "Partner"
+msgstr "Партнер"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+#: view:hr.sign.out.project:0
+msgid "Sign In/Out by Project"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Sat"
+msgstr "Саб"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Sun"
+msgstr "Нед"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Analytic account"
+msgstr "Аналитичко конто"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+#: view:hr.analytical.timesheet.users:0
+msgid "Print"
+msgstr "Печати"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+#: model:ir.actions.act_window,name:hr_timesheet.act_hr_timesheet_line_evry1_all_form
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_working_hours
+msgid "Timesheet Lines"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.users:0
+msgid "Monthly Employees Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "July"
+msgstr "Јули"
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,date:0
+#: field:hr.sign.out.project,date_start:0
+msgid "Starting Date"
+msgstr "Почетен датум"
+
+#. module: hr_timesheet
+#: view:hr.employee:0
+msgid "Categories"
+msgstr "Категории"
+
+#. module: hr_timesheet
+#: constraint:hr.analytic.timesheet:0
+msgid "You cannot modify an entry in a Confirmed/Done timesheet !."
+msgstr ""
+
+#. module: hr_timesheet
+#: help:hr.employee,product_id:0
+msgid "Specifies employee's designation as a product with type 'service'."
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Total cost"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "September"
+msgstr "Септември"
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_analytic_timesheet
+msgid "Timesheet Line"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.analytical.timesheet.users,employee_ids:0
+msgid "employees"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Stats by month"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+#: field:hr.analytical.timesheet.employee,month:0
+#: field:hr.analytical.timesheet.users,month:0
+msgid "Month"
+msgstr "Месец"
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,info:0
+msgid "Work Description"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Invoice Analysis"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.report.xml,name:hr_timesheet.report_user_timesheet
+msgid "Employee timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_sign_in
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_sign_out
+msgid "Sign in / Sign out by project"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_define_analytic_structure
+msgid "Define your Analytic Structure"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "Sign in / Sign out"
+msgstr "Најава / Одјава"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/hr_timesheet.py:175
+#, python-format
+msgid ""
+"Analytic journal is not defined for employee %s \n"
+"Define an employee for the selected user and assign an analytic journal!"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "(Keep empty for current time)"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.employee:0
+msgid "Timesheets"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,help:hr_timesheet.action_define_analytic_structure
+msgid ""
+"You should create an analytic account structure depending on your needs to "
+"analyse costs and revenues. In OpenERP, analytic accounts are also used to "
+"track customer contracts."
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.analytic.timesheet,line_id:0
+msgid "Analytic Line"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "August"
+msgstr "Август"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "June"
+msgstr "Јуни"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+msgid "Print My Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Date"
+msgstr "Датум"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "November"
+msgstr "Ноември"
+
+#. module: hr_timesheet
+#: constraint:hr.employee:0
+msgid "Error ! You cannot create recursive Hierarchy of Employees."
+msgstr "Грешка! Не можете да креирате рекурзивна хиерархија на вработените."
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,date:0
+msgid "Closing Date"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "October"
+msgstr "Октомври"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "January"
+msgstr "Јануари"
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Key dates"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Thu"
+msgstr "Чет"
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Analysis stats"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_analytical_timesheet_employee
+msgid "Print Employee Timesheet & Print My Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,emp_id:0
+#: field:hr.sign.out.project,emp_id:0
+msgid "Employee ID"
+msgstr "Идентификационен Број на Вработениот"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "General Information"
+msgstr "Општи информации"
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_my
+msgid "My Current Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "December"
+msgstr "Декември"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+#: view:hr.analytical.timesheet.users:0
+#: view:hr.sign.in.project:0
+#: view:hr.sign.out.project:0
+msgid "Cancel"
+msgstr "Откажи"
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_users
+#: model:ir.actions.report.xml,name:hr_timesheet.report_users_timesheet
+#: model:ir.actions.wizard,name:hr_timesheet.wizard_hr_timesheet_users
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_timesheet_users
+msgid "Employees Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Information"
+msgstr "Информации"
+
+#. module: hr_timesheet
+#: field:hr.analytical.timesheet.employee,employee_id:0
+#: model:ir.model,name:hr_timesheet.model_hr_employee
+msgid "Employee"
+msgstr "Вработен"
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,help:hr_timesheet.act_hr_timesheet_line_evry1_all_form
+msgid ""
+"Through this menu you can register and follow your workings hours by project "
+"every day."
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,server_date:0
+#: field:hr.sign.out.project,server_date:0
+msgid "Current Date"
+msgstr "Тековен датум"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+msgid "This wizard will print monthly timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+#: field:hr.employee,product_id:0
+msgid "Product"
+msgstr "Продукт"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Invoicing"
+msgstr "Фактурирање"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "May"
+msgstr "Мај"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Total time"
+msgstr "Вкупно време"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "(local time on the server side)"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_sign_in_project
+msgid "Sign In By Project"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "February"
+msgstr "Февруари"
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_sign_out_project
+msgid "Sign Out By Project"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.users:0
+msgid "Employees"
+msgstr "Вработени"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "March"
+msgstr "Март"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "April"
+msgstr "Април"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/hr_timesheet.py:177
+#, python-format
+msgid ""
+"No analytic account defined on the project.\n"
+"Please set one or we can not automatically fill the timesheet."
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+#: view:hr.analytic.timesheet:0
+msgid "Users"
+msgstr "Корисници"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "Start Working"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Stats by user"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_print_employee.py:42
+#, python-format
+msgid "No employee defined for this user"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.analytical.timesheet.employee,year:0
+#: field:hr.analytical.timesheet.users,year:0
+msgid "Year"
+msgstr "Година"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Accounting"
+msgstr "Сметководство"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "Change Work"
+msgstr ""
+
+#~ msgid "Sum"
+#~ msgstr "Вкупно"
+
+#~ msgid "Total"
+#~ msgstr "Вкупно"
index cc04bed..59d688f 100644 (file)
@@ -23,7 +23,7 @@
     import time
     uid = ref('base.user_demo')
     new_id = self.create(cr, uid, {'emp_id': ref('hr.employee_qdp'), 'name': 'Quentin Paolino',
-    'server_date': time.strftime('%Y-%m-%d %H:%M:%S'), 'state': 'present'})
+    'server_date': time.strftime('%Y-%m-%d %H:%M:%S')})
     self.sign_in_result(cr, uid, [new_id], context)
 -
   I change my project "Thymbra" and I click on the "Change Work" button of this wizard
index e92e88b..031a17b 100644 (file)
@@ -147,7 +147,7 @@ class hr_si_project(osv.osv_memory):
             'view_type': 'form',
             'view_mode': 'tree,form',
             'res_model': 'hr.sign.%s.project' % in_out,
-            'views': [(False,'tree'), (resource_id,'form')],
+            'views': [(resource_id,'form')],
             'type': 'ir.actions.act_window',
             'target': 'new'
         }
index ab76f2b..67fcb10 100644 (file)
@@ -129,17 +129,18 @@ class account_analytic_line(osv.osv):
     def _default_journal(self, cr, uid, context=None):
         proxy = self.pool.get('hr.employee')
         record_ids = proxy.search(cr, uid, [('user_id', '=', uid)], context=context)
-        employee = proxy.browse(cr, uid, record_ids[0], context=context)
-        return employee.journal_id and employee.journal_id.id or False
+        if record_ids:
+            employee = proxy.browse(cr, uid, record_ids[0], context=context)
+            return employee.journal_id and employee.journal_id.id or False
+        return False
 
     def _default_general_account(self, cr, uid, context=None):
         proxy = self.pool.get('hr.employee')
         record_ids = proxy.search(cr, uid, [('user_id', '=', uid)], context=context)
-        if not record_ids:
-            raise osv.except_osv(_('Error!'), _('Please create an employee associated to this user.'))
-        employee = proxy.browse(cr, uid, record_ids[0], context=context)
-        if employee.product_id and employee.product_id.property_account_income:
-            return employee.product_id.property_account_income.id
+        if record_ids:
+            employee = proxy.browse(cr, uid, record_ids[0], context=context)
+            if employee.product_id and employee.product_id.property_account_income:
+                return employee.product_id.property_account_income.id
         return False
 
     _defaults = {
@@ -176,7 +177,7 @@ account_analytic_line()
 
 class hr_analytic_timesheet(osv.osv):
     _inherit = "hr.analytic.timesheet"
-    def on_change_account_id(self, cr, uid, ids, account_id):
+    def on_change_account_id(self, cr, uid, ids, account_id, user_id=False):
         res = {}
         if not account_id:
             return res
index b752ade..95fa39a 100644 (file)
@@ -50,7 +50,7 @@
             <field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
             <field name="arch" type="xml">
                 <field name="account_id" position="replace">
-                    <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id)" context="{'default_use_timesheets': 1}"/>
+                    <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/>
                 </field>
             </field>
         </record>
@@ -72,7 +72,7 @@
             <field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree"/>
             <field name="arch" type="xml">
                 <field name="account_id" position="replace">
-                    <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id)" context="{'default_use_timesheets': 1}"/>
+                    <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/>
                 </field>
             </field>
         </record>
index 96cb15d..e62134e 100644 (file)
@@ -388,7 +388,7 @@ class hr_timesheet_line(osv.osv):
         return True
 
     def multi_on_change_account_id(self, cr, uid, ids, account_ids, context=None):
-        return dict([(el, self.on_change_account_id(cr, uid, ids, el)) for el in account_ids])
+        return dict([(el, self.on_change_account_id(cr, uid, ids, el, context.get('user_id', uid))) for el in account_ids])
 
 
 hr_timesheet_line()
index b247805..fc35a17 100644 (file)
@@ -97,7 +97,7 @@
                             <field colspan="4" context="{'user_id':user_id}" name="timesheet_ids" nolabel="1">
                                 <tree editable="top" string="Timesheet Lines">
                                     <field name="date"/>
-                                    <field domain="[('type','in',['normal', 'contract']), ('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id)" context="{'default_use_timesheets': 1}"/>
+                                    <field domain="[('type','in',['normal', 'contract']), ('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/>
                                     <field name="name"/>
                                     <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time"/>
                                     <field name="to_invoice" widget="selection"/>
                                 </tree>
                                 <form string="Timesheet Lines" version="7.0">
                                     <field name="date"/>
-                                    <field domain="[('type','=','normal'), ('state', '&lt;&gt;', 'close')]" name="account_id" on_change="on_change_account_id(account_id)"/>
+                                    <field domain="[('type','=','normal'), ('state', '&lt;&gt;', 'close')]" name="account_id" on_change="on_change_account_id(account_id, user_id)"/>
                                     <field name="name"/>
                                     <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time"/>
                                     <field name="to_invoice"/>
diff --git a/addons/hr_timesheet_sheet/i18n/mk.po b/addons/hr_timesheet_sheet/i18n/mk.po
new file mode 100644 (file)
index 0000000..23a08ee
--- /dev/null
@@ -0,0 +1,1031 @@
+# Macedonian 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-10-22 12:23+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: Macedonian <mk@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-10-23 04:48+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
+
+#. module: hr_timesheet_sheet
+#: field:hr.analytic.timesheet,sheet_id:0 field:hr.attendance,sheet_id:0
+#: field:hr_timesheet_sheet.sheet.account,sheet_id:0
+#: field:hr_timesheet_sheet.sheet.day,sheet_id:0
+msgid "Sheet"
+msgstr "Лист"
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,name:hr_timesheet_sheet.process_transition_timesheetdraft0
+msgid "Service"
+msgstr "Сервис"
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/wizard/hr_timesheet_current.py:38
+#, python-format
+msgid "No employee defined for your user !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:hr_timesheet_sheet.sheet:0
+#: view:timesheet.report:0
+msgid "Group By..."
+msgstr "Групирај По..."
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,total_attendance:0
+#: field:hr_timesheet_sheet.sheet,total_attendance_day:0
+msgid "Total Attendance"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+#: field:hr_timesheet_sheet.sheet,department_id:0 view:timesheet.report:0
+#: field:timesheet.report,department_id:0
+msgid "Department"
+msgstr "Сектор"
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid "Timesheet in current year"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,name:hr_timesheet_sheet.process_transition_tasktimesheet0
+msgid "Task timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Today"
+msgstr "Денес"
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:274
+#, python-format
+msgid ""
+"Please verify that the total difference of the sheet is lower than %.2f !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "March"
+msgstr "Март"
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 field:timesheet.report,cost:0
+msgid "#Cost"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid "Timesheet of last month"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,company_id:0
+#: field:hr_timesheet_sheet.sheet,company_id:0 view:timesheet.report:0
+#: field:timesheet.report,company_id:0
+msgid "Company"
+msgstr "Фирма"
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:hr_timesheet_sheet.sheet:0
+#: model:ir.model,name:hr_timesheet_sheet.model_hr_timesheet_report
+#: model:ir.model,name:hr_timesheet_sheet.model_hr_timesheet_sheet_sheet
+#: model:ir.model,name:hr_timesheet_sheet.model_timesheet_report
+#: model:process.node,name:hr_timesheet_sheet.process_node_timesheet0
+#: view:timesheet.report:0
+msgid "Timesheet"
+msgstr "Работни Часови"
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Set to Draft"
+msgstr "Сетирај на Драфт"
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,date_to:0 field:timesheet.report,date_to:0
+msgid "Date to"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,note:hr_timesheet_sheet.process_node_invoiceonwork0
+msgid "Based on the timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid "Group by day of date"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:615
+#, python-format
+msgid "You cannot modify an entry in a confirmed timesheet!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition.action,name:hr_timesheet_sheet.process_transition_action_validatetimesheet0
+msgid "Validate"
+msgstr "Потврди"
+
+#. module: hr_timesheet_sheet
+#: selection:hr_timesheet_sheet.sheet,state:0
+msgid "Approved"
+msgstr "Одобрено"
+
+#. module: hr_timesheet_sheet
+#: selection:hr_timesheet_sheet.sheet,state_attendance:0
+msgid "Present"
+msgstr "Присутен"
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0
+msgid "Total Cost"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:263
+#, python-format
+msgid ""
+"In order to create a timesheet for this employee, you must assign the "
+"employee to an analytic journal!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+#: model:process.transition.action,name:hr_timesheet_sheet.process_transition_action_refusetimesheet0
+msgid "Refuse"
+msgstr "Одбиј"
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:619
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:639
+#, python-format
+msgid ""
+"You cannot enter an attendance date outside the current timesheet dates!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.actions.act_window,help:hr_timesheet_sheet.action_hr_timesheet_current_open
+msgid ""
+"My Timesheet opens your timesheet so that you can book your activities into "
+"the system. From the same form, you can register your attendances (Sign "
+"In/Out) and describe the working hours made on the different projects. At "
+"the end of the period defined in the company, the timesheet is confirmed by "
+"the user and can be validated by his manager. If required, as defined on the "
+"project, you can generate the invoices based on the timesheet."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet.day:0
+msgid "Total Difference"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid " Month-1 "
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "My Departments Timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.act_hr_timesheet_sheet_sheet_by_day
+msgid "Timesheet by Day"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet.account,name:0
+msgid "Project / Analytic Account"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,name:hr_timesheet_sheet.process_transition_validatetimesheet0
+msgid "Validation"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:274
+#, python-format
+msgid "Warning !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,note:hr_timesheet_sheet.process_node_attendance0
+msgid "Employee's timesheet entry"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,account_id:0
+#: view:timesheet.report:0 field:timesheet.report,account_id:0
+msgid "Analytic Account"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:timesheet.report,nbr:0
+msgid "#Nbr"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,date_from:0
+#: field:timesheet.report,date_from:0
+msgid "Date from"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0
+msgid " Month "
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.act_hr_employee_2_hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.act_hr_timesheet_sheet_form
+#: model:ir.ui.menu,name:hr_timesheet_sheet.menu_act_hr_timesheet_sheet_form
+#: view:res.company:0
+msgid "Timesheets"
+msgstr "Работни часови"
+
+#. module: hr_timesheet_sheet
+#: model:process.node,name:hr_timesheet_sheet.process_node_confirmedtimesheet0
+#: view:timesheet.report:0 selection:timesheet.report,state:0
+msgid "Confirmed"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet.day,total_attendance:0
+#: model:ir.model,name:hr_timesheet_sheet.model_hr_attendance
+#: model:process.node,name:hr_timesheet_sheet.process_node_attendance0
+msgid "Attendance"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition.action,name:hr_timesheet_sheet.process_transition_action_draftconfirmtimesheet0
+msgid "Confirm"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,timesheet_ids:0
+msgid "Timesheet lines"
+msgstr "Редови на работни часови"
+
+#. module: hr_timesheet_sheet
+#: constraint:res.company:0
+msgid "Error! You can not create recursive companies."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,state:0 view:timesheet.report:0
+#: field:timesheet.report,state:0
+msgid "State"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,note:hr_timesheet_sheet.process_node_confirmedtimesheet0
+msgid "State is 'confirmed'."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,employee_id:0
+msgid "Employee"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr_timesheet_sheet.sheet,state:0
+#: selection:timesheet.report,state:0
+msgid "New"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.action_week_attendance_graph
+msgid "My Total Attendances By Week"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:241
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:246
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:248
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:250
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:257
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:259
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:261
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:263
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:318
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:548
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:615
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:646
+#: code:addons/hr_timesheet_sheet/wizard/hr_timesheet_current.py:38
+#, python-format
+msgid "Error !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet.account,total:0
+msgid "Total Time"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.act_hr_timesheet_sheet_sheet_2_hr_analytic_timesheet
+msgid "Timesheet Lines"
+msgstr "Редови на работни часови"
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0
+msgid "Hours"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid "Group by month of date"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: constraint:hr.attendance:0
+msgid "Error: Sign in (resp. Sign out) must follow Sign out (resp. Sign in)"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:455
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:457
+#, python-format
+msgid "Invalid action !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,note:hr_timesheet_sheet.process_transition_validatetimesheet0
+msgid "The project manager validates the timesheets."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "July"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:res.company:0
+msgid "Configuration"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,name:hr_timesheet_sheet.process_node_workontask0
+msgid "Work on Task"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Daily"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 field:timesheet.report,quantity:0
+msgid "#Quantity"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,total_timesheet:0
+#: field:hr_timesheet_sheet.sheet,total_timesheet_day:0
+#: view:hr_timesheet_sheet.sheet.day:0
+#: field:hr_timesheet_sheet.sheet.day,total_timesheet:0
+msgid "Total Timesheet"
+msgstr "Вкупно работни часови"
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Available Attendance"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Sign In"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 field:timesheet.report,total_timesheet:0
+msgid "#Total Timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.model,name:hr_timesheet_sheet.model_hr_timesheet_current_open
+msgid "hr.timesheet.current.open"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Go to:"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "September"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "December"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:248
+#, python-format
+msgid ""
+"In order to create a timesheet for this employee, you must link the employee "
+"to a product, like 'Consultant'!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.current.open:0
+msgid "It will open your current timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:241
+#, python-format
+msgid "You cannot duplicate a timesheet!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,month:0
+#: selection:res.company,timesheet_range:0 view:timesheet.report:0
+#: field:timesheet.report,month:0
+msgid "Month"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 field:timesheet.report,total_diff:0
+msgid "#Total Diff"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "In Draft"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:261
+#, python-format
+msgid ""
+"In order to create a timesheet for this employee, you must link the employee "
+"to a product!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,name:hr_timesheet_sheet.process_transition_attendancetimesheet0
+msgid "Sign in/out"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr_timesheet_sheet.sheet,state:0
+msgid "Waiting Approval"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,name:hr_timesheet_sheet.process_transition_invoiceontimesheet0
+msgid "Billing"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,note:hr_timesheet_sheet.process_transition_timesheetdraft0
+msgid ""
+"The timesheet line represents the time spent by the employee on a specific "
+"service provided."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: constraint:hr_timesheet_sheet.sheet:0
+msgid "You must select a Current date which is in the timesheet dates !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,name:0
+msgid "Note"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.actions.act_window,help:hr_timesheet_sheet.action_hr_timesheet_report_stat_all
+msgid ""
+"This report performs analysis on timesheets created by your human resources "
+"in the system. It allows you to have a full overview of  entries done by "
+"your employees. You can group them by specific selection criteria thanks to "
+"the search tool."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 selection:timesheet.report,state:0
+msgid "Draft"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:res.company,timesheet_max_difference:0
+msgid "Timesheet allowed difference(Hours)"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,note:hr_timesheet_sheet.process_transition_invoiceontimesheet0
+msgid "The invoice is created based on the timesheet."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,name:hr_timesheet_sheet.process_node_drafttimesheetsheet0
+msgid "Draft Timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:res.company,timesheet_range:0
+msgid "Week"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "August"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Approve"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "June"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,state_attendance:0
+msgid "Current Status"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:646
+#, python-format
+msgid "You cannot modify an entry in a confirmed timesheet !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.model,name:hr_timesheet_sheet.model_hr_timesheet_sheet_sheet_account
+#: model:ir.model,name:hr_timesheet_sheet.model_hr_timesheet_sheet_sheet_day
+msgid "Timesheets by Period"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,user_id:0
+#: field:hr_timesheet_sheet.sheet,user_id:0 view:timesheet.report:0
+#: field:timesheet.report,user_id:0
+msgid "User"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.act_hr_timesheet_sheet_sheet_by_account
+msgid "Timesheet by Account"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr.timesheet.report,date:0 field:hr_timesheet_sheet.sheet.day,name:0
+msgid "Date"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "November"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid "Extended Filters..."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:res.company,timesheet_range:0
+msgid "Timesheet range"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:548
+#, python-format
+msgid "You can not modify an entry in a confirmed timesheet !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:board.board:0
+msgid "My Total Attendance By Week"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:259
+#, python-format
+msgid ""
+"You cannot have 2 timesheets that overlaps!\n"
+"You should use the menu 'My Timesheet' to avoid this problem."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "October"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.actions.act_window,help:hr_timesheet_sheet.act_hr_timesheet_sheet_form
+msgid ""
+"Check your timesheets for a specific period. You can also encode time spent "
+"on a project (i.e. an analytic account) thus generating costs in the "
+"analytic account concerned."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:237
+#, python-format
+msgid ""
+"The timesheet cannot be validated as it does not contain an equal number of "
+"sign ins and sign outs!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "January"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,note:hr_timesheet_sheet.process_transition_attendancetimesheet0
+msgid "The employee signs in and signs out."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.model,name:hr_timesheet_sheet.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Summary"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: constraint:hr_timesheet_sheet.sheet:0
+msgid ""
+"You cannot have 2 timesheets that overlaps !\n"
+"Please use the menu 'My Current Timesheet' to avoid this problem."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Unvalidated Timesheets"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:457
+#, python-format
+msgid "You cannot delete a timesheet which have attendance entries!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr.timesheet.report,quantity:0
+msgid "Quantity"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:455
+#, python-format
+msgid "You cannot delete a timesheet which is already confirmed!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,general_account_id:0
+#: view:timesheet.report:0 field:timesheet.report,general_account_id:0
+msgid "General Account"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: help:res.company,timesheet_range:0
+msgid "Periodicity on which you validate your timesheets."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet.account:0
+msgid "Search Account"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: help:res.company,timesheet_max_difference:0
+msgid ""
+"Allowed difference in hours between the sign in/out and the timesheet "
+"computation for one sheet. Set this to 0 if you do not want any control."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0 field:hr_timesheet_sheet.sheet,period_ids:0
+#: view:hr_timesheet_sheet.sheet.day:0
+msgid "Period"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,day:0
+#: selection:res.company,timesheet_range:0 view:timesheet.report:0
+#: field:timesheet.report,day:0
+msgid "Day"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.current.open:0
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.action_hr_timesheet_current_open
+#: model:ir.actions.server,name:hr_timesheet_sheet.ir_actions_server_timsheet_sheet
+#: model:ir.ui.menu,name:hr_timesheet_sheet.menu_act_hr_timesheet_sheet_form_my_current
+msgid "My Current Timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 selection:timesheet.report,state:0
+msgid "Done"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,note:hr_timesheet_sheet.process_node_drafttimesheetsheet0
+msgid "State is 'draft'."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: constraint:hr.analytic.timesheet:0
+msgid "You cannot modify an entry in a Confirmed/Done timesheet !."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.current.open:0
+msgid "Cancel"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,name:hr_timesheet_sheet.process_node_validatedtimesheet0
+msgid "Validated"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,name:hr_timesheet_sheet.process_node_invoiceonwork0
+msgid "Invoice on Work"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid "Timesheet in current month"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet.account:0
+msgid "Timesheet by Accounts"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/wizard/hr_timesheet_current.py:51
+#, python-format
+msgid "Open Timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 view:timesheet.report:0
+msgid "Group by year of date"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,note:hr_timesheet_sheet.process_node_validatedtimesheet0
+msgid "State is 'validated'."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: help:hr_timesheet_sheet.sheet,state:0
+msgid ""
+" * The 'Draft' state is used when a user is encoding a new and unconfirmed "
+"timesheet.                 \n"
+"* The 'Confirmed' state is used for to confirm the timesheet by user.        "
+"         \n"
+"* The 'Done' state is used when users timesheet is accepted by his/her "
+"senior."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.action_hr_timesheet_report_stat_all
+#: model:ir.ui.menu,name:hr_timesheet_sheet.menu_hr_timesheet_report_all
+msgid "Timesheet Analysis"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Search Timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Confirmed Timesheets"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.model,name:hr_timesheet_sheet.model_hr_analytic_timesheet
+msgid "Timesheet Line"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,product_id:0
+#: view:timesheet.report:0 field:timesheet.report,product_id:0
+msgid "Product"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+#: field:hr_timesheet_sheet.sheet,attendances_ids:0
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.act_hr_timesheet_sheet_sheet_2_hr_attendance
+msgid "Attendances"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr.timesheet.report,name:0 field:timesheet.report,name:0
+msgid "Description"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,note:hr_timesheet_sheet.process_transition_confirmtimesheet0
+msgid "The employee periodically confirms his own timesheets."
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "May"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,note:hr_timesheet_sheet.process_node_workontask0
+msgid "Defines the work summary of task"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Sign Out"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,note:hr_timesheet_sheet.process_transition_tasktimesheet0
+msgid "Moves task entry into the timesheet line"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet.day:0
+msgid "Total Attendances"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:ir.actions.act_window,name:hr_timesheet_sheet.action_timesheet_report_stat_all
+#: model:ir.ui.menu,name:hr_timesheet_sheet.menu_timesheet_report_all
+msgid "Timesheet Sheet Analysis"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,total_difference:0
+#: field:hr_timesheet_sheet.sheet,total_difference_day:0
+#: field:hr_timesheet_sheet.sheet.day,total_difference:0
+msgid "Difference"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr_timesheet_sheet.sheet,state_attendance:0
+msgid "Absent"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "February"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: sql_constraint:res.company:0
+msgid "The company name must be unique !"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Employees"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.node,note:hr_timesheet_sheet.process_node_timesheet0
+msgid "Information of time spent on a service"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: selection:hr.timesheet.report,month:0 selection:timesheet.report,month:0
+msgid "April"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.transition,name:hr_timesheet_sheet.process_transition_confirmtimesheet0
+msgid "Confirmation"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet.account,invoice_rate:0
+msgid "Invoice rate"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:619
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:639
+#, python-format
+msgid "UserError"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:250
+#, python-format
+msgid ""
+"In order to create a timesheet for this employee, you must assign the "
+"employee to an analytic journal, like 'Timesheet'!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:318
+#, python-format
+msgid "You cannot sign in/sign out from an other date than today"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "Submit to Manager"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,account_ids:0
+msgid "Analytic accounts"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 field:timesheet.report,to_invoice:0
+msgid "Type of Invoicing"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:246
+#: code:addons/hr_timesheet_sheet/hr_timesheet_sheet.py:257
+#, python-format
+msgid ""
+"In order to create a timesheet for this employee, you must assign it to a "
+"user!"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:timesheet.report:0 field:timesheet.report,total_attendance:0
+msgid "#Total Attendance"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr.timesheet.report,cost:0
+msgid "Cost"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr_timesheet_sheet.sheet,date_current:0
+#: field:timesheet.report,date_current:0
+msgid "Current date"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: model:process.process,name:hr_timesheet_sheet.process_process_hrtimesheetprocess0
+msgid "Hr Timesheet"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.report:0 field:hr.timesheet.report,year:0
+#: view:timesheet.report:0 field:timesheet.report,year:0
+msgid "Year"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr.timesheet.current.open:0 selection:hr_timesheet_sheet.sheet,state:0
+msgid "Open"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet:0
+msgid "To Approve"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: view:hr_timesheet_sheet.sheet.account:0
+msgid "Total"
+msgstr ""
+
+#. module: hr_timesheet_sheet
+#: field:hr.timesheet.report,journal_id:0
+msgid "Journal"
+msgstr ""
+
+#~ msgid "My Timesheet"
+#~ msgstr "Мои работни часови"
index 497fe8d..cfd87d7 100644 (file)
@@ -46,6 +46,7 @@ class timesheet_report(osv.osv):
         'department_id':fields.many2one('hr.department','Department',readonly=True),
         'date_from': fields.date('Date from',readonly=True,),
         'date_to': fields.date('Date to',readonly=True),
+        'date_current': fields.date('Current date', required=True),
         'state' : fields.selection([
             ('new', 'New'),
             ('draft','Draft'),
@@ -64,6 +65,9 @@ class timesheet_report(osv.osv):
                         htss.name,
                         htss.date_from,
                         htss.date_to,
+                        to_char(htss.date_from, 'YYYY-MM-DD') as day,
+                        to_char(htss.date_from, 'YYYY') as year,
+                        to_char(htss.date_from, 'MM') as month,
                         count(*) as nbr,
                         aal.unit_amount as quantity,
                         aal.amount as cost,
index 178009b..0b16827 100644 (file)
@@ -1,10 +1,6 @@
 -
-  !record {model: ir.actions.todo, id: config_call_account_template}:
-    action_id: account.action_wizard_multi_chart
-    type: automatic
--
   !python {model: ir.actions.todo}: |
-    install_todo = self.browse(cr, uid, ref('l10n_be.config_call_account_template'))
+    install_todo = self.browse(cr, uid, ref('account.action_wizard_multi_chart_todo'))
     if install_todo.state == 'open':
         wiz = self.pool.get('wizard.multi.charts.accounts')
         values = {
index e9822e2..305ec40 100644 (file)
@@ -1,28 +1,41 @@
-# Spanish translation for openobject-addons
-# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# Spanish (Mexico) 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>, 2011.
+# 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: 2011-01-07 06:07+0000\n"
-"PO-Revision-Date: 2011-02-15 15:37+0000\n"
+"POT-Creation-Date: 2011-12-23 09:56+0000\n"
+"PO-Revision-Date: 2012-10-22 22:58+0000\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: Spanish <es@li.org>\n"
+"Language-Team: Spanish (Mexico) <es_MX@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: 2011-09-05 05:58+0000\n"
-"X-Generator: Launchpad (build 13830)\n"
+"X-Launchpad-Export-Date: 2012-10-24 04:55+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
 
 #. module: l10n_mx
-#: model:ir.module.module,description:l10n_mx.module_meta_information
-msgid ""
-"This is the module to manage the accounting chart for Mexico in Open ERP."
-msgstr ""
-"Este es el módulo para gestionar el plan contable para Méjico en Open ERP."
+#: model:account.account.type,name:l10n_mx.account_type_receivable
+msgid "Receivable"
+msgstr "Por cobrar"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_equity
+msgid "Equity"
+msgstr "Capital"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_tax
+msgid "Tax"
+msgstr "Impuesto"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_cash
+msgid "Cash"
+msgstr "Efectivo"
 
 #. module: l10n_mx
 #: model:ir.actions.todo,note:l10n_mx.config_call_account_template_mx_chart
@@ -35,16 +48,28 @@ msgid ""
 "Management/Configuration/Financial Accounting/Financial Accounts/Generate "
 "Chart of Accounts from a Chart Template."
 msgstr ""
-"Generar Plan Contable a partir de una plantilla de Plan. Se le preguntará "
-"por el nombre de la compañía, la plantilla de plan contable a seguir, el no. "
-"de dígitos para generar el código de sus cuentas y la cuenta bancaria, la "
-"divisa para crear Diarios. Por lo tanto, la copia exacta de la plantilla de "
-"plan contable será generada.\n"
-"Este es el mismo asistente que se ejecuta desde Gestión "
-"Financiera/Configuración/Contabilidad Financiera/Contabilidad "
-"Financiera/Generar Plan Contable a partir de una Plantilla de Plan."
-
-#. module: l10n_mx
-#: model:ir.module.module,shortdesc:l10n_mx.module_meta_information
-msgid "Mexico - Chart of Account"
-msgstr "Méjico - Plan Contable"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_payable
+msgid "Payable"
+msgstr "A pagar"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_asset
+msgid "Asset"
+msgstr "Activo"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_income
+msgid "Income"
+msgstr "Ingreso"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_expense
+msgid "Expense"
+msgstr "Gasto"
+
+#. module: l10n_mx
+#: model:account.account.type,name:l10n_mx.account_type_view
+msgid "View"
+msgstr "Vista"
index abf714a..aea7ee6 100644 (file)
@@ -27,6 +27,7 @@ import mail_mail
 import mail_thread
 import mail_group
 import mail_vote
+import mail_favorite
 import res_partner
 import res_users
 import report
@@ -36,4 +37,3 @@ import mail_group_menu
 import update
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
index 39a3f1b..27565bc 100644 (file)
@@ -28,7 +28,7 @@
     'description': """
 Business oriented Social Networking
 ===================================
-The Social Networking module provides a unified social network abstraction layer allowing applications to display a complete 
+The Social Networking module provides a unified social network abstraction layer allowing applications to display a complete
 communication history on documents with a fully-integrated email and message management system.
 
 It enables the users to read and send messages as well as emails. It also provides a feeds page combined to a subscription mechanism that allows to follow documents and to be constantly updated about recent news.
@@ -54,6 +54,7 @@ Main Features
         'mail_message_view.xml',
         'mail_mail_view.xml',
         'mail_followers_view.xml',
+        'mail_favorite_view.xml',
         'mail_thread_view.xml',
         'mail_group_view.xml',
         'res_partner_view.xml',
diff --git a/addons/mail/mail_favorite.py b/addons/mail/mail_favorite.py
new file mode 100644 (file)
index 0000000..4fe5fbd
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2012-Today OpenERP SA (<http://www.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
+
+
+class mail_favorite(osv.Model):
+    ''' Favorite model: relationship table between messages and users. A favorite
+        message is a message the user wants to see in a specific 'Favorite'
+        mailbox, like a starred mechanism. '''
+
+    _name = 'mail.favorite'
+    _description = 'Favorite messages'
+    _columns = {
+            'message_id': fields.many2one('mail.message', 'Message', select=1,
+                ondelete='cascade', required=True),
+            'user_id': fields.many2one('res.users', 'User', select=1,
+                ondelete='cascade', required=True),
+        }
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/mail_favorite_view.xml b/addons/mail/mail_favorite_view.xml
new file mode 100644 (file)
index 0000000..3aa73d5
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<openerp>
+    <data>
+
+        <!--  FOLLOWERS !-->
+        <record model="ir.ui.view" id="view_mail_favorite_tree">
+            <field name="name">mail.favorite.tree</field>
+            <field name="model">mail.favorite</field>
+            <field name="arch" type="xml">
+                <tree string="Favorites">
+                    <field name="user_id"/>
+                    <field name="message_id"/>
+                </tree>
+            </field>
+        </record>
+
+        <record model="ir.ui.view" id="view_mail_favorite_form">
+            <field name="name">mail.favorite.form</field>
+            <field name="model">mail.favorite</field>
+            <field name="arch" type="xml">
+                <form string="Favorite Form" version="7.0">
+                    <sheet>
+                        <group>
+                            <field name="user_id"/>
+                            <field name="message_id"/>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+
+        <record id="action_view_favorites" model="ir.actions.act_window">
+            <field name="name">Favorites</field>
+            <field name="res_model">mail.favorite</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+
+        <!-- Add favorites related menu entries in Settings/Email -->
+        <menuitem name="Favorites" id="menu_email_favorites" parent="base.menu_email"
+                    action="action_view_favorites" sequence="40" groups="base.group_no_one"/>
+
+    </data>
+</openerp>
index 707ece6..a29ee25 100644 (file)
@@ -41,7 +41,7 @@ class ir_ui_menu(osv.osv):
         """ Override to take off menu entries (mail.group) the user is not
             following. Access are done using SUPERUSER_ID to avoid access
             rights issues for an internal back-end algorithm. """
-        ids = super(ir_ui_menu, self).search(cr, uid, args, offset=0, limit=None, order=order, context=context, count=False)
+        ids = super(ir_ui_menu, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=False)
         partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
         follower_obj = self.pool.get('mail.followers')
         for menu in self.browse(cr, uid, ids, context=context):
@@ -52,4 +52,6 @@ class ir_ui_menu(osv.osv):
                     ], context=context)
                 if not sub_ids:
                     ids.remove(menu.id)
+        if count:
+            return len(ids)
         return ids
index b8c1edc..8719d59 100644 (file)
 ##############################################################################
 
 import logging
-import openerp
 import tools
 
 from email.header import decode_header
 from openerp import SUPERUSER_ID
-from operator import itemgetter
 from osv import osv, orm, fields
 from tools.translate import _
 
@@ -48,7 +46,10 @@ class mail_message(osv.Model):
     _order = 'id desc'
 
     _message_read_limit = 10
+    _message_read_fields = ['id', 'parent_id', 'model', 'res_id', 'body', 'subject', 'date', 'to_read',
+        'type', 'vote_user_ids', 'attachment_ids', 'author_id', 'partner_ids', 'record_name', 'favorite_user_ids']
     _message_record_name_length = 18
+    _message_read_more_limit = 1024
 
     def _shorten_name(self, name):
         if len(name) <= (self._message_record_name_length + 3):
@@ -56,7 +57,9 @@ class mail_message(osv.Model):
         return name[:self._message_record_name_length] + '...'
 
     def _get_record_name(self, cr, uid, ids, name, arg, context=None):
-        """ Return the related document name, using get_name. """
+        """ Return the related document name, using name_get. It is included in
+            a try/except statement, because if uid cannot read the related
+            document, he should see a void string instead of crashing. """
         result = dict.fromkeys(ids, False)
         for message in self.read(cr, uid, ids, ['model', 'res_id'], context=context):
             if not message['model'] or not message['res_id']:
@@ -69,7 +72,7 @@ class mail_message(osv.Model):
 
     def _get_to_read(self, cr, uid, ids, name, arg, context=None):
         """ Compute if the message is unread by the current user. """
-        res = dict((id, {'to_read': False}) for id in ids)
+        res = dict((id, False) for id in ids)
         partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
         notif_obj = self.pool.get('mail.notification')
         notif_ids = notif_obj.search(cr, uid, [
@@ -78,16 +81,16 @@ class mail_message(osv.Model):
             ('read', '=', False)
         ], context=context)
         for notif in notif_obj.browse(cr, uid, notif_ids, context=context):
-            res[notif.message_id.id]['to_read'] = True
+            res[notif.message_id.id] = not notif.read
         return res
 
     def _search_to_read(self, cr, uid, obj, name, domain, context=None):
         """ Search for messages to read by the current user. Condition is
             inversed because we search unread message on a read column. """
         if domain[0][2]:
-            read_cond = '(read = false or read is null)'
+            read_cond = "(read = False OR read IS NULL)"
         else:
-            read_cond = 'read = true'
+            read_cond = "read = True"
         partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
         cr.execute("SELECT message_id FROM mail_notification "\
                         "WHERE partner_id = %%s AND %s" % read_cond,
@@ -132,8 +135,12 @@ class mail_message(osv.Model):
             type='boolean', string='To read',
             help='Functional field to search for messages the current user has to read'),
         'subtype_id': fields.many2one('mail.message.subtype', 'Subtype'),
-        'vote_user_ids': fields.many2many('res.users', 'mail_vote', 'message_id', 'user_id', string='Votes',
+        'vote_user_ids': fields.many2many('res.users', 'mail_vote',
+            'message_id', 'user_id', string='Votes',
             help='Users that voted for this message'),
+        'favorite_user_ids': fields.many2many('res.users', 'mail_favorite',
+            'message_id', 'user_id', string='Favorite',
+            help='Users that set this message in their favorites'),
     }
 
     def _needaction_domain_get(self, cr, uid, context=None):
@@ -142,8 +149,7 @@ class mail_message(osv.Model):
         return []
 
     def _get_default_author(self, cr, uid, context=None):
-        # remove context to avoid possible hack in browse with superadmin using context keys that could trigger a specific behavior
-        return self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id
+        return self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
 
     _defaults = {
         'type': 'email',
@@ -156,33 +162,49 @@ class mail_message(osv.Model):
     # Vote/Like
     #------------------------------------------------------
 
-    def vote_toggle(self, cr, uid, ids, user_ids=None, context=None):
-        ''' Toggles voting. Done as SUPERUSER_ID because of write access on
-            mail.message not always granted. '''
-        if not user_ids:
-            user_ids = [uid]
+    def vote_toggle(self, cr, uid, ids, context=None):
+        ''' Toggles vote. Performed using read to avoid access rights issues.
+            Done as SUPERUSER_ID because uid may vote for a message he cannot modify. '''
         for message in self.read(cr, uid, ids, ['vote_user_ids'], context=context):
-            for user_id in user_ids:
-                has_voted = user_id in message.get('vote_user_ids')
-                if not has_voted:
-                    self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(4, user_id)]}, context=context)
-                else:
-                    self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(3, user_id)]}, context=context)
-        return not(has_voted) or False
+            new_has_voted = not (uid in message.get('vote_user_ids'))
+            if new_has_voted:
+                self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(4, uid)]}, context=context)
+            else:
+                self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(3, uid)]}, context=context)
+        return new_has_voted or False
+
+    #------------------------------------------------------
+    # Favorite
+    #------------------------------------------------------
+
+    def favorite_toggle(self, cr, uid, ids, context=None):
+        ''' Toggles favorite. Performed using read to avoid access rights issues.
+            Done as SUPERUSER_ID because uid may star a message he cannot modify. '''
+        for message in self.read(cr, uid, ids, ['favorite_user_ids'], context=context):
+            new_is_favorite = not (uid in message.get('favorite_user_ids'))
+            if new_is_favorite:
+                self.write(cr, SUPERUSER_ID, message.get('id'), {'favorite_user_ids': [(4, uid)]}, context=context)
+            else:
+                self.write(cr, SUPERUSER_ID, message.get('id'), {'favorite_user_ids': [(3, uid)]}, context=context)
+        return new_is_favorite or False
 
     #------------------------------------------------------
     # Message loading for web interface
     #------------------------------------------------------
 
     def _message_get_dict(self, cr, uid, message, context=None):
-        """ Return a dict representation of the message.
+        """ Return a dict representation of the message. This representation is
+            used in the JS client code, to display the messages.
 
             :param dict message: read result of a mail.message
         """
+        has_voted = False
         if uid in message['vote_user_ids']:
             has_voted = True
-        else:
-            has_voted = False
+
+        is_favorite = False
+        if uid in message['favorite_user_ids']:
+            is_favorite = True
 
         try:
             attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, message['attachment_ids'], context=context)]
@@ -206,35 +228,48 @@ class mail_message(osv.Model):
             'date': message['date'],
             'author_id': message['author_id'],
             'is_author': message['author_id'] and message['author_id'][0] == uid,
+            # TDE note: is this useful ? to check
             'partner_ids': partner_ids,
             'parent_id': message['parent_id'] and message['parent_id'][0] or False,
             # TDE note: see with CHM about votes, how they are displayed (only number, or name_get ?)
-            # 'vote_user_ids': vote_ids,
+            # vote: should only use number of votes
+            'vote_nb': len(message['vote_user_ids']),
             'has_voted': has_voted,
+            'is_private': message['model'] and message['res_id'],
+            'is_favorite': is_favorite,
             'to_read': message['to_read'],
         }
 
-    def _message_read_expandable(self, cr, uid, tree, result, message_loaded, domain, context, parent_id, limit):
+    def _message_read_expandable(self, cr, uid, message_list, read_messages,
+            message_loaded_ids=[], domain=[], context=None, parent_id=False, limit=None):
         """ Create the expandable message for all parent message read
             this function is used by message_read
-            TDE note: add default values for args, add some comments
 
-            :param dict tree: tree of message ids
+            :param list message_list: list of messages given by message_read to
+                which we have to add expandables
+            :param dict read_messages: dict [id]: read result of the messages to
+                easily have access to their values, given their ID
         """
+        # sort for group items / TDE: move to message_read
+        # result = sorted(result, key=lambda k: k['id'])
         tree_not = []
         # expandable for not show message
-        for msg_id in tree:
-            # get all childs
-            not_loaded_ids = self.search(cr, SUPERUSER_ID, [
-                ('parent_id', '=', msg_id),
-                ('id', 'not in', message_loaded)
-                ], context=context, limit=1000)
+        id_list = sorted(read_messages.keys())
+        for message_id in id_list:
+            message = read_messages[message_id]
+
+            # TDE note: check search is correctly implemented in mail.message
+            not_loaded_ids = self.search(cr, uid, [
+                ('parent_id', '=', message['id']),
+                ('id', 'not in', message_loaded_ids),
+                ], context=context, limit=self._message_read_more_limit)
             # group childs not read
             id_min = None
             id_max = None
             nb = 0
+
             for not_loaded_id in not_loaded_ids:
-                if not_loaded_id not in tree:
+                if not read_messages.get(not_loaded_id):
                     nb += 1
                     if id_min == None or id_min > not_loaded_id:
                         id_min = not_loaded_id
@@ -243,42 +278,43 @@ class mail_message(osv.Model):
                     tree_not.append(not_loaded_id)
                 else:
                     if nb > 0:
-                        result.append({
-                            'domain': [('id', '>=', id_min), ('id', '<=', id_max), ('parent_id', '=', msg_id)],
+                        message_list.append({
+                            'domain': [('id', '>=', id_min), ('id', '<=', id_max), ('parent_id', '=', message_id)],
                             'nb_messages': nb,
                             'type': 'expandable',
-                            'parent_id': msg_id,
+                            'parent_id': message_id,
                             'id':  id_min,
+                            'model':  message['model']
                         })
                     id_min = None
                     id_max = None
                     nb = 0
             if nb > 0:
-                result.append({
-                    'domain': [('id', '>=', id_min), ('id', '<=', id_max), ('parent_id', '=', msg_id)],
+                message_list.append({
+                    'domain': [('id', '>=', id_min), ('id', '<=', id_max), ('parent_id', '=', message_id)],
                     'nb_messages': nb,
                     'type': 'expandable',
-                    'parent_id': msg_id,
-                    'id':  id_min
+                    'parent_id': message_id,
+                    'id':  id_min,
+                    'model':  message['model'],
                 })
 
+        for msg_id in read_messages.keys() + tree_not:
+            message_loaded_ids.append(msg_id)
+
         # expandable for limit max
-        ids = self.search(cr, SUPERUSER_ID, domain + [('id', 'not in', message_loaded + tree + tree_not)], context=context, limit=1)
+        ids = self.search(cr, uid, domain + [('id', 'not in', message_loaded_ids)], context=context, limit=1)
         if len(ids) > 0:
-            result.append({
+            message_list.append({
                 'domain': domain,
                 'nb_messages': 0,
                 'type': 'expandable',
                 'parent_id': parent_id,
-                'id': -1
+                'id': -1,
+                'max_limit': True,
             })
 
-        result = sorted(result, key=lambda k: k['id'])
-
-        return result
-
-    _message_read_fields = ['id', 'parent_id', 'model', 'res_id', 'body', 'subject', 'date', 'to_read',
-        'type', 'vote_user_ids', 'attachment_ids', 'author_id', 'partner_ids', 'record_name']
+        return message_list
 
     def _get_parent(self, cr, uid, message, context=None):
         """ Tools method that tries to get the parent of a mail.message. If
@@ -295,11 +331,11 @@ class mail_message(osv.Model):
         except (orm.except_orm, osv.except_osv):
             return False
 
-    def message_read(self, cr, uid, ids=False, domain=[], context=None, parent_id=False, limit=None):
+    def message_read(self, cr, uid, ids=False, domain=[], message_loaded_ids=[], context=None, parent_id=False, limit=None):
         """ Read messages from mail.message, and get back a structured tree
             of messages to be displayed as discussion threads. If IDs is set,
             fetch these records. Otherwise use the domain to fetch messages.
-            After having fetch messages, their parents will be added to obtain
+            After having fetch messages, their parents & child will be added to obtain
             well formed threads.
 
             TDE note: update this comment after final method implementation
@@ -310,60 +346,51 @@ class mail_message(osv.Model):
                 further parents
             :return list: list of trees of messages
         """
-        # don't read the message display by .js, in context message_loaded list
-        # TDE note: use an argument, do not use context
-        if context is None:
-            context = {}
-        if context.get('message_loaded'):
-            domain += [('id', 'not in', context.get('message_loaded'))]
+        if message_loaded_ids:
+            domain += [('id', 'not in', message_loaded_ids)]
         limit = limit or self._message_read_limit
-        id_tree = []
+        read_messages = {}
         message_list = []
-        record = None
 
-        # select ids
-        # TDE note: should not receive [None] -> investigate
-        if ids and ids != [None]:
+        # specific IDs given: fetch those ids and return directly the message list
+        if ids:
             for message in self.read(cr, uid, ids, self._message_read_fields, context=context):
                 message_list.append(self._message_get_dict(cr, uid, message, context=context))
+            message_list = sorted(message_list, key=lambda k: k['id'])
             return message_list
 
-        # key: ID, value: record
-        ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit)
-
+        # TDE FIXME: check access rights on search are implemented for mail.message
+        # fetch messages according to the domain, add their parents if uid has access to
+        ids = self.search(cr, uid, domain, context=context, limit=limit)
         for message in self.read(cr, uid, ids, self._message_read_fields, context=context):
-            # if not in record and not in message_loded list
-            if message['id'] not in id_tree and message['id'] not in context.get('message_loaded', []):
-                record = self._message_get_dict(cr, uid, message, context=context)
-                id_tree.append(message['id'])
-                message_list.append(record)
-
-            parent = self._get_parent(cr, uid, message, context=context)
-            while parent and parent['id'] != parent_id:
-                if parent['id'] not in id_tree:
-                    message = parent
-                    id_tree.append(message['id'])
-                    # if not in record and not in message_loded list
-                    if message['id'] not in context.get('message_loaded', []):
-                        record = self._message_get_dict(cr, uid, message, context=context)
-                        message_list.append(record)
-                parent = self._get_parent(cr, uid, parent, context=context)
+            # if not in tree and not in message_loded list
+            if not read_messages.get(message.get('id')) and message.get('id') not in message_loaded_ids:
+                read_messages[message.get('id')] = message
+                message_list.append(self._message_get_dict(cr, uid, message, context=context))
 
-        message_list = sorted(message_list, key=lambda k: k['id'])
+                # get all parented message if the user have the access
+                parent = self._get_parent(cr, uid, message, context=context)
+                while parent and parent.get('id') != parent_id:
+                    if not read_messages.get(parent.get('id')) and parent.get('id') not in message_loaded_ids:
+                        read_messages[parent.get('id')] = parent
+                        message_list.append(self._message_get_dict(cr, uid, parent, context=context))
+                    parent = self._get_parent(cr, uid, parent, context=context)
 
-        message_list = self._message_read_expandable(cr, uid, id_tree, message_list, context.get('message_loaded', []), domain, context, parent_id, limit)
+        # get the child expandable messages for the tree
+        message_list = sorted(message_list, key=lambda k: k['id'])
+        message_list = self._message_read_expandable(cr, uid, message_list, read_messages,
+            message_loaded_ids=message_loaded_ids, domain=domain, context=context, parent_id=parent_id, limit=limit)
 
+        # message_list = sorted(message_list, key=lambda k: k['id'])
         return message_list
 
     # TDE Note: do we need this ?
     # def user_free_attachment(self, cr, uid, context=None):
-    #     attachment_list = []
-
     #     attachment = self.pool.get('ir.attachment')
-    #     attachment_ids = attachment.search(cr, uid, [('res_model','=',''),('create_uid','=',uid)])
+    #     attachment_list = []
+    #     attachment_ids = attachment.search(cr, uid, [('res_model', '=', 'mail.message'), ('create_uid', '=', uid)])
     #     if len(attachment_ids):
     #         attachment_list = [{'id': attach.id, 'name': attach.name, 'date': attach.create_date} for attach in attachment.browse(cr, uid, attachment_ids, context=context)]
-
     #     return attachment_list
 
     #------------------------------------------------------
@@ -384,7 +411,8 @@ class mail_message(osv.Model):
                 - Otherwise: raise
             - create: if
                 - I am in the document message_follower_ids OR
-                - I can write on the related document if res_model, res_id
+                - I can write on the related document if res_model, res_id OR
+                - I create a private message (no model, no res_id)
                 - Otherwise: raise
             - write: if
                 - I can write on the related document if res_model, res_id
@@ -422,6 +450,10 @@ class mail_message(osv.Model):
         if operation == 'read':
             author_ids = [mid for mid, message in message_values.iteritems()
                 if message.get('author_id') and message.get('author_id') == partner_id]
+        # Create: Check messages you create that are private messages -> ir.rule ?
+        elif operation == 'create':
+            author_ids = [mid for mid, message in message_values.iteritems()
+                if not message.get('model') and not message.get('res_id')]
         else:
             author_ids = []
 
@@ -480,13 +512,14 @@ class mail_message(osv.Model):
     def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
         """ Override to explicitely call check_access_rule, that is not called
             by the ORM. It instead directly fetches ir.rules and apply them. """
-        res = super(mail_message, self).read(cr, uid, ids, fields=fields, context=context, load=load)
         self.check_access_rule(cr, uid, ids, 'read', context=context)
+        res = super(mail_message, self).read(cr, uid, ids, fields=fields, context=context, load=load)
         return res
 
     def unlink(self, cr, uid, ids, context=None):
         # cascade-delete attachments that are directly attached to the message (should only happen
         # for mail.messages that act as parent for a standalone mail.mail record).
+        self.check_access_rule(cr, uid, ids, 'unlink', context=context)
         attachments_to_delete = []
         for message in self.browse(cr, uid, ids, context=context):
             for attach in message.attachment_ids:
@@ -514,7 +547,6 @@ class mail_message(osv.Model):
             fol_objs = fol_obj.browse(cr, uid, fol_ids, context=context)
             extra_notified = set(fol.partner_id.id for fol in fol_objs)
             missing_notified = extra_notified - partners_to_notify
-            missing_notified = missing_notified
             if missing_notified:
                 self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context)
 
@@ -523,7 +555,7 @@ class mail_message(osv.Model):
             Call mail_notification.notify to manage the email sending
         """
         message = self.browse(cr, uid, newid, context=context)
-        if message and message.model and message.res_id:
+        if message.model and message.res_id:
             self._notify_followers(cr, uid, newid, message, context=context)
 
         # add myself if I wrote on my wall, otherwise remove myself author
index 59ca333..4677bee 100644 (file)
@@ -56,8 +56,9 @@
                     <field name="subject" string="Content" filter_domain="['|', ('subject', 'ilike', self), ('body', 'ilike', self)]" />
                     <field name="type"/>
                     <field name="author_id"/>
+                    <field name="partner_ids"/>
                     <filter string="Unread"
-                            name="messages_unread" help="Show messages to read"
+                            name="message_unread" help="Show messages to read"
                             domain="[('to_read', '=', True)]"/>
                     <filter string="Comments"
                             name="comments" help="Comments"
         <!-- Add menu entry in Settings/Email -->
         <menuitem name="Messages" id="menu_mail_message" parent="base.menu_email" action="action_view_mail_message"/>
 
-        <record id="action_mail_inbox_feeds" model="ir.actions.client">
-            <field name="name">Inbox</field>
-            <field name="tag">mail.wall</field>
-            <field name="params" eval="&quot;{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]), ('to_read', '=', True)],
-                'context': {'default_model': 'res.users', 'default_res_id': uid} }&quot;"/>
-        </record>
-
-        <record id="action_mail_archives_feeds" model="ir.actions.client">
-            <field name="name">Archives</field>
-            <field name="tag">mail.wall</field>
-            <field name="params" eval="&quot;{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]), ('to_read', '=', False)],
-                'context': {'default_model': 'res.users', 'default_res_id': uid} }&quot;"/>
-        </record>
-
-        <record id="action_mail_sent_feeds" model="ir.actions.client">
-            <field name="name">Sent</field>
-            <field name="tag">mail.wall</field>
-            <field name="params" eval="&quot;{'domain': [('author_id.user_ids', 'in', [uid])],
-                'context': {'default_model': 'res.users', 'default_res_id': uid} }&quot;"/>
-        </record>
     </data>
-</openerp>
+</openerp>
\ No newline at end of file
index 7c92e91..04da686 100644 (file)
@@ -703,12 +703,12 @@ class mail_thread(osv.AbstractModel):
         if attachments:
             ir_attachment = self.pool.get('ir.attachment')
             mail_message = self.pool.get('mail.message')
-            attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [('res_model', '=', False), ('res_id', '=', False), ('user_id', '=', uid), ('id', 'in', attachments)], context=context)
+            attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [('res_model', '=', 'mail.message'), ('res_id', '=', 0), ('create_uid', '=', uid), ('id', 'in', attachments)], context=context)
             if attachment_ids:
                 ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context)
                 mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}, context=context)
-        new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id], context=context)
 
+        new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id], context=context)
         return new_message
 
     #------------------------------------------------------
@@ -716,7 +716,7 @@ class mail_thread(osv.AbstractModel):
     #------------------------------------------------------
 
     def message_get_subscription_data(self, cr, uid, ids, context=None):
-        """ Wrapper to get subtypes. """
+        """ Wrapper to get subtypes data. """
         return self._get_subscription_data(cr, uid, ids, None, None, context=context)
 
     def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, context=None):
index 696edde..5ef5e14 100644 (file)
@@ -1,35 +1,82 @@
 <?xml version="1.0"?>
 <openerp>
     <data>
+        <record id="action_mail_inbox_feeds" model="ir.actions.client">
+            <field name="name">Inbox</field>
+            <field name="tag">mail.wall</field>
+            <field name="params" eval="&quot;{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]), ('to_read', '=', True)],
+                'context': {'default_model': 'res.users', 'default_res_id': uid, 'typeof_thread': 'inbox'} }&quot;"/>
+        </record>
+
+        <record id="action_mail_to_me_feeds" model="ir.actions.client">
+            <field name="name">To: me</field>
+            <field name="tag">mail.wall</field>
+            <field name="params" eval="&quot;{'domain': [('partner_ids.user_ids', 'in', [uid]), ('to_read', '=', True), ('author_id.user_ids', 'in', [uid])],
+                'context': {'default_model': 'res.users', 'default_res_id': uid, 'typeof_thread': 'inbox'} }&quot;"/>
+        </record>
+
+        <record id="action_mail_star_feeds" model="ir.actions.client">
+            <field name="name">Favorites</field>
+            <field name="tag">mail.wall</field>
+            <field name="params" eval="&quot;{'domain': [('favorite_user_ids.user_ids', 'in', [uid])],
+                'context': {'default_model': 'res.users', 'default_res_id': uid, 'typeof_thread': 'stared'} }&quot;"/>
+        </record>
+
+        <record id="action_mail_archives_feeds" model="ir.actions.client">
+            <field name="name">Archives</field>
+            <field name="tag">mail.wall</field>
+            <field name="params" eval="&quot;{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]), ('to_read', '=', False)],
+                'context': {'default_model': 'res.users', 'default_res_id': uid, 'typeof_thread': 'archives'} }&quot;"/>
+        </record>
+
+        <record id="action_mail_sent_feeds" model="ir.actions.client">
+            <field name="name">Sent</field>
+            <field name="tag">mail.wall</field>
+            <field name="params" eval="&quot;{'domain': [('author_id.user_ids', 'in', [uid])],
+                'context': {'default_model': 'res.users', 'default_res_id': uid, 'typeof_thread': 'send'} }&quot;"/>
+        </record>
+
+        <!-- MENU -->
 
         <!-- Top menu item -->
-        <menuitem name="Home"
-          id="mail_feeds_main"
+        <menuitem name="Mails"
+          id="mail.mail_feeds_main"
           groups="base.group_user"
           sequence="10"/>
 
         <!-- Left-side menu: Feeds -->
-        <menuitem id="mail_feeds" name="Feeds" parent="mail.mail_feeds_main" groups="base.group_user" sequence="10"/>
+        <menuitem id="mail.mail_feeds" name="Feeds &amp; Mailbox" parent="mail.mail_feeds_main" groups="base.group_user" sequence="10"/>
         <menuitem id="mail_my_stuff" name="Organizer" parent="mail.mail_feeds_main"/>
 
         <record id="mail_inboxfeeds" model="ir.ui.menu">
           <field name="name">Inbox</field>
           <field name="sequence" eval="10"/>
           <field name="action" ref="action_mail_inbox_feeds"/>
-          <field name="parent_id" ref="mail_feeds"/>
+          <field name="parent_id" ref="mail.mail_feeds"/>
+        </record>
+        <record id="mail_tomefeeds" model="ir.ui.menu">
+          <field name="name">To: me</field>
+          <field name="sequence" eval="11"/>
+          <field name="action" ref="action_mail_to_me_feeds"/>
+          <field name="parent_id" ref="mail.mail_feeds"/>
+        </record>
+        <record id="mail_starfeeds" model="ir.ui.menu">
+          <field name="name">Favorites</field>
+          <field name="sequence" eval="14"/>
+          <field name="action" ref="action_mail_star_feeds"/>
+          <field name="parent_id" ref="mail.mail_feeds"/>
         </record>
         <record id="mail_archivesfeeds" model="ir.ui.menu">
           <field name="name">Archives</field>
-          <field name="sequence" eval="12"/>
+          <field name="sequence" eval="16"/>
           <field name="action" ref="action_mail_archives_feeds"/>
-          <field name="parent_id" ref="mail_feeds"/>
+          <field name="parent_id" ref="mail.mail_feeds"/>
         </record>
         <record id="mail_sentfeeds" model="ir.ui.menu">
           <field name="name">Sent</field>
-          <field name="sequence" eval="13"/>
+          <field name="sequence" eval="18"/>
           <field name="action" ref="action_mail_sent_feeds"/>
-          <field name="parent_id" ref="mail_feeds"/>
+          <field name="parent_id" ref="mail.mail_feeds"/>
         </record>
-
     </data>
-</openerp>
+</openerp>
\ No newline at end of file
index c318538..54b8a76 100644 (file)
@@ -126,6 +126,19 @@ class res_users(osv.Model):
         return self.pool.get('res.partner').message_post_api(cr, uid, partner_id, body=body, subject=subject,
             type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, **kwargs)
 
+    def message_post(self, cr, uid, thread_id, context=None, **kwargs):
+        """ Redirect the posting of message on res.users to the related partner.
+            This is done because when giving the context of Chatter on the
+            various mailboxes, we do not have access to the current partner_id.
+            We therefore post on the user and redirect on its partner. """
+        assert thread_id, "res.users does not support posting global messages"
+        if context and 'thread_model' in context:
+            context['thread_model'] = 'res.partner'
+        if isinstance(thread_id, (list, tuple)):
+            thread_id = thread_id[0]
+        partner_id = self.pool.get('res.users').read(cr, uid, thread_id, ['partner_id'], context=context)['partner_id'][0]
+        return self.pool.get('res.partner').message_post(cr, uid, partner_id, context=context, **kwargs)
+
     def message_update(self, cr, uid, ids, msg_dict, update_vals=None, context=None):
         partner_id = self.pool.get('res.users').browse(cr, uid, ids)[0].partner_id.id
         return self.pool.get('res.partner').message_update(cr, uid, [partner_id], msg_dict,
index 53083a5..3f2b7bf 100644 (file)
@@ -11,7 +11,7 @@
         </record>
 
         <record id="mail_followers_read_own" model="ir.rule">
-            <field name="name">mail.followers: read its own entries</field>
+            <field name="name">mail.followers: read and write its own entries</field>
             <field name="model_id" ref="model_mail_followers"/>
             <field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
             <field name="perm_create" eval="False"/>
index 0f1f90d..50ce0e0 100644 (file)
 /* Specific display of threads in the wall */
 /* ------------------------------------------------------------ */
 
-.openerp ul.oe_mail_wall_threads .oe_mail_msg_content textarea.oe_mail_compose_textarea {
+.openerp ul.oe_mail_wall_threads .oe_msg_content textarea.oe_mail_compose_textarea {
     width: 434px;
     height: 30px;
     padding: 4px;
 }
 
-.openerp li.oe_mail_wall_thread:first .oe_mail_msg_notification {
+.openerp li.oe_mail_wall_thread:first .oe_msg_notification {
     border-top: 0;
 }
 
@@ -69,7 +69,7 @@
     height: 28px;
 }
 
-.openerp div.oe_thread_placeholder div.oe_mail_msg_content {
+.openerp div.oe_thread_placeholder div.oe_msg_content {
     width: 440px;
 }
 
 }
 
 /* default textarea (oe_mail_compose_textarea), and body textarea for compose form view */
-.openerp .oe_mail_msg_content textarea.oe_mail_compose_textarea:focus,
-.openerp .oe_mail_msg_content div.oe_mail_compose_message_body textarea:focus {
+.openerp .oe_msg_content textarea.oe_mail_compose_textarea:focus,
+.openerp .oe_msg_content div.oe_mail_compose_message_body textarea:focus {
     outline: 0;
     border-color: rgba(82, 168, 236, 0.8);
     -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
 }
 
 .openerp .oe_mail_vote_count,
-.openerp .oe_mail_msg_vote{
+.openerp .oe_msg_vote{
     vertical-align: bottom;
 }
 
+.openerp button.oe_mail_starbox{
+    background: #ff0000;
+}
+.openerp button.oe_mail_starbox.oe_stared{
+    background: #00FF00;
+}
+
 .openerp div.oe_mail_thread_display {
     white-space: normal;
 }
     margin: 0 0 4px 0;
 }
 
-.openerp .oe_mail_msg_notification,
-.openerp .oe_mail_msg_expandable,
-.openerp .oe_mail_msg_comment,
-.openerp .oe_mail_msg_email {
+.openerp .oe_msg_notification,
+.openerp .oe_msg_expandable,
+.openerp .oe_msg_comment,
+.openerp .oe_msg_email {
     padding: 8px;
     background: white;
     position: relative;
 }
 
-.openerp .oe_mail_msg_notification:after, 
-.openerp .oe_mail_msg_comment:after, 
-.openerp .oe_mail_msg_email:after {
+.openerp .oe_msg_notification:after, 
+.openerp .oe_msg_comment:after, 
+.openerp .oe_msg_email:after {
     content: "";
     display: block;
     clear: both; 
 }
 
-.openerp div.oe_mail_msg_content {
+.openerp div.oe_msg_content {
     float: left;
     position: relative;
     width: 486px;
 }
 
-.openerp div.oe_mail_msg_content > li {
+.openerp div.oe_msg_content > li {
     float: left;
     margin-right: 3px;
 }
 
-.openerp .oe_mail_msg_content:after {
+.openerp .oe_msg_content:after {
     content: "";
     display: block;
     clear: both; 
 /* Messages layout
 /* ------------------------------------------------------------ */
 
-.openerp .oe_mail_msg .oe_mail_msg_title {
+.openerp .oe_mail_msg .oe_msg_title {
     margin: 0;
     font-size: 1.3em;
     font-weight: bold;
 }
-.openerp .oe_mail_msg .oe_mail_msg_title a:link,
-.openerp .oe_mail_msg .oe_mail_msg_title a:visited {
+.openerp .oe_mail_msg .oe_msg_title a:link,
+.openerp .oe_mail_msg .oe_msg_title a:visited {
     color: #4C4C4C;
     text-decoration: none;
 }
 
-.openerp .oe_mail_msg .oe_mail_msg_body {
+.openerp .oe_mail_msg .oe_msg_body {
     margin-bottom: .5em;
     text-align: justify;
 }
 
-.openerp .oe_mail_msg .oe_mail_msg_body pre {
+.openerp .oe_mail_msg .oe_msg_body pre {
     font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif;
     margin: 0px;
     white-space: pre-wrap;
 }
 
 /* Message footer */
-.openerp .oe_mail_msg .oe_mail_msg_footer {
+.openerp .oe_mail_msg .oe_msg_footer {
     color: #888;
 }
-.openerp .oe_mail_msg .oe_mail_msg_footer li {
+.openerp .oe_mail_msg .oe_msg_footer li {
     float: left;
     margin-right: 3px;
 }
-.openerp .oe_mail_msg .oe_mail_msg_footer li:after {
+.openerp .oe_mail_msg .oe_msg_footer li:after {
     content: " · ";
 }
-.openerp .oe_mail_msg .oe_mail_msg_footer li:last-child:after {
+.openerp .oe_mail_msg .oe_msg_footer li:last-child:after {
     content: "";
 }
 
 /* Attachments list */
-.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments {
+.openerp .oe_msg_content ul.oe_msg_attachments {
     width: 100%;
     margin: .5em 0 0 0;
     padding: .5em 0;
     list-style-position: inside;
 }
-.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments.oe_hidden {
+.openerp .oe_msg_content ul.oe_msg_attachments.oe_hidden {
     display: none;
 }
-.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments li {
+.openerp .oe_msg_content ul.oe_msg_attachments li {
     float: none;
     height: 20px;
     line-height: 20px;
     padding: 0;
     list-style-type: square;
 }
-.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments .oe_upload_in_process {
+.openerp .oe_msg_content ul.oe_msg_attachments .oe_upload_in_process {
     float: right;
     width: 200px;
     height: 16px;
 }
-.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments .oe_upload_in_process div {
+.openerp .oe_msg_content ul.oe_msg_attachments .oe_upload_in_process div {
     float: left;
     width: 38px;
     height: 16px;
     margin-right: 2px;
     background: #66FF66;
 }
-.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments .oe_upload_in_process span {
+.openerp .oe_msg_content ul.oe_msg_attachments .oe_upload_in_process span {
     color: #aaaaaa;
     position: absolute;
 }
 
+/* ------------------------------------------------------------ */
+/* Topbar button
+/* ------------------------------------------------------------ */
+
+.openerp .oe_topbar .oe_topbar_compose_full_email {
+    float: right;
+    margin: 3px 25px 0 0;
+}
\ No newline at end of file
index e2f136e..c706c55 100644 (file)
@@ -2,11 +2,11 @@
 /* Compose Message */
 /* ------------------------------ */
 
-.openerp .oe_mail_msg_content .oe_mail_compose_message_footer {
+.openerp .oe_msg_content .oe_mail_compose_message_footer {
     height: 24px;
 }
 
-.openerp .oe_mail_msg_content .oe_mail_compose_message_footer button.oe_mail_compose_message_button_send {
+.openerp .oe_msg_content .oe_mail_compose_message_footer button.oe_mail_compose_message_button_send {
     float: left;
 }
 
@@ -98,7 +98,7 @@
     font-size: 30px;
 }
 
-.openerp .oe_mail .oe_mail_msg_attachments input {
+.openerp .oe_mail .oe_msg_attachments input {
     visibility: hidden;
 }
 
 }
 
 /* form_view: delete white background */
-.openerp .oe_mail_msg_content div.oe_formview {
+.openerp .oe_msg_content div.oe_formview {
     background-color: transparent;
 }
 
-.openerp .oe_mail_msg_content div.oe_form_nosheet {
+.openerp .oe_msg_content div.oe_form_nosheet {
     margin: 0px;
 }
 
-.openerp .oe_mail_msg_content table.oe_form_group {
+.openerp .oe_msg_content table.oe_form_group {
     margin: 0px;
 }
 
-.openerp .oe_mail_msg_content table.oe_form_field,
-.openerp .oe_mail_msg_content div.oe_form_field {
+.openerp .oe_msg_content table.oe_form_field,
+.openerp .oe_msg_content div.oe_form_field {
     padding: 0px;
 }
 
-.openerp .oe_mail_msg_content td.oe_form_group_cell {
+.openerp .oe_msg_content td.oe_form_group_cell {
     vertical-align: bottom;
 }
 
 /* subject: change width */
-.openerp .oe_mail_msg_content .oe_form .oe_form_field input[type='text'] {
+.openerp .oe_msg_content .oe_form .oe_form_field input[type='text'] {
     width: 472px;
 }
 
 /* body_html: cleditor */
-.openerp .oe_mail_msg_content div.cleditorMain {
+.openerp .oe_msg_content div.cleditorMain {
     border: 1px solid #cccccc;
 }
 
 /* destination_partner_ids */
-.openerp .oe_mail_msg_content div.text-core {
+.openerp .oe_msg_content div.text-core {
     height: 22px !important;
     width: 472px;
 }
\ No newline at end of file
index b70e64d..7501eab 100644 (file)
@@ -12,37 +12,25 @@ openerp.mail = function(session) {
      * ------------------------------------------------------------
      * 
      * Override of formview do_action method, to catch all return action about
-     * mail.compose.message. The purpose is to bind 'Send by e-mail' buttons
-     * and redirect them to the Chatter.
+     * mail.compose.message. The purpose is to bind 'Send by e-mail' buttons.
      */
 
     session.web.FormView = session.web.FormView.extend({
         do_action: function(action) {
             if (action.res_model == 'mail.compose.message') {
-
                 /* hack for stop context propagation of wrong value
                  * delete this hack when a global method to clean context is create
-                */
-                for(var key in action.context){
-                    if( key!='default_template_id' &&
-                        key!='default_composition_mode' &&
-                        key!='default_use_template' &&
-                        key!='default_model' &&
-                        key!='default_res_id' &&
-                        key!='default_subtype' &&
-                        key!='active_id' &&
-                        key!='lang' &&
-                        key!='bin_raw' &&
-                        key!='tz' &&
-                        key!='active_model' &&
-                        key!='edi_web_url_view' &&
-                        key!='active_ids')
-                    action.context[key]=null;
-                };
+                 */
+                var context_keys = ['default_template_id', 'default_composition_mode', 
+                    'default_use_template', 'default_partner_ids', 'default_model',
+                    'default_res_id', 'default_content_subtype', 'active_id', 'lang',
+                    'bin_raw', 'tz', 'active_model', 'edi_web_url_view', 'active_ids']
+                for (var key in action.context) {
+                    if (_.indexOf(context_keys, key) == -1) {
+                        action.context[key] = null;
+                    }
+                }
                 /* end hack */
-
-                $('.openerp .oe_mail_wall_threads .oe_mail_thread button.oe_mail_wall_button_fetch').click();
-
             }
             return this._super.apply(this, arguments);
         },
@@ -92,6 +80,7 @@ openerp.mail = function(session) {
 
         /* replace textarea text into html text
          * (add <p>, <a>)
+         * TDE note : should not be here, but server-side I think ...
         */
         get_text2html: function(text){
             return text
@@ -124,26 +113,27 @@ openerp.mail = function(session) {
         init: function (parent, options) {
             var self = this;
             this._super(parent);
-            this.attachment_ids = [];
-
             this.context = options.context || {};
 
-            this.id =           options.parameters.id;
-            this.model =        options.parameters.model;
-            this.res_id =       options.parameters.res_id;
-            this.partner_ids =  options.parameters.partner_ids;
-            this.options={thread:{}};
-            this.options.thread.show_header_compose =  options.parameters.options.thread.show_header_compose;
-            this.options.thread.display_on_flat =  options.parameters.options.thread.display_on_flat;
-
-            this.attachment_ids = [];
+            this.datasets = {
+                'attachment_ids' : [],
+                'id': options.datasets.id,
+                'model': options.datasets.model,
+                'res_model': options.datasets.res_model,
+                'is_private': options.datasets.is_private || false,
+                'partner_ids': options.datasets.partner_ids || []
+            };
+            this.options={};
+            this.options.thread={};
+            this.options.thread.show_header_compose = options.options.thread.show_header_compose;
+            this.options.thread.display_on_thread = options.options.thread.display_on_thread;
             this.options.thread.show_attachment_delete = true;
             this.options.thread.show_attachment_link = true;
 
             this.parent_thread= parent.messages!= undefined ? parent : false;
 
-
             this.ds_attachment = new session.web.DataSetSearch(this, 'ir.attachment');
+
             this.fileupload_id = _.uniqueId('oe_fileupload_temp');
             $(window).on(self.fileupload_id, self.on_attachment_loaded);
         },
@@ -167,7 +157,7 @@ openerp.mail = function(session) {
             } else {
                 this.list_attachment.replaceWith( render );
             }
-            this.list_attachment = this.$("ul.oe_mail_msg_attachments");
+            this.list_attachment = this.$("ul.oe_msg_attachments");
 
             // event: delete an attachment
             this.$el.on('click', '.oe_mail_attachment_delete', self.on_attachment_delete);
@@ -182,26 +172,25 @@ openerp.mail = function(session) {
 
                 // if the files exits for this answer, delete the file before upload
                 var attachments=[];
-                for(var i in this.attachment_ids){
-                    if((this.attachment_ids[i].filename || this.attachment_ids[i].name) == filename){
-                        if(this.attachment_ids[i].upload){
+                for(var i in this.datasets.attachment_ids){
+                    if((this.datasets.attachment_ids[i].filename || this.datasets.attachment_ids[i].name) == filename){
+                        if(this.datasets.attachment_ids[i].upload){
                             return false;
                         }
-                        this.ds_attachment.unlink([this.attachment_ids[i].id]);
+                        this.ds_attachment.unlink([this.datasets.attachment_ids[i].id]);
                     } else {
-                        attachments.push(this.attachment_ids[i]);
+                        attachments.push(this.datasets.attachment_ids[i]);
                     }
                 }
-                this.attachment_ids = attachments;
+                this.datasets.attachment_ids = attachments;
 
                 // submit file
                 //session.web.blockUI();
                 self.$('form.oe_form_binary_form').submit();
-                //self.submit_ajax_attachment();
 
                 this.$(".oe_attachment_file").hide();
 
-                this.attachment_ids.push({
+                this.datasets.attachment_ids.push({
                     'id': 0,
                     'name': filename,
                     'filename': filename,
@@ -212,57 +201,11 @@ openerp.mail = function(session) {
             }
         },
         
-        submit_ajax_attachment: function(){
-            var self=this;
-            var $form = self.$('form.oe_form_binary_form');
-            var filename = this.$('input.oe_form_binary_file').val().replace(/.*[\\\/]/,'');
-
-            // create form data
-            var fomdata = new FormData();
-            $.each($form.find('input'), function(i, field) {
-                var $field=$(field);
-                if($field.attr('type')!='file'){
-                    fomdata.append($field.attr('name'), $field.val());
-                } else {
-                    fomdata.append($field.attr('name'), field.files[0]);
-                }
-            });
-
-            var progress=function(event) {
-                self.$("span[name='"+filename+"'] div:lt("+Math.floor(event.loaded / event.total*5)+")").show();
-            };
-
-            $.ajax({
-                url: $form.attr("action"),
-                data: fomdata,
-                cache: false,
-                contentType: false,
-                processData: false,
-                type: 'POST',
-                enctype: 'multipart/form-data',
-                xhr: function() {
-                    // custom xhr
-                    myXhr = $.ajaxSettings.xhr();
-                    if(myXhr.upload){
-                        // for handling the progress of the upload
-                        myXhr.upload.addEventListener('progress', progress, false);
-                    }
-                    myXhr.addEventListener('progress', progress, false);
-                    return myXhr;
-                },
-                success: function(data){
-                    $iframe=$('<iframe style="display:none;"/>').html(data);
-                    $iframe.appendTo(self.$el);
-                    $iframe.remove();
-                }
-            });
-        },
-        
         on_attachment_loaded: function (event, result) {
             //session.web.unblockUI();
-            for(var i in this.attachment_ids){
-                if(this.attachment_ids[i].filename == result.filename && this.attachment_ids[i].upload){
-                    this.attachment_ids[i]={
+            for(var i in this.datasets.attachment_ids){
+                if(this.datasets.attachment_ids[i].filename == result.filename && this.datasets.attachment_ids[i].upload) {
+                    this.datasets.attachment_ids[i]={
                         'id': result.id,
                         'name': result.name,
                         'filename': result.filename,
@@ -283,15 +226,15 @@ openerp.mail = function(session) {
             var attachment_id=$(event.target).data("id");
             if (attachment_id) {
                 var attachments=[];
-                for(var i in this.attachment_ids){
-                    if(attachment_id!=this.attachment_ids[i].id){
-                        attachments.push(this.attachment_ids[i]);
+                for(var i in this.datasets.attachment_ids){
+                    if(attachment_id!=this.datasets.attachment_ids[i].id){
+                        attachments.push(this.datasets.attachment_ids[i]);
                     }
                     else {
                         this.ds_attachment.unlink([attachment_id]);
                     }
                 }
-                this.attachment_ids = attachments;
+                this.datasets.attachment_ids = attachments;
                 this.display_attachments();
             }
         },
@@ -328,8 +271,16 @@ openerp.mail = function(session) {
 
         on_compose_fullmail: function(){
             var attachments=[];
-            for(var i in this.attachment_ids){
-                attachments.push(this.attachment_ids[i].id);
+            for(var i in this.datasets.attachment_ids){
+                attachments.push(this.datasets.attachment_ids[i].id);
+            }
+            /* TDE note: I think this is not necessary, because
+             * 1/ post on a document: followers added server-side in _notify
+             * 2/ reply to a message: mail.compose.message should add the previous partners
+             */
+            var partner_ids=[];
+            for(var i in this.datasets.partner_ids){
+                partner_ids.push(this.datasets.partner_ids[i][0]);
             }
             var action = {
                 type: 'ir.actions.act_window',
@@ -340,30 +291,32 @@ openerp.mail = function(session) {
                 views: [[false, 'form']],
                 target: 'new',
                 context: {
-                    'default_model': false,
-                    'default_res_id': 0,
+                    'default_model': this.context.default_model,
+                    'default_res_id': this.context.default_res_id,
                     'default_content_subtype': 'html',
-                    'default_parent_id': this.id,
+                    'default_parent_id': this.context.default_parent_id,
                     'default_body': mail.ChatterUtils.get_text2html(this.$('textarea').val() || ''),
                     'default_attachment_ids': attachments,
+                    'default_partner_ids': partner_ids
                 },
             };
             this.do_action(action);
         },
 
-        on_cancel: function(){
-            event.stopPropagation();
+        on_cancel: function(event){
+            if(event) event.stopPropagation();
             this.$('textarea').val("");
             this.$('input[data-id]').remove();
             //this.attachment_ids=[];
             this.display_attachments();
-            if(!this.options.thread.show_header_compose || !this.options.thread.display_on_flat){
+            if(!this.options.thread.show_header_compose || !this.options.thread.display_on_thread[0]){
                 this.$el.hide();
             }
         },
 
         /*post a message and fetch the message*/
         on_message_post: function (body) {
+            var self = this;
 
             if (! body) {
                 var comment_node = this.$('textarea');
@@ -372,12 +325,12 @@ openerp.mail = function(session) {
             }
 
             var attachments=[];
-            for(var i in this.attachment_ids){
-                if(this.attachment_ids[i].upload){
+            for(var i in this.datasets.attachment_ids){
+                if(this.datasets.attachment_ids[i].upload){
                     session.web.dialog($('<div>' + session.web.qweb.render('CrashManager.warning', {message: 'Please, wait while the file is uploading.'}) + '</div>'));
                     return false;
                 }
-                attachments.push(this.attachment_ids[i].id);
+                attachments.push(this.datasets.attachment_ids[i].id);
             }
 
             if(body.match(/\S+/)) {
@@ -386,12 +339,15 @@ openerp.mail = function(session) {
                         mail.ChatterUtils.get_text2html(body), 
                         false, 
                         'comment', 
-                        'mail.mt_comment',, 
+                        'mail.mt_comment',
                         this.context.default_parent_id, 
-                        attachments]
-                    ).then(this.parent_thread.proxy('switch_new_message'));
-                this.attachment_ids=[];
-                this.on_cancel();
+                        attachments,
+                        this.parent_thread.context
+                    ]).then(function(records){
+                        self.parent_thread.switch_new_message(records);
+                        self.datasets.attachment_ids=[];
+                        self.on_cancel();
+                    });
                 return true;
             }
         },
@@ -418,13 +374,18 @@ openerp.mail = function(session) {
             this.domain = options.domain || [];
             this.context = _.extend({
                 default_model: 'mail.thread',
-                default_res_id:  0,
+                default_res_id: 0,
                 default_parent_id: false }, options.context || {});
 
-            this.id =           options.parameters.id || -1;
-            this.parent_id=     options.parameters.parent_id || false;
-            this.nb_messages =  options.parameters.nb_messages || 0;
-            this.type =         'expandable';
+            this.datasets = {
+                'id' : options.datasets.id || -1,
+                'model' : options.datasets.model || false,
+                'parent_id' : options.datasets.parent_id || false,
+                'nb_messages' : options.datasets.nb_messages || 0,
+                'type' : 'expandable',
+                'max_limit' : options.datasets.max_limit || false,
+                'flag_used' : false,
+            };
 
             // record options and data
             this.parent_thread= parent.messages!= undefined ? parent : options.options.thread._parents[0] ;
@@ -441,17 +402,33 @@ openerp.mail = function(session) {
          * in the function. */
         bind_events: function() {
             var self = this;
-            // event: click on 'Vote' button
             this.$el.on('click', 'a.oe_mail_fetch_more', self.on_expandable);
         },
 
+        animated_destroy: function(options) {
+            var self=this;
+            //graphic effects
+            if(options && options.fadeTime) {
+                self.$el.fadeOut(options.fadeTime, function(){
+                    self.destroy();
+                });
+            } else {
+                self.destroy();
+            }
+        },
+
         /*The selected thread and all childs (messages/thread) became read
         * @param {object} mouse envent
         */
         on_expandable: function (event) {
             if(event)event.stopPropagation();
+            if(this.datasets.flag_used) {
+                return false
+            }
+            this.datasets.flag_used = true;
+
+            this.animated_destroy({'fadeTime':300});
             this.parent_thread.message_fetch(false, this.domain, this.context);
-            this.destroy();
             return false;
         },
     });
@@ -494,80 +471,92 @@ openerp.mail = function(session) {
          *              will not be truncated if it does not have 110% of the parameter
          *          @param {Boolean} [show_record_name]
          *          @param {Boolean} [show_dd_delete]
-         *          @param {Boolean} [show_dd_hide]
+         *          @param {Array [A,B]} [show_reply] display the reply button on the
+         *              message for thread level between A and B. -1 for no begin or no end.
+         *          @param {Array [A,B]} [show_read_unread] display the read/unread button on the
+         *              message for thread level between A and B. -1 for no begin or no end.
          */
         init: function(parent, options) {
             this._super(parent);
 
-            // record parameters
-            var param =         options.parameters;
-            for(var i in param){
-                this[i] = param[i];
-            }
-            this.id =           param.id || -1;
-            this.model =        param.model || false;
-            this.parent_id=     param.parent_id || false;
-            this.res_id =       param.res_id || false;
-            this.type =         param.type || false;
-            this.is_author =    param.is_author || false;
-            this.subject =      param.subject || false;
-            this.name =         param.name || false;
-            this.record_name =  param.record_name || false;
-            this.body =         param.body || false;
-            this.vote_user_ids =param.vote_user_ids || [];
-            this.has_voted =    param.has_voted || false;
-
-            this.vote_user_ids = param.vote_user_ids || [];
-
-            this.to_read =      param.to_read || false;
-            this._date =        param.date;
-            this.author_id =    param.author_id || [];
-            this.attachment_ids = param.attachment_ids || [];
+            // record datasets
+            var param = options.datasets;
+            this.datasets = _.extend({
+                'id' : -1,
+                'model' : false,
+                'parent_id': false,
+                'res_id' : false,
+                'type' : false,
+                'is_author' : false,
+                'is_private' : false,
+                'subject' : false,
+                'name' : false,
+                'record_name' : false,
+                'body' : false,
+                'vote_user_ids' :[],
+                'has_voted' : false,
+                'is_favorite' : false,
+                'thread_level' : 0,
+                'to_read' : true,
+                'author_id' : [],
+                'attachment_ids' : [],
+            }, param || {});
+            this.datasets._date = param.date;
 
             // record domain and context
             this.domain = options.domain || [];
             this.context = _.extend({
                 default_model: 'mail.thread',
-                default_res_id:  0,
+                default_res_id: 0,
                 default_parent_id: false }, options.context || {});
 
             // record options
             this.options={
                 'thread' : options.options.thread,
                 'message' : {
-                    'message_ids':            options.options.message.message_ids || null,
-                    'message_data':           options.options.message.message_data || null,
-                    'show_record_name':       options.options.message.show_record_name != undefined ? options.options.message.show_record_name: true,
-                    'show_dd_delete':         options.options.message.show_dd_delete || false,
-                    'show_dd_hide':           options.options.message.show_dd_hide || false,
-                    'truncate_limit':         options.options.message.truncate_limit || 250,
+                    'message_ids': options.options.message.message_ids || null,
+                    'message_data': options.options.message.message_data || null,
+                    'show_record_name': options.options.message.show_record_name != undefined ? options.options.message.show_record_name: true,
+                    'show_dd_delete': options.options.message.show_dd_delete || false,
+                    'truncate_limit': options.options.message.truncate_limit || 250,
+                    'show_reply': options.options.message.show_reply || [0,-1],
+                    'show_read_unread': options.options.message.show_read_unread || [0,-1],
                 }
             };
 
+            this.datasets.show_reply = this.options.message.show_reply[0]>=0 && 
+                this.options.message.show_reply[0]<=this.datasets.thread_level &&
+                (this.options.message.show_reply[1]<0 || this.options.message.show_reply[1]>=this.datasets.thread_level);
+
+            this.datasets.show_read_unread = this.options.message.show_read_unread[0]>=0 && 
+                this.options.message.show_read_unread[0]<=this.datasets.thread_level &&
+                (this.options.message.show_read_unread[1]<0 || this.options.message.show_read_unread[1]>=this.datasets.thread_level);
+
             // record options and data
             this.parent_thread= parent.messages!= undefined ? parent : options.options.thread._parents[0];
             this.thread = false;
 
-            if( param.id > 0 ) {
+            if( this.datasets.id > 0 ) {
                 this.formating_data();
             }
 
             this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification');
             this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
+            this.ds_follow = new session.web.DataSetSearch(this, 'mail.followers');
         },
 
         formating_data: function(){
 
             //formating and add some fields for render
-            this.date = session.web.format_value(this._date, {type:"datetime"});
-            this.timerelative = $.timeago(this.date);
-            if (this.type == 'email') {
-                this.avatar = ('/mail/static/src/img/email_icon.png');
+            this.datasets.date = session.web.format_value(this.datasets._date, {type:"datetime"});
+            this.datasets.timerelative = $.timeago(this.datasets.date);
+            if (this.datasets.type == 'email') {
+                this.datasets.avatar = ('/mail/static/src/img/email_icon.png');
             } else {
-                this.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.author_id[0]);
+                this.datasets.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.datasets.author_id[0]);
             }
-            for (var l in this.attachment_ids) {
-                var attach = this.attachment_ids[l];
+            for (var l in this.datasets.attachment_ids) {
+                var attach = this.datasets.attachment_ids[l];
                 attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach);
             }
         },
@@ -587,20 +576,22 @@ openerp.mail = function(session) {
             var self = this;
 
             // event: click on 'Attachment(s)' in msg
-            this.$('a.oe_mail_msg_view_attachments:first').on('click', function (event) {
-                self.$('.oe_mail_msg_attachments:first').toggle();
+            this.$('a.oe_msg_view_attachments:first').on('click', function (event) {
+                self.$('.oe_msg_attachments:first').toggle();
             });
             // event: click on icone 'Read' in header
             this.$el.on('click', 'a.oe_read', this.on_message_read_unread);
             // event: click on icone 'UnRead' in header
             this.$el.on('click', 'a.oe_unread', this.on_message_read_unread);
             // event: click on 'Delete' in msg side menu
-            this.$el.on('click', 'a.oe_mail_msg_delete', this.on_message_delete);
+            this.$el.on('click', 'a.oe_msg_delete', this.on_message_delete);
 
             // event: click on 'Reply' in msg
             this.$el.on('click', 'a.oe_reply', this.on_message_reply);
             // event: click on 'Vote' button
-            this.$el.on('click', 'button.oe_mail_msg_vote', this.on_vote);
+            this.$el.on('click', 'button.oe_msg_vote', this.on_vote);
+            // event: click on 'Star' button
+            this.$el.on('click', 'button.oe_mail_starbox', this.on_star);
         },
 
         on_message_reply:function(event){
@@ -610,11 +601,11 @@ openerp.mail = function(session) {
         },
 
         expender: function(){
-            this.$('div.oe_mail_msg_body:first').expander({
+            this.$('div.oe_msg_body:first').expander({
                 slicePoint: this.options.truncate_limit,
                 expandText: 'read more',
                 userCollapseText: '[^]',
-                detailClass: 'oe_mail_msg_tail',
+                detailClass: 'oe_msg_tail',
                 moreClass: 'oe_mail_expand',
                 lessClass: 'oe_mail_reduce',
                 });
@@ -625,20 +616,20 @@ openerp.mail = function(session) {
             if(this.thread){
                 return false;
             }
-            var param = _.extend(self, {'parent_id': self.id});
+
             /*create thread*/
             self.thread = new mail.Thread(self, {
                     'domain': self.domain,
                     'context':{
-                        'default_model': self.model,
-                        'default_res_id': self.res_id,
-                        'default_parent_id': self.id
+                        'default_model': self.datasets.model,
+                        'default_res_id': self.datasets.res_id,
+                        'default_parent_id': self.datasets.id
                     },
                     'options': {
-                        'thread' :  self.options.thread,
+                        'thread' : self.options.thread,
                         'message' : self.options.message
                     },
-                    'parameters': param
+                    'datasets': self.datasets
                 }
             );
             /*insert thread in parent message*/
@@ -663,7 +654,7 @@ openerp.mail = function(session) {
             
             this.animated_destroy({fadeTime:250});
             // delete this message and his childs
-            var ids = [this.id].concat( this.get_child_ids() );
+            var ids = [this.datasets.id].concat( this.get_child_ids() );
             this.ds_message.unlink(ids);
             this.animated_destroy();
             return false;
@@ -673,18 +664,20 @@ openerp.mail = function(session) {
         * @param {object} mouse envent
         */
         on_message_read_unread: function (event) {
+            // TDE note: code here seems complicated... just check that current message is read (value coming from server)
+            // and send its opposite to set_message_read
             event.stopPropagation();
-            if($(event.srcElement).hasClass("oe_read")) this.animated_destroy({fadeTime:250});
             // if this message is read, all childs message display is read
-            var ids = [this.id].concat( this.get_child_ids() );
-            
-            if($(event.srcElement).hasClass("oe_read")) {
-                this.ds_notification.call('set_message_read', [ids, true]);
-                this.$el.removeClass("oe_mail_unread").addClass("oe_mail_read");
-            } else {
-                this.ds_notification.call('set_message_read', [ids, false]);
-                this.$el.removeClass("oe_mail_read").addClass("oe_mail_unread");
+            var ids = [this.datasets.id].concat( this.get_child_ids() );
+            var read = $(event.srcElement).hasClass("oe_read");
+            this.$el.removeClass("oe_mail_" + (read?"un":"") + "read").addClass("oe_mail_" + (read?"":"un") + "read");
+
+            if( (read && this.options.thread.typeof_thread == 'inbox') ||
+                (!read && this.options.thread.typeof_thread == 'archives')) {
+                this.animated_destroy({fadeTime:250});
             }
+            // TDE note: should have a context here
+            this.ds_notification.call('set_message_read', [ids, read]);
             return false;
         },
 
@@ -705,7 +698,7 @@ openerp.mail = function(session) {
                 }
             }
 
-            if(this.id==options.id)
+            if(this.datasets.id==options.id)
                 return this;
 
             for(var i in this.thread.messages){
@@ -722,30 +715,29 @@ openerp.mail = function(session) {
         */
         get_child_ids: function(){
             var res=[]
-            if(arguments[0]) res.push(this.id);
+            if(arguments[0]) res.push(this.datasets.id);
             if(this.thread){
                 res = res.concat( this.thread.get_child_ids(true) );
             }
             return res;
         },
 
-
         on_vote: function (event) {
             event.stopPropagation();
             var self=this;
-            return this.ds_message.call('vote_toggle', [[self.id]]).pipe(function(vote){
-
-                self.has_voted=vote;
-                if (!self.has_voted) {
+            return this.ds_message.call('vote_toggle', [[self.datasets.id]]).pipe(function(vote){
+                // TDE note: to update, because vote_user_ids is about to disappear to be replaced by vote_nb (number of votes)
+                self.datasets.has_voted=vote;
+                if (!self.datasets.has_voted) {
                     var votes=[];
-                    for(var i in self.vote_user_ids){
-                        if(self.vote_user_ids[i][0]!=self.session.uid)
-                            vote.push(self.vote_user_ids[i]);
+                    for(var i in self.datasets.vote_user_ids){
+                        if(self.datasets.vote_user_ids[i][0]!=self.datasets.session.uid)
+                            vote.push(self.datasets.vote_user_ids[i]);
                     }
-                    self.vote_user_ids=votes;
+                    self.datasets.vote_user_ids=votes;
                 }
                 else {
-                    self.vote_user_ids.push([self.session.uid, 'You']);
+                    self.datasets.vote_user_ids.push([self.session.uid, 'You']);
                 }
                 self.display_vote();
             });
@@ -759,6 +751,26 @@ openerp.mail = function(session) {
             self.$(".placeholder-mail-vote:first").empty();
             self.$(".placeholder-mail-vote:first").html(vote_element);
         },
+
+        // Stared/unstared + Render star.
+        on_star: function (event) {
+            event.stopPropagation();
+            var self=this;
+            var button = self.$('button.oe_mail_starbox:first');
+            return this.ds_message.call('favorite_toggle', [[self.datasets.id]]).pipe(function(star){
+                self.datasets.is_favorite=star;
+                if(self.datasets.is_favorite){
+                    button.addClass('oe_stared');
+                } else {
+                    button.removeClass('oe_stared');
+                    if( self.options.thread.typeof_thread == 'stared' ) {
+                        self.animated_destroy({fadeTime:250});
+                    }
+                }
+            });
+            return false;
+        },
+
     });
 
     /** 
@@ -793,8 +805,13 @@ openerp.mail = function(session) {
          *              for each click on "show more message"
          *          @param {Number} [expandable_default_number=5] number message show
          *              on begin before the first click on "show more message"
-         *          @param {Boolean} [display_on_flat] display all thread
-         *              on the wall thread level (no hierarchy)
+         *          @param {Array [A,B]} [display_on_thread] display the threads (hierarchy)
+         *              for the thread level between A and B. -1 for no begin or no end.
+         *              All thread before A are insert in the root thread.
+         *              All thread after B are insert in parent thread on B level.
+         *          @param {Select} [typeof_thread] inbox/archives/stared/sent
+         *              type of thread and option for user application like animate
+         *              destroy for read/unread
          *          @param {Array} [parents] liked with the parents thread
          *              use with browse, fetch... [O]= top parent
          */
@@ -803,62 +820,65 @@ openerp.mail = function(session) {
             this.domain = options.domain || [];
             this.context = _.extend({
                 default_model: 'mail.thread',
-                default_res_id:  0,
+                default_res_id: 0,
                 default_parent_id: false }, options.context || {});
 
             // options
             this.options={
                 'thread' : {
-                    'thread_level':         (options.options.thread.thread_level+1) || 0,
-                    'show_header_compose':  (options.options.thread.show_header_compose != undefined ? options.options.thread.show_header_compose: false),
-                    'use_composer':         options.options.thread.use_composer || false,
-                    'expandable_number':    options.options.thread.expandable_number || 5,
+                    'show_header_compose': (options.options.thread.show_header_compose != undefined ? options.options.thread.show_header_compose: false),
+                    'use_composer': options.options.thread.use_composer || false,
+                    'expandable_number': options.options.thread.expandable_number || 5,
                     'expandable_default_number': options.options.thread.expandable_default_number || 5,
-                    '_expandable_max':      options.options.thread.expandable_default_number || 5,
-                    'display_on_flat':      options.options.thread.display_on_flat || false,
-                    '_parents':             (options.options.thread._parents != undefined ? options.options.thread._parents : []).concat( [this] )
+                    '_expandable_max': options.options.thread.expandable_default_number || 5,
+                    'display_on_thread': options.options.thread.display_on_thread || [0,-1],
+                    'typeof_thread': options.options.thread.typeof_thread || 'inbox',
+                    '_parents': (options.options.thread._parents != undefined ? options.options.thread._parents : []).concat( [this] )
                 },
                 'message' : options.options.message
             };
 
             // record options and data
-            this.parent_linked_message= parent.thread!= undefined ? parent : false ;
+            this.parent_message= parent.thread!= undefined ? parent : false ;
 
-            var param = options.parameters
+            var param = options.datasets
             // datasets and internal vars
-            this.id=            param.id || false;
-            this.model=         param.model || false;
-            this.parent_id=     param.parent_id || false;
-            this.author_id =   param.author_id || false;
-            this.partner_ids =  [];
+            this.datasets = {
+                'id' : param.id || false,
+                'model' : param.model || false,
+                'parent_id' : param.parent_id || false,
+                'is_private' : param.is_private || false,
+                'author_id' : param.author_id || false,
+                'thread_level' : (param.thread_level+1) || 0,
+                'partner_ids' : []
+            };
+
             for(var i in param.partner_ids){
                 if(param.partner_ids[i][0]!=(param.author_id ? param.author_id[0] : -1)){
-                    this.partner_ids.push(param.partner_ids[i]);
+                    this.datasets.partner_ids.push(param.partner_ids[i]);
                 }
             }
 
             this.messages = [];
+            this.ComposeMessage = false;
 
-            this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model);
+            this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model || 'mail.thread');
             this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
         },
         
         start: function() {
-            // TDE TODO: check for deferred, not sure it is correct
             this._super.apply(this, arguments);
 
-            this.list_ul=this.$('ul.oe_mail_thread_display:first');
-            this.more_msg=this.$(">.oe_mail_msg_more_message:first");
+            this.list_ul = this.$('ul.oe_mail_thread_display:first');
+            this.more_msg = this.$(">.oe_msg_more_message:first");
 
             this.display_user_avatar();
             var display_done = compose_done = false;
             
-            this.instantiate_ComposeMessage();
-
             this.bind_events();
 
             if(this.options.thread._parents[0]==this){
-                this.on_first_thread();
+                this.on_root_thread();
             }
 
             return display_done && compose_done;
@@ -868,7 +888,8 @@ openerp.mail = function(session) {
             // add message composition form view
             this.ComposeMessage = new mail.ThreadComposeMessage(this,{
                 'context': this.context,
-                'parameters': this,
+                'datasets': this.datasets,
+                'options': this.options,
                 'show_attachment_delete': true,
             });
             this.ComposeMessage.appendTo(this.$(".oe_mail_thread_action:first"));
@@ -876,27 +897,26 @@ openerp.mail = function(session) {
 
         /* this method is runing for first parent thread
         */
-        on_first_thread: function(){
+        on_root_thread: function(){
             var self=this;
             // fetch and display message, using message_ids if set
             this.message_fetch();
 
             $(document).scroll( self.on_scroll );
+            $(window).resize( self.on_scroll );
             window.setTimeout( self.on_scroll, 500 );
 
             $(session.web.qweb.render('mail.wall_no_message', {})).appendTo(this.$('ul.oe_mail_thread_display'));
 
+            this.instantiate_ComposeMessage();
+            this.ComposeMessage.datasets.is_private=true;
+
             if(this.options.thread.show_header_compose){
                 this.ComposeMessage.$el.show();
                 //this.ComposeMessage.set_free_attachments();
             }
 
-            var button_fetch = $('<button style="display:none;" class="oe_mail_wall_button_fetch"/>').click(function(event){
-                if(event)event.stopPropagation();
-                self.message_fetch();
-            });
-            this.$el.prepend(button_fetch);
-            this.$el.addClass("oe_mail_wall_first_thread");
+            this.$el.addClass("oe_mail_root_thread");
         },
 
         /* When the expandable object is visible on screen (with scrolling)
@@ -904,16 +924,17 @@ openerp.mail = function(session) {
         */
         on_scroll: function(event){
             if(event)event.stopPropagation();
-            var last=this.messages[0];
-            if(last && last.type=="expandable"){
-                var pos = last.$el.position();
+            var message = this.messages[0];
+            if(message && message.datasets.type=="expandable" && message.datasets.max_limit){
+                var pos = message.$el.position();
                 if(pos.top){
                     /* bottom of the screen */
-                    var bottom = $(window).scrollTop()+$(window).height()+100;
+                    var bottom = $(window).scrollTop()+$(window).height()+200;
                     if(bottom - pos.top > 0){
-                        last.on_expandable();
+                        message.on_expandable();
                     }
                 }
+
             }
         },
 
@@ -930,10 +951,21 @@ openerp.mail = function(session) {
         */
         get_child_ids: function(){
             var res=[];
-            for(var i in this.messages){
-                if(this.messages[i].thread){
-                    res = res.concat( this.messages[i].get_child_ids(true) );
-                }
+            _(this.get_childs()).each(function (val, key) { res.push(val.datasets.id); });
+            return res;
+        },
+
+        /* get all child message/thread linked
+        */
+        get_childs: function(nb_thread_level){
+            var res=[];
+            if(arguments[1]) res.push(this);
+            if(isNaN(nb_thread_level) || nb_thread_level>0){
+                _(this.messages).each(function (val, key) {
+                    if(val.thread){
+                        res = res.concat( val.thread.get_childs((isNaN(nb_thread_level) ? null : nb_thread_level-1), true) ) 
+                    }
+                });
             }
             return res;
         },
@@ -954,7 +986,7 @@ openerp.mail = function(session) {
                 return this.options.thread._parents[0].browse_thread(options);
             }
 
-            if(this.id==options.id){
+            if(this.datasets.id==options.id){
                 return this;
             }
 
@@ -989,6 +1021,9 @@ openerp.mail = function(session) {
         /* this function is launch when a user click on "Reply" button
         */
         on_compose_message: function(){
+            if(!this.ComposeMessage){
+                this.instantiate_ComposeMessage();
+            }
             this.ComposeMessage.$el.toggle();
             return false;
         },
@@ -1000,7 +1035,7 @@ openerp.mail = function(session) {
          * @param {Array} replace_domain: added to this.domain
          * @param {Object} replace_context: added to this.context
          */
-        message_fetch: function (initial_mode, replace_domain, replace_context, ids) {
+        message_fetch: function (initial_mode, replace_domain, replace_context, ids, callback) {
             var self = this;
 
             // initial mode: try to use message_data or message_ids
@@ -1010,28 +1045,51 @@ openerp.mail = function(session) {
             // domain and context: options + additional
             fetch_domain = replace_domain ? replace_domain : this.domain;
             fetch_context = replace_context ? replace_context : this.context;
-            fetch_context.message_loaded= [this.id||0].concat( self.options.thread._parents[0].get_child_ids() );
+            var message_loaded = [this.datasets.id||0].concat( self.options.thread._parents[0].get_child_ids() );
 
-            return this.ds_message.call('message_read', [ids, fetch_domain, fetch_context, this.context.default_parent_id || undefined]
+            return this.ds_message.call('message_read', [ids, fetch_domain, message_loaded, fetch_context, this.context.default_parent_id || undefined]
                 ).then(this.proxy('switch_new_message'));
         },
 
         /* create record object and linked him
          */
-        create_message_object: function (message) {
+        create_message_object: function (data) {
             var self = this;
 
+            if(data.type=='expandable'){
+                var message = new mail.ThreadExpandable(self, {
+                    'domain': data.domain,
+                    'context': {
+                        'default_model': data.model || self.context.default_model,
+                        'default_res_id': data.res_id || self.context.default_res_id,
+                        'default_parent_id': self.datasets.id },
+                    'datasets': data
+                });
+            } else {
+                var message = new mail.ThreadMessage(self, {
+                    'domain': data.domain,
+                    'context': {
+                        'default_model': data.model,
+                        'default_res_id': data.res_id,
+                        'default_parent_id': data.id },
+                    'options':{
+                        'thread': self.options.thread,
+                        'message': self.options.message
+                    },
+                    'datasets': _.extend(data, {'thread_level': self.datasets.thread_level})
+                });
+                var data = _.extend(data, {'thread_level': self.datasets.thread_level});
+            }
+
             // check if the message is already create
-            for(var i in this.messages){
-                if(this.messages[i].id==message.id){
-                    this.messages[i].destroy();
-                    this.messages[i]=self.insert_message(message);
+            for(var i in self.messages){
+                if(self.messages[i].datasets.id==message.datasets.id){
+                    self.messages[i].destroy();
+                    self.messages[i]=self.insert_message(message);
                     return true;
                 }
             }
-
             self.messages.push( self.insert_message(message) );
-            
         },
 
         /** Displays a message or an expandable message  */
@@ -1040,47 +1098,61 @@ openerp.mail = function(session) {
 
             this.$("li.oe_wall_no_message").remove();
 
-            if(message.type=='expandable'){
-                var message = new mail.ThreadExpandable(self, {
-                    'domain': message.domain,
-                    'context': {
-                        'default_model':        message.model,
-                        'default_res_id':       message.res_id,
-                        'default_parent_id':    message.id },
-                    'parameters': message
-                });
-            } else {
-                var message = new mail.ThreadMessage(self, {
-                    'domain': message.domain,
-                    'context': {
-                        'default_model':        message.model,
-                        'default_res_id':       message.res_id,
-                        'default_parent_id':    message.id },
-                    'options':{
-                        'thread': self.options.thread,
-                        'message': self.options.message
-                    },
-                    'parameters': message
-                });
+            // insert on hierarchy display => insert in self child
+            var thread_messages = self.messages;
+            var thread = self;
+            var flat = false;
+            var hierarchy = self.options.thread.display_on_thread;
+            if( hierarchy[0] < 0 ||
+                hierarchy[0] > self.datasets.thread_level ||
+                (hierarchy[1]>0 && hierarchy[1] < self.datasets.thread_level) ) {
+
+                var flat = true;
+
+                if(hierarchy[0]<0){
+                
+                    // all is in flat mode
+                    thread =  self.options.thread._parents[0];
+                    var nb_thread_level = null;
+                
+                } else if(hierarchy[0] > self.datasets.thread_level) {
+                 
+                    // list all childs messages for flat display before the hierarchy
+                    thread =  self.options.thread._parents[0];
+                    var nb_thread_level = hierarchy[0];
+                
+                } else if(hierarchy[1] < self.datasets.thread_level) {
+                
+                    // list all childs messages for flat display after the hierarchy
+                    thread =  self.options.thread._parents[hierarchy[1]];
+                    var nb_thread_level = hierarchy[1]>0 ? hierarchy[1]-hierarchy[0] : null;
+                } else {
+
+                    thread =  self.options.thread._parents[0];
+                    var nb_thread_level = null;
+                }
+
+                var thread_messages = [];
+                _(thread.get_childs( nb_thread_level )).each(function (val, key) { thread_messages.push(val.parent_message); });
             }
 
-            var thread_messages = (self.options.thread.display_on_flat && self.options.thread.thread_level ? self.options.thread._parents[0].messages : []).concat(self.messages);
-            var thread = (self.options.thread.display_on_flat && self.options.thread.thread_level ? self.options.thread._parents[0] : self);
 
             // check older and newer message for insert
             var parent_newer = false;
             var parent_older = false;
-            for(var i in thread_messages){
-                if(thread_messages[i].id > message.id){
-                    if(!parent_newer || parent_newer.id>=thread_messages[i].id)
-                        parent_newer = thread_messages[i];
-                } else if(thread_messages[i].id>0 && thread_messages[i].id < message.id) {
-                    if(!parent_older || parent_older.id<thread_messages[i].id)
-                        parent_older = thread_messages[i];
+            if ( message.datasets.id > 0 ){
+                for(var i in thread_messages){
+                    if(thread_messages[i].datasets.id > message.datasets.id){
+                        if(!parent_newer || parent_newer.datasets.id>=thread_messages[i].datasets.id)
+                            parent_newer = thread_messages[i];
+                    } else if(thread_messages[i].datasets.id>0 && thread_messages[i].datasets.id < message.datasets.id) {
+                        if(!parent_older || parent_older.id<thread_messages[i].datasets.id)
+                            parent_older = thread_messages[i];
+                    }
                 }
             }
 
-            var sort = self.options.thread.thread_level==0 || (self.options.thread.display_on_flat && self.options.thread.thread_level<=1);
+            var sort = self.datasets.thread_level==0 || (flat && self.datasets.thread_level>=1);
 
             if(parent_older){
                 if(sort){
@@ -1088,21 +1160,20 @@ openerp.mail = function(session) {
                 } else {
                     message.insertAfter(parent_older.$el);
                 }
-            }
-            else if(parent_newer){
+            } else if(parent_newer){
                 if(sort){
                     message.insertAfter(parent_newer.$el);
                 } else {
                     message.insertBefore(parent_newer.$el);
                 }
-            }
-            else {
-                if(sort){
+            } else {
+                if(sort && message.id > 0){
                     message.prependTo(thread.list_ul);
                 } else {
                     message.appendTo(thread.list_ul);
                 }
             }
+
             return message
         },
 
@@ -1154,6 +1225,7 @@ openerp.mail = function(session) {
             this.$el.toggle(this.view.get("actual_mode") !== "create");
         },
         render_value: function() {
+            var self = this;
             if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
                 this.$('oe_mail_thread').hide();
                 return;
@@ -1161,7 +1233,8 @@ openerp.mail = function(session) {
             // update context
             _.extend(this.options.context, {
                 default_res_id: this.view.datarecord.id,
-                default_model: this.view.model });
+                default_model: this.view.model,
+                default_is_private: false });
             // update domain
             var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]);
             // create and render Thread widget
@@ -1179,13 +1252,15 @@ openerp.mail = function(session) {
                         'thread':{
                             'show_header_compose': show_header_compose,
                             'use_composer': show_header_compose,
-                            'display_on_flat':true
+                            'display_on_thread':[-1,-1]
                         },
                         'message':{
-                            'show_dd_delete': true
+                            'show_reply': [-1,-1],
+                            'show_read_unread': [-1,-1],
+                            'show_dd_delete': false
                         }
                     },
-                    'parameters': {},
+                    'datasets': {},
                 }
             );
             return this.thread.appendTo( this.$('.oe_mail_wall_threads:first') );
@@ -1272,21 +1347,25 @@ openerp.mail = function(session) {
          * Display the threads
           */
         message_render: function (search) {
+            var domain = this.options.domain.concat(this.search_results['domain']);
+            var context = _.extend(this.options.context, search&&search.search_results['context'] ? search.search_results['context'] : {});
             this.thread = new mail.Thread(this, {
-                    'domain' : this.options.domain.concat(this.search_results['domain']),
-                    'context' : _.extend(this.options.context, search&&search.search_results['context'] ? search.search_results['context'] : {}),
+                    'domain' : domain,
+                    'context' : context,
                     'options': {
                         'thread' :{
                             'use_composer': true,
                             'show_header_compose': false,
+                            'typeof_thread': context.typeof_thread || 'inbox',
+                            'display_on_thread': [0,1]
                         },
                         'message': {
-                            'show_reply': true,
-                            'show_dd_hide': true,
-                            'show_dd_delete': true,
+                            'show_reply': [0,0],
+                            'show_read_unread': [0,-1],
+                            'show_dd_delete': false,
                         },
                     },
-                    'parameters': {},
+                    'datasets': {},
                 }
             );
             return this.thread.appendTo( this.$('.oe_mail_wall_threads:first') );
@@ -1299,4 +1378,58 @@ openerp.mail = function(session) {
             this.$("button.oe_write_onwall:first").click(function(){ self.thread.ComposeMessage.$el.toggle(); });
         }
     });
+
+
+    /**
+     * ------------------------------------------------------------
+     * UserMenu
+     * ------------------------------------------------------------
+     * 
+     * Add a link on the top user bar for write a full mail
+     */
+    session.web.ComposeMessageTopButton = session.web.Widget.extend({
+        template:'mail.compose_message.button_top_bar',
+
+        init: function (parent, options) {
+            this._super.apply(this, options);
+            this.options = this.options || {};
+            this.options.domain = this.options.domain || [];
+            this.options.context = {
+                'default_model': false,
+                'default_res_id': 0,
+                'default_content_subtype': 'html',
+            };
+        },
+
+        start: function(parent, params) {
+            var self = this;
+            this.$el.on('click', 'button', self.on_compose_message );
+            this._super(parent, params);
+        },
+
+        on_compose_message: function(event){
+            event.stopPropagation();
+            var action = {
+                type: 'ir.actions.act_window',
+                res_model: 'mail.compose.message',
+                view_mode: 'form',
+                view_type: 'form',
+                action_from: 'mail.ThreadComposeMessage',
+                views: [[false, 'form']],
+                target: 'new',
+                context: this.options.context,
+            };
+            session.client.action_manager.do_action(action);
+        },
+
+    });
+
+    session.web.UserMenu = session.web.UserMenu.extend({
+        start: function(parent, params) {
+            var render = new session.web.ComposeMessageTopButton();
+            render.insertAfter(this.$el);
+            this._super(parent, params);
+        }
+    });
+
 };
index 3fa33db..806bf28 100644 (file)
@@ -39,6 +39,7 @@ openerp_mail_followers = function(session, mail) {
             this._check_visibility();
             this.reinit();
             this.bind_events();
+            this._super();
         },
 
         _check_visibility: function() {
@@ -72,7 +73,7 @@ openerp_mail_followers = function(session, mail) {
                     target: 'new',
                     context: {
                         'default_res_model': self.view.dataset.model,
-                        'default_res_id': self.view.datarecord.id
+                        'default_res_id': self.view.datarecord.id,
                     },
                 }
                 self.do_action(action, {
@@ -90,12 +91,6 @@ openerp_mail_followers = function(session, mail) {
             });
         },
 
-        set_value: function (value_) {
-            this._super(value_);
-            // TDE FIXME: render_value is never called... ask to niv
-            this.render_value();
-        },
-
         render_value: function () {
             this.reinit();
             return this.fetch_followers(this.get("value"));
@@ -187,7 +182,7 @@ openerp_mail_followers = function(session, mail) {
         display_subtypes:function (data) {
             var self = this;
             var subtype_list_ul = this.$('.oe_subtypes');
-            var records = (data[this.view.datarecord.id] || data[null]).message_subtype_data;
+            var records = data[this.view.datarecord.id].message_subtype_data;
 
             _(records).each(function (record, record_name) {
                 record.name = record_name;
index 6ace665..fbb64cc 100644 (file)
@@ -11,7 +11,7 @@
     <t t-name="mail.compose_message">
         <div class="oe_mail_compose_textarea">
             <img class="oe_mail_icon oe_mail_frame oe_left" alt="User img"/>
-            <div class="oe_mail_msg_content">
+            <div class="oe_msg_content">
                 <!-- contains the composition form -->
                 <!-- default content: old basic textarea -->
                 <div class="oe_mail_post_header">
         Template used to display attachments in a mail.message
         -->
     <t t-name="mail.thread.message.attachments">
-        <ul t-attf-class="oe_mail_msg_attachments #{widget.attachment_ids[0] and widget.options.thread.show_attachment_link?'':'oe_hidden'}">
-            <t t-foreach="widget.attachment_ids" t-as="attachment">
+        <ul t-attf-class="oe_msg_attachments #{widget.datasets.attachment_ids[0] and widget.options.thread.show_attachment_link?'':'oe_hidden'}">
+            <t t-foreach="widget.datasets.attachment_ids" t-as="attachment">
                 <li>
                     <span t-if="(attachment.upload or attachment.percent_loaded&lt;100)" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}" t-attf-name="{attachment.name || attachment.filename}">
                         <div class="oe_upload_in_process">
-                            <span>Upload in progress...</span>
-                            <div t-attf-style="{attachment.percent_loaded&gt;0?'':'display:none;'}"/>
-                            <div t-attf-style="{attachment.percent_loaded&gt;20?'':'display:none;'}"/>
-                            <div t-attf-style="{attachment.percent_loaded&gt;40?'':'display:none;'}"/>
-                            <div t-attf-style="{attachment.percent_loaded&gt;60?'':'display:none;'}"/>
-                            <div t-attf-style="{attachment.percent_loaded&gt;80?'':'display:none;'}"/>
+                            <span>...Upload in progress...</span>
                         </div>
                         <t t-raw="attachment.name || attachment.filename"/>
                     </span>
         -->
     <t t-name="mail.thread.list_recipients">
         <div class="oe_mail_list_recipients">
-            Post to: 
-            <span t-if="widget.context.default_res_id and widget.context.default_res_id" class="oe_all_follower">All Followers</span> 
-            <t t-if="!widget.context.default_res_id and widget.context.default_res_id and widget.partner_ids.length"> and </t>
+            Post to:
+            <span t-if="!widget.datasets.is_private" class="oe_all_follower">All Followers</span> 
+            <t t-if="!widget.datasets.is_private and widget.datasets.partner_ids.length"> and </t>
             <t t-set="inc" t-value="0"/>
-            <t t-if="widget.partner_ids.length" t-foreach="widget.partner_ids" t-as="partner"><span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/><a t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a></span><t t-set="inc" t-value="inc+1"/>
+            <t t-if="widget.datasets.partner_ids.length" t-foreach="widget.datasets.partner_ids" t-as="partner"><span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/><a t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a></span><t t-set="inc" t-value="inc+1"/>
             </t>
-            <t t-if="widget.partner_ids.length>=3">
-                <span class="oe_more">, <a><t t-raw="widget.partner_ids.length-3"/> others...</a></span>
+            <t t-if="widget.datasets.partner_ids.length>=3">
+                <span class="oe_more">, <a><t t-raw="widget.datasets.partner_ids.length-3"/> others...</a></span>
                 <a class="oe_more_hidden">&lt;&lt;&lt;</a>
             </t>
         </div>
         wall main template
         Template used to display the communication history in the wall.
         -->
-    <div t-name="mail.wall" class="oe_view_manager oe_mail_wall oe_view_manag
-        er_current">
+    <div t-name="mail.wall" class="oe_view_manager oe_mail_wall oe_view_manager_current">
         <table class="oe_view_manager_header">
           <colgroup>
             <col width="33%"/>
     </div>
 
     <!-- default layout -->
-    <li t-name="mail.thread.message" t-attf-class="oe_mail oe_mail_thread_msg #{widget.to_read ?'oe_mail_unread':'oe_mail_read'}">
-        <div t-attf-class="oe_mail_msg_#{widget.type} oe_semantic_html_override">
+    <li t-name="mail.thread.message" t-attf-class="oe_mail oe_mail_thread_msg #{widget.datasets.to_read ?'oe_mail_unread':'oe_mail_read'}">
+        <div t-attf-class="oe_msg_#{widget.datasets.type} oe_semantic_html_override">
             <!-- message actions (read/unread, reply, delete...) -->
             <ul class="oe_header">
                 <li class="placeholder-mail-vote"><t t-call="mail.thread.message.vote"/></li>
-                <li t-if="!widget.options.thread.display_on_flat" title="Read" class="oe_read"><a class="oe_read oe_e">W</a></li>
-                <li t-if="!widget.options.thread.display_on_flat" title="Set back to unread" class="oe_unread"><a class="oe_unread oe_e">h</a></li>
-                <li title="Quick reply"><a class="oe_reply oe_e">)</a></li>
-                <t t-if="(widget.is_author and widget.options.message.show_dd_delete) or widget.type == 'email'">
+                <li class="placeholder-mail-star"><t t-call="mail.thread.message.star"/></li>
+                <li t-if="widget.datasets.show_read_unread" title="Read" class="oe_read"><a class="oe_read oe_e">W</a></li>
+                <li t-if="widget.datasets.show_read_unread" title="Set back to unread" class="oe_unread"><a class="oe_unread oe_e">h</a></li>
+                <li title="Quick reply" t-if="widget.datasets.show_reply"><a class="oe_reply oe_e">)</a></li>
+                <t t-if="(widget.datasets.is_author and widget.options.message.show_dd_delete) or widget.datasets.type == 'email'">
                     <li>
                         <span class="oe_dropdown_toggle">
                             <a class="oe_e" title="More options">í</a>
                             <ul class="oe_dropdown_menu">
-                                <li t-if="widget.is_author and widget.options.message.show_dd_delete"><a class="oe_mail_msg_delete">Delete</a></li>
-                                <!--  Uncomment when adding subtype hiding
-                                <li t-if="display['show_hide']">
-                                    <a href="#" class="oe_mail_msg_hide_type" t-attf-data-subtype='{widget.subtype}'>Hide '<t t-esc="widget.subtype"/>' for this document</a>
-                                </li> -->
-                                <li t-if="widget.type == 'email'"><a class="oe_mail_msg_details" t-attf-href="#model=mail.message&amp;id=#{widget.id}" >Details</a></li>
+                                <li t-if="widget.datasets.is_author and widget.options.message.show_dd_delete"><a class="oe_msg_delete">Delete</a></li>
+                                <li t-if="widget.datasets.type == 'email'"><a class="oe_msg_details" t-attf-href="#model=mail.message&amp;id=#{widget.datasets.id}" >Details</a></li>
                             </ul>
                         </span>
                     </li>
                 </t>
             </ul>
 
-            <a t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}" t-att-title="widget.author_id[1]">
-                <img class="oe_mail_icon oe_mail_frame oe_left" t-att-src="widget.avatar"/>
+            <a t-attf-href="#model=res.partner&amp;id=#{widget.datasets.author_id[0]}" t-att-title="widget.datasets.author_id[1]">
+                <img class="oe_mail_icon oe_mail_frame oe_left" t-att-src="widget.datasets.avatar"/>
             </a>
 
-            <div class="oe_mail_msg_content">
+            <div class="oe_msg_content">
                 <!-- message itself -->
                 <div class="oe_mail_msg">
-                    <h1 t-if="widget.subject" class="oe_mail_msg_title">
-                        <t t-raw="widget.subject"/>
+                    <h1 t-if="widget.datasets.subject" class="oe_msg_title">
+                        <t t-raw="widget.datasets.subject"/>
                     </h1>
-                    <ul class="oe_mail_msg_footer">
-                        <li t-if="widget.author_id"><a t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}"><t t-raw="widget.author_id[1]"/></a></li>
-                        <li><span t-att-title="widget.date"><t t-raw="widget.timerelative"/></span></li>
-                        <li t-if="widget.attachment_ids.length > 0">
-                            <a class="oe_mail_msg_view_attachments">
-                                <t t-if="widget.attachment_ids.length == 1">1 Attachment</t>
-                                <t t-if="widget.attachment_ids.length > 1"><t t-raw="widget.attachment_ids.length"/> Attachments</t>
+                    <ul class="oe_msg_footer">
+                        <li t-if="widget.datasets.author_id"><a t-attf-href="#model=res.partner&amp;id=#{widget.datasets.author_id[0]}"><t t-raw="widget.datasets.author_id[1]"/></a></li>
+                        <li><span t-att-title="widget.datasets.date"><t t-raw="widget.datasets.timerelative"/></span></li>
+                        <li t-if="widget.datasets.attachment_ids.length > 0">
+                            <a class="oe_msg_view_attachments">
+                                <t t-if="widget.datasets.attachment_ids.length == 1">1 Attachment</t>
+                                <t t-if="widget.datasets.attachment_ids.length > 1"><t t-raw="widget.datasets.attachment_ids.length"/> Attachments</t>
                             </a>
                         </li>
                     </ul>
                     <div class="oe_clear"/>
-                    <div class="oe_mail_msg_body">
-                        <t t-if="widget.options.message.show_record_name and widget.record_name and (!widget.subject) and !widget.options.thread.thread_level and !widget.options.thread.display_on_flat and widget.model!='res.partner'">
-                            <a class="oe_mail_action_model" t-attf-href="#model=#{widget.model}&amp;id=#{widget.res_id}"><t t-raw="widget.record_name"/></a>
+                    <div class="oe_msg_body">
+                        <t t-if="widget.options.message.show_record_name and widget.datasets.record_name and (!widget.datasets.subject) and !widget.options.thread.thread_level and !widget.options.thread.display_on_thread[0] and widget.datasets.model!='res.partner'">
+                            <a class="oe_mail_action_model" t-attf-href="#model=#{widget.datasets.model}&amp;id=#{widget.res_id}"><t t-raw="widget.datasets.record_name"/></a>
                         </t>
-                        <t t-raw="widget.body"/>
+                        <t t-raw="widget.datasets.body"/>
                     </div>
-                    <t t-if="widget.attachment_ids.length > 0">
+                    <t t-if="widget.datasets.attachment_ids.length > 0">
                         <div class="oe_clear"></div>
                         <t t-call="mail.thread.message.attachments"/>
                     </t>
 
     <!-- expandable message layout -->
     <li t-name="mail.thread.expandable" class="oe_mail oe_mail_thread_msg oe_mail_unread">
-        <div t-attf-class="oe_mail_msg_#{widget.type} oe_semantic_html_override">
-            <div class="oe_mail_msg_content oe_mail_msg_more_message">
-                <a class="oe_mail_fetch_more">Load more messages <span t-if="widget.nb_messages>0">(<t t-raw="widget.nb_messages"/> messages not display)</span>...</a>
+        <div t-attf-class="oe_msg_#{widget.datasets.type} oe_semantic_html_override">
+            <div class="oe_msg_content oe_msg_more_message">
+                <a class="oe_mail_fetch_more">Load more messages <span t-if="widget.datasets.nb_messages>0">(<t t-raw="widget.datasets.nb_messages"/> messages not display)</span>...</a>
             </div>
         </div>
     </li>
 
+    <!--
+        mail.compose_message.button_top_bar
+        render of the button on the user bar for open wizard compose message
+        -->
+    <t t-name="mail.compose_message.button_top_bar">
+        <div class="oe_topbar_compose_full_email">
+            <button class="oe_button oe_highlight">Write an email</button>
+        </div>
+    </t>
+
     <!-- mail.thread.message.vote
         Template used to display Like/Unlike in a mail.message
     -->
     <span t-name="mail.thread.message.vote">
         <span class="oe_left oe_mail_vote_count">
-            <t t-if='widget.has_voted'>
+            <t t-if='widget.datasets.has_voted'>
                 You
             </t>
-            <t t-if='(widget.vote_user_ids.length-(widget.has_voted?1:0)) > 0'>
-                <t t-if='widget.has_voted'> and </t>
-                <t t-esc="widget.vote_user_ids.length"/> people
+            <t t-if='(widget.datasets.vote_user_ids.length-(widget.datasets.has_voted?1:0)) > 0'>
+                <t t-if='widget.datasets.has_voted'> and </t>
+                <t t-esc="widget.datasets.vote_user_ids.length"/> people
             </t>
-            <t t-if='widget.vote_user_ids.length > 0'>
+            <t t-if='widget.datasets.vote_user_ids.length > 0'>
                 agree
             </t>
         </span>
-        <button t-attf-class="oe_mail_msg_vote oe_tag">
+        <button t-attf-class="oe_msg_vote oe_tag">
             <span>
                 <t t-if="!widget.has_voted">Agree</t>
                 <t t-if="widget.has_voted">Undo</t>
         </button>
     </span>
 
+    <!-- mail.thread.message.star
+        Template used to display stared/unstared message in a mail.message
+    -->
+    <span t-name="mail.thread.message.star">
+        <span class="oe_left">
+            <button t-attf-class="oe_mail_starbox oe_tag #{widget.datasets.is_favorite?'oe_stared':''}">*</button>
+        </span>
+    </span>
+
 </template>
index 271d4d3..2eff59f 100644 (file)
@@ -520,6 +520,10 @@ class test_mail(TestMailMockups):
         self.assertEqual(message2.subject, _subject, 'mail.message subject incorrect')
         self.assertEqual(message2.body, group_bird.description, 'mail.message body incorrect')
 
+    def test_30_message_read(self):
+        """ Tests for message_read and expandables. """
+        self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True')
+
     def test_40_needaction(self):
         """ Tests for mail.message needaction. """
         cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
@@ -577,11 +581,19 @@ class test_mail(TestMailMockups):
         reply_msg = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
                                          extra='In-Reply-To: %s' % msg1.message_id)
         self.mail_group.message_process(cr, uid, None, reply_msg)
+        # TDE note: temp various asserts because of the random bug about msg1.child_ids
+        msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=1)
+        new_msg = self.mail_message.browse(cr, uid, msg_ids[0])
+        self.assertEqual(new_msg.parent_id, msg1, 'Newly processed mail_message (%d) should have msg1 as parent' % (new_msg.id))
 
         # 2. References header
         reply_msg2 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: Re: 1',
                                          extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id)
         self.mail_group.message_process(cr, uid, None, reply_msg2)
+        # TDE note: temp various asserts because of the random bug about msg1.child_ids
+        msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=1)
+        new_msg = self.mail_message.browse(cr, uid, msg_ids[0])
+        self.assertEqual(new_msg.parent_id, msg1, 'Newly processed mail_message should have msg1 as parent')
 
         # 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, not to mail
         reply_msg3 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com',
@@ -591,9 +603,15 @@ class test_mail(TestMailMockups):
         group_pigs.refresh()
         msg1.refresh()
         self.assertEqual(5, len(group_pigs.message_ids), 'group should contain 5 messages')
+        # TDE note: python test + debug because of the random error we see with the next assert
+        if len(msg1.child_ids) != 2:
+            msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=10)
+            for new_msg in self.mail_message.browse(cr, uid, msg_ids):
+                print new_msg.subject, '(id', new_msg.id, ')', 'parent_id:', new_msg.parent_id
+                print '\tchild_ids', [child.id for child in new_msg.child_ids]
         self.assertEqual(2, len(msg1.child_ids), 'msg1 should have 2 children now')
 
-    def test_60_vote(self):
+    def test_60_message_vote(self):
         """ Test designed for the vote/unvote feature. """
         cr, uid = self.cr, self.uid
         user_admin = self.res_users.browse(cr, uid, uid)
@@ -613,7 +631,7 @@ class test_mail(TestMailMockups):
         # Test: msg1 has Admin as voter
         self.assertEqual(set(msg1.vote_user_ids), set([user_admin]), 'after voting, Admin is not the voter')
         # Do: Bert vote for msg1
-        self.mail_message.vote_toggle(cr, uid, [msg1.id], [user_bert_id])
+        self.mail_message.vote_toggle(cr, user_bert_id, [msg1.id])
         msg1.refresh()
         # Test: msg1 has Admin and Bert as voters
         self.assertEqual(set(msg1.vote_user_ids), set([user_admin, user_bert]), 'after voting, Admin and Bert are not the voters')
@@ -622,3 +640,7 @@ class test_mail(TestMailMockups):
         msg1.refresh()
         # Test: msg1 has Bert as voter
         self.assertEqual(set(msg1.vote_user_ids), set([user_bert]), 'after unvoting for Admin, Bert is not the voter')
+
+    def test_70_message_favorite(self):
+        """ Tests for favorites. """
+        self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True')
index 9e35391..f571a59 100644 (file)
@@ -22,7 +22,7 @@ check the logs to see if a message we just received was already logged.
 """
 _PREVIOUS_LOG_CHECK = datetime.timedelta(days=365)
 
-def get_sys_logs(cr, uid):
+def get_sys_logs(self, cr, uid):
     """
     Utility method to send a publisher warranty get logs messages.
     """
@@ -42,7 +42,7 @@ def get_sys_logs(cr, uid):
         nbr_active_share_users = pool.get("res.users").search(cr, uid, [("share", "=", True), ("date", ">=", limit_date_str)], count=True)
     user = pool.get("res.users").browse(cr, uid, uid)
 
-    web_base_url = safe_eval(self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', 'False'))
+    web_base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', 'False')
     msg = {
         "dbuuid": dbuuid,
         "nbr_users": nbr_users,
@@ -62,6 +62,7 @@ def get_sys_logs(cr, uid):
     arguments_raw = urllib.urlencode(arguments)
 
     url = config.get("publisher_warranty_url")
+
     uo = urllib2.urlopen(url, arguments_raw, **add_arg)
     result = {}
     try:
@@ -84,8 +85,8 @@ class publisher_warranty_contract(osv.osv):
         """
         try:
             try:
-                result = get_sys_logs(cr, uid)
-            except Exception:
+                result = get_sys_logs(self, cr, uid)
+            except Exception, ex:
                 if cron_mode: # we don't want to see any stack trace in cron
                     return False
                 _logger.debug("Exception while sending a get logs messages", exc_info=1)
index ce86e0b..255954e 100644 (file)
@@ -6,14 +6,14 @@
             <field name="model">mail.compose.message</field>
             <field name="arch" type="xml">
                 <form string="Compose Email" version="7.0">
-                    <!-- truly invisible fields for control and options -->
-                    <field name="composition_mode" nolabel="1" invisible="0"/>
-                    <field name="model" nolabel="1" invisible="0"/>
-                    <field name="res_id" nolabel="1" invisible="0"/>
-                    <field name="parent_id" nolabel="1" invisible="0"/>
-                    <field name="content_subtype" nolabel="1" invisible="0"/>
-                    <!-- visible wizard -->
                     <group>
+                        <!-- truly invisible fields for control and options -->
+                        <field name="composition_mode" invisible="1"/>
+                        <field name="model" invisible="1"/>
+                        <field name="res_id" invisible="1"/>
+                        <field name="parent_id" invisible="1"/>
+                        <field name="content_subtype" invisible="1"/>
+                        <!-- visible wizard -->
                         <field name="subject" placeholder="Subject..."
                                 attrs="{'invisible':[('content_subtype', '=', 'plain')]}"/>/>
                         <field name="partner_ids" widget="many2many_tags" placeholder="Add contacts to notify..."
index 9d1ae9e..9e35377 100644 (file)
                         <page string="Consumed Products">
                             <group>
                                 <group string="Products to Consume">
-                                    <field name="move_lines" nolabel="1">
+                                    <field name="move_lines" nolabel="1" options="{'reload_on_button': true}">
                                         <tree colors="blue:state == 'draft';black:state in ('picking_except','confirmed','ready','in_production');gray:state in ('cancel','done') " string="Products to Consume">
                                             <field name="product_id"/>
                                             <field name="product_qty"  string="Quantity"/>
index 19f8a48..e2ba45e 100644 (file)
@@ -110,7 +110,7 @@ class procurement_order(osv.osv):
 
     def production_order_create_note(self, cr, uid, ids, context=None):
         for procurement in self.browse(cr, uid, ids, context=context):
-            body = _("Manufacturing Order created.")
+            body = _("Manufacturing Order <em>%s</em> created.") % ( procurement.production_id.name,)
             self.message_post(cr, uid, [procurement.id], body=body, context=context)
     
 procurement_order()
index d7213a1..6ca9cb3 100644 (file)
@@ -24,7 +24,6 @@ access_account_account,account.account mrp_worker,account.model_account_account,
 access_purchase_order_mrp_worker,purchase.order mrp_worker,purchase.model_purchase_order,mrp.group_mrp_user,1,0,0,0\r
 access_purchase_order_line_mrp_worker,purchase.order.line mrp_worker,purchase.model_purchase_order_line,mrp.group_mrp_user,1,0,0,0\r
 access_hr_timesheet_group_mrp_worker,resource.calendar mrp_manager,resource.model_resource_calendar,mrp.group_mrp_manager,1,1,1,1\r
-access_procurement_stock_worker,procurement.order stock_worker,model_procurement_order,stock.group_stock_user,1,1,1,1\r
 access_procurement_user,procurement.order.user,model_procurement_order,base.group_user,1,1,1,1\r
 access_mrp_production_stock_worker,mrp.production stock_worker,model_mrp_production,stock.group_stock_user,1,0,0,0\r
 access_report_workcenter_load,report.workcenter.load,model_report_workcenter_load,mrp.group_mrp_manager,1,1,1,1\r
index 1d89d28..3671408 100644 (file)
           <para style="terp_tblheader_General_Right">Total:</para>
         </td>
         <td>
-          <para style="terp_default_Right_9">[[ formatLang(pos_payment_user_total(data['form'], currency_obj = company.currency_id)) or removeParentNode('blockTable')]]</para>
+          <para style="terp_default_Right_9">[[ formatLang(pos_payment_user_total(data['form']), currency_obj = company.currency_id) or removeParentNode('blockTable')]]</para>
         </td>
       </tr>
     </blockTable>
index 1ad03c5..bd174b1 100644 (file)
@@ -938,10 +938,11 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
             this.renderElement();
         },
         addPaymentLine: function(newPaymentLine) {
+            var self = this;
             var x = new module.PaymentlineWidget(null, {
                     payment_line: newPaymentLine
                 });
-            x.on_delete.add(_.bind(this.deleteLine, this, x));
+            x.on('delete_payment_line', self, self.deleteLine);
             x.appendTo(this.$('#paymentlines'));
         },
         renderElement: function() {
index 47a527a..28ab79c 100644 (file)
@@ -142,7 +142,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
         },
         click_handler: function() {
             this.order.selectLine(this.model);
-            this.on_selected();
+            this.trigger('order_line_selected');
         },
         renderElement: function() {
             this._super();
@@ -153,10 +153,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
         },
         refresh: function(){
             this.renderElement();
-            this.on_refresh();
+            this.trigger('order_line_refreshed');
         },
-        on_selected: function() {},
-        on_refresh: function(){},
     });
     
     module.OrderWidget = module.PosBaseWidget.extend({
@@ -230,8 +228,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
                         model: orderLine,
                         order: this.pos.get('selectedOrder'),
                 });
-               line.on_selected.add(_.bind(this.update_numpad, this));
-                line.on_refresh.add(_.bind(this.update_summary, this));
+               line.on('order_line_selected', self, self.update_numpad);
+                line.on('order_line_refreshed', self, self.update_summary);
                 line.appendTo($content);
             }, this));
             this.update_numpad();
@@ -303,7 +301,6 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
             this.payment_line = options.payment_line;
             this.payment_line.bind('change', this.changedAmount, this);
         },
-        on_delete: function() {},
         changeAmount: function(event) {
             var newAmount;
             newAmount = event.currentTarget.value;
@@ -317,10 +314,13 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
                        this.renderElement();
         },
         renderElement: function() {
+            var self = this;
             this.name =   this.payment_line.get_cashregister().get('journal_id')[1];
             this._super();
             this.$('input').keyup(_.bind(this.changeAmount, this));
-            this.$('.delete-payment-line').click(this.on_delete);
+            this.$('.delete-payment-line').click(function() {
+                self.trigger('delete_payment_line');
+            });
         },
     });
 
@@ -1055,8 +1055,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
             this.pos.barcode_reader.disconnect();
             return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id']).pipe(
                     _.bind(function(res) {
-                return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) {
-                    var action = result.result;
+                return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(action) {
                     action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}});
                     //self.destroy();
                     this.do_action(action);
index a88c8ce..e177b07 100644 (file)
@@ -5,7 +5,7 @@
         <record id="portal_stock_picking_user_rule" model="ir.rule">
             <field name="name">Portal Personal Claims</field>
             <field ref="crm_claim.model_crm_claim" name="model_id"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in', [user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
index 316fb1b..1247d25 100644 (file)
@@ -5,7 +5,7 @@
         <record id="portal_task_rule" model="ir.rule">
             <field name="name">Portal Personal Task</field>
             <field ref="project.model_project_task" name="model_id"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in', [user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
index d58e160..9527f1f 100644 (file)
@@ -5,7 +5,7 @@
         <record id="portal_issue_rule" model="ir.rule">
             <field name="name">Portal Personal Issues</field>
             <field ref="project_issue.model_project_issue" name="model_id"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in', [user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
index 5786fbc..6b25d87 100644 (file)
@@ -13,7 +13,7 @@
             <field name="view_mode">tree,form,calendar,graph</field>
             <field name="context">{"search_default_draft":1}</field>
             <field name="search_view_id" ref="sale.view_sales_order_filter"/>
-            <field name="help">You dont have any quotation.</field>
+            <field name="help">You don't have any quotation.</field>
         </record>
 
         <record id="action_order_form" model="ir.actions.act_window">
@@ -23,7 +23,7 @@
             <field name="view_mode">tree,form,calendar,graph</field>
             <field name="search_view_id" ref="sale.view_sales_order_filter"/>
             <field name="context">{"search_default_sales":1}</field>
-            <field name="help">You dont have any sale order.</field>
+            <field name="help">You don't have any sale order.</field>
         </record>
 
         <record id="action_picking_tree" model="ir.actions.act_window">
@@ -34,7 +34,7 @@
             <field name="domain">[('type','=','out')]</field>
             <field name="context">{'default_type': 'out', 'contact_display': 'partner_address'}</field>
             <field name="search_view_id" ref="stock.view_picking_out_search"/>
-            <field name="help">You dont have any delivery order.</field>
+            <field name="help">You don't have any delivery order.</field>
         </record>
 
         <record id="product_normal_action" model="ir.actions.act_window">
@@ -55,7 +55,7 @@
             <field name="domain">[('type','=','out_invoice')]</field>
             <field name="context">{'default_type':'out_invoice', 'type':'out_invoice', 'journal_type': 'sale'}</field>
             <field name="search_view_id" ref="account.view_account_invoice_filter"/>
-            <field name="help">You dont have any invoice.</field>
+            <field name="help">You don't have any invoice.</field>
         </record>
 
         <record id="action_vendor_receipt" model="ir.actions.act_window">
@@ -65,7 +65,7 @@
             <field name="context">{'type':'receipt'}</field>
             <field name="search_view_id" ref="account_voucher.view_voucher_filter_customer_pay"/>
             <field name="target">current</field>
-            <field name="help">You dont have any payment.</field>
+            <field name="help">You don't have any payment.</field>
         </record>
 
         <menuitem name="Quotations" id="portal_quotations" parent="portal.portal_orders"
index d27317d..c4bf613 100644 (file)
@@ -6,42 +6,42 @@
         <record id="portal_sale_order_user_rule" model="ir.rule">
             <field name="name">Portal Personal Quotations/Sales Orders</field>
             <field name="model_id" ref="sale.model_sale_order"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
         <record id="portal_stock_picking_user_rule" model="ir.rule">
             <field name="name">Portal Personal Delivery Orders</field>
             <field name="model_id" ref="stock.model_stock_picking"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
         <record id="portal_stock_picking_user_rule" model="ir.rule">
             <field name="name">Portal Personal Delivery Orders Out</field>
             <field name="model_id" ref="stock.model_stock_picking_out"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
         <record id="portal_account_invoice_user_rule" model="ir.rule">
             <field name="name">Portal Personal Account Invoices</field>
             <field name="model_id" ref="account.model_account_invoice"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
         <record id="portal_personal_payment" model="ir.rule">
             <field name="name">Portal Personal Payments</field>
             <field name="model_id" ref="account_voucher.model_account_voucher"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
         <record id="portal_personal_contact" model="ir.rule">
             <field name="name">Portal Personal Contacts</field>
             <field name="model_id" ref="base.model_res_partner"/>
-            <field name="domain_force">[('message_follower_ids','in',user.partner_id.id)]</field>
+            <field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
             <field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
         </record>
 
index c214dbb..2405f6d 100644 (file)
@@ -176,6 +176,11 @@ instance.web.ViewManager.include({
                 var notes = new_notes.substring(0,60) +'..';
             }
             r.text(nodes.x+60, nodes.y+30, (notes || new_notes)).attr({"title":nodes.notes,"cursor": "default"});
+            r['image']('/web/static/src/img/icons/gtk-info.png', nodes.x, nodes.y+75, 16, 16)
+              .attr({"cursor": "pointer", "title": "Help"})
+              .click(function() {
+                   window.open(nodes.url || "http://doc.openerp.com/v6.1/index.php?model=" + nodes.model);
+              });
             if(nodes.menu) {
                  r['image']('/web/static/src/img/icons/gtk-jump-to.png', nodes.x+100, nodes.y+75, 16, 16)
                     .attr({"cursor": "pointer", "title": nodes.menu.name})
index b1a39aa..d6229b6 100644 (file)
@@ -16,7 +16,7 @@
                    <div class="oe_view_manager_header" style="padding: 8px;">
                        <div class="oe_header_row">
                             <h2 class="oe_view_title">
-                                <span class="oe_view_title_text oe_breadcrumb_title"><t t-esc="action.name"/> (<t t-esc="action.res_model"/>)</span>
+                                <span class="oe_view_title_text oe_breadcrumb_title"><t t-esc="action.name"/> (<a t-attf-href="http://doc.openerp.com/v6.1/index.php?model=#{action.res_model}"><t t-esc="action.res_model"/></a>)</span>
                             </h2>
                        </div>
                     </div>
@@ -25,7 +25,7 @@
         </tr>
         <tr>
             <td style="padding-left:10px;">
-                <p><t t-esc="process_help"/></p>
+                <p><t t-raw="process_help"/></p>
             </td>
         </tr>
         <tr>
index c26a7b7..e0e3553 100644 (file)
@@ -13,7 +13,7 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-19 05:14+0000\n"
+"X-Launchpad-Export-Date: 2012-10-20 05:07+0000\n"
 "X-Generator: Launchpad (build 16165)\n"
 
 #. module: product
index 3bc6e6d..f5c69c7 100644 (file)
@@ -410,7 +410,7 @@ class product_pricelist_item(osv.osv):
         'min_quantity': fields.integer('Min. Quantity', required=True, help="The rule only applies if the partner buys/sells equal to or more than this quantity."),
         'sequence': fields.integer('Sequence', required=True, help="Gives the order in which the pricelist items will be checked. The evaluation gives highest priority to lowest sequence and stops as soon as a matching item is found."),
         'base': fields.selection(_price_field_get, 'Based on', required=True, size=-1, help="The mode for computing the price for this rule."),
-        'base_pricelist_id': fields.many2one('product.pricelist', 'If Other Pricelist'),
+        'base_pricelist_id': fields.many2one('product.pricelist', 'Other Pricelist'),
 
         'price_surcharge': fields.float('Price Surcharge',
             digits_compute= dp.get_precision('Product Price'), help='Specify the fixed amount to add or substract(if negative) to the amount calculated with the discount.'),
index 01cb4dc..a1b996b 100644 (file)
@@ -92,7 +92,7 @@
                     </group>
                     <group col="4" string="Price Computation">
                         <field name="base"/>
-                        <field name="base_pricelist_id" attrs="{'required': [('base','=', -1)], 'readonly': [('base','!=', -1)]}"/>
+                        <field name="base_pricelist_id" attrs="{'invisible':[('base', '!=', -1)],'required': [('base','=', -1)], 'readonly': [('base','!=', -1)]}"/>
                     </group>
                     <group col="6" colspan="5">
                         <label string="New Price ="/>
index b7fbcd5..74b2b86 100644 (file)
                 Click to define a new product.
               </p><p>
                 You must define a product for everything you buy or sell,
-                wether it's a physical product, a consumable or service.
+                whether it's a physical product, a consumable or service.
               </p>
             </field>
         </record>
               <p class="oe_view_nocontent_create">
                 Click to define a new product.
               </p><p>
-                You must define a product for everything you sell, wether it's
+                You must define a product for everything you sell, whether it's
                 a physical product, a consumable or a service you offer to
                 customers.
               </p><p>
               <p class="oe_view_nocontent_create">
                 Click to define a new product.
               </p><p>
-                You must define a product for everything you purchase, wheter
+                You must define a product for everything you purchase, whether
                 it's a physical product, a consumable or services you buy to
                 subcontractants.
               </p><p>
index 9a022ff..56d7fef 100644 (file)
@@ -777,7 +777,6 @@ class task(base_stage, osv.osv):
     _defaults = {
         'stage_id': _get_default_stage_id,
         'project_id': _get_default_project_id,
-        'state': 'draft',
         'kanban_state': 'normal',
         'priority': '2',
         'progress': 0,
@@ -1030,7 +1029,6 @@ class task(base_stage, osv.osv):
                 'user_id': delegate_data['user_id'] and delegate_data['user_id'][0] or False,
                 'planned_hours': delegate_data['planned_hours'] or 0.0,
                 'parent_ids': [(6, 0, [task.id])],
-                'state': 'draft',
                 'description': delegate_data['new_task_description'] or '',
                 'child_ids': [],
                 'work_ids': []
index 249fb3e..0de5e17 100644 (file)
@@ -26,7 +26,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_project_project"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_project_unread" model="ir.values">
             <field name="name">action_project_unread</field>
@@ -44,7 +44,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_project_project"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_project_read" model="ir.values">
             <field name="name">action_project_read</field>
                                     <field name="resource_calendar_id"/>
                                 </group>
                                 <group string="Miscellaneous" name="misc">
+                                    <field name="date_start"/>
                                     <field name="date" string="End Date"/>
                                     <field name="priority" groups="base.group_no_one"/>
                                     <field name="active" attrs="{'invisible':[('state','in',['open', 'pending', 'template'])]}"/>
                                 </group>
                             </group>
                         </page>
-                        <page string="Tasks Stages">
+                        <page string="Tasks Stages" attrs="{'invisible': [('use_tasks', '=', False)]}">
                              <field name="type_ids"/>
                         </page>
                     </notebook>
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_project_task"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_project_task_unread" model="ir.values">
             <field name="name">action_project_task_unread</field>
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_project_task"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_project_task_read" model="ir.values">
             <field name="name">action_project_task_read</field>
             <field name="arch" type="xml">
                 <form string="Project" version="7.0">
                     <header>
-                        <span groups="base.group_user">
-                            <!--
-                            <button name="do_open" string="Start Task" type="object"
-                                    states="draft,pending" class="oe_highlight"/>
-                            <button name="do_draft" string="Draft" type="object"
-                                    states="cancel,done"/>
-                            -->
-                            <button name="%(action_project_task_reevaluate)d" string="Reactivate" type="action"
-                                    states="cancelled,done" context="{'button_reactivate':True}"/>
-                            <button name="action_close" string="Done" type="object"
-                                    states="draft,open,pending"/>
-                            <button name="do_cancel" string="Cancel" type="object"
-                                    states="draft,open,pending"/>
-                        </span>
+                        <!--
+                        <button name="do_open" string="Start Task" type="object"
+                                states="draft,pending" class="oe_highlight"/>
+                        <button name="do_draft" string="Draft" type="object"
+                                states="cancel,done"/>
+                        -->
+                        <button name="%(action_project_task_reevaluate)d" string="Reactivate" type="action"
+                                states="cancelled,done" context="{'button_reactivate':True}" groups="base.group_user"/>
+                        <button name="action_close" string="Done" type="object"
+                                states="draft,open,pending" groups="base.group_user"/>
+                        <button name="do_cancel" string="Cancel" type="object"
+                                states="draft,open,pending" groups="base.group_user"/>
                         <field name="stage_id" widget="statusbar" clickable="True"/>
                     </header>
                     <sheet string="Task">
                             <field name="description" attrs="{'readonly':[('state','=','done')]}" placeholder="Add a Description..."/>
                             <field name="work_ids" groups="project.group_tasks_work_on_tasks">
                                 <tree string="Task Work" editable="top">
-                                    <field name="date"/>
                                     <field name="name"/>
-                                    <field name="user_id"/>
                                     <field name="hours" widget="float_time" sum="Spent Hours"/>
+                                    <field name="date"/>
+                                    <field name="user_id"/>
                                 </tree>
                             </field>
                             <group>
         <menuitem action="open_task_type_form" name="Task Stages" id="menu_task_types_view" parent="base.menu_project_config_project" sequence="2"/>
         <menuitem action="open_view_project_all" id="menu_projects" name="Projects" parent="menu_project_management" sequence="1"/>
 
-        <act_window context="{'search_default_user_id': active_id, 'default_user_id': active_id}" id="act_res_users_2_project_project" name="User's projects" res_model="project.project" src_model="res.users" view_mode="tree,form" view_type="form"/>
 
          <record id="task_company" model="ir.ui.view">
             <field name="name">res.company.task.config</field>
index 9e43407..1cb5b20 100644 (file)
@@ -275,7 +275,6 @@ class project_issue(base_stage, osv.osv):
         'active': 1,
         'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
         'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
-        'state': 'draft',
         'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
         'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
         'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
@@ -332,7 +331,7 @@ class project_issue(base_stage, osv.osv):
             })
             vals = {
                 'task_id': new_task_id,
-                'state':'pending'
+                'stage_id': self.stage_find(cr, uid, [bug], bug.project_id.id, [('state', '=', 'pending')], context=context),
             }
             self.convert_to_task_send_note(cr, uid, [bug.id], context=context)
             case_obj.write(cr, uid, [bug.id], vals, context=context)
index 4cd9e2c..6ff5388 100644 (file)
@@ -11,7 +11,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_project_issue"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_project_issue_unread" model="ir.values">
             <field name="name">action_project_issue_unread</field>
@@ -29,7 +29,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_project_issue"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_project_issue_read" model="ir.values">
             <field name="name">action_project_issue_read</field>
             <field name="arch" type="xml">
                 <form string="Issue" version="7.0">
                 <header>
-                    <span groups="base.group_user">
-                        <button name="case_close" string="Done" type="object"
-                                states="open"/>
-                         <button name="case_close" string="Done" type="object"
-                                states="draft,pending"/>
-                        <button name="case_cancel" string="Cancel" type="object"
-                                states="draft,open,pending"/>
-                    </span>
+                    <button name="case_close" string="Done" type="object" 
+                            states="open" groups="base.group_user"/>
+                    <button name="case_close" string="Done" type="object"
+                            states="draft,pending" groups="base.group_user"/>
+                    <button name="case_cancel" string="Cancel" type="object"
+                            states="draft,open,pending" groups="base.group_user"/>
                     <field name="stage_id" widget="statusbar" clickable="True"/>
                 </header>
                 <sheet string="Issue">
index 12fac78..7963c30 100644 (file)
@@ -46,12 +46,15 @@ class project_project(osv.osv):
 
     def open_timesheets(self, cr, uid, ids, context=None):
         """ open Timesheets view """
+        mod_obj = self.pool.get('ir.model.data')
+        act_obj = self.pool.get('ir.actions.act_window')
+
         project = self.browse(cr, uid, ids[0], context)
         view_context = {
             'search_default_account_id': [project.analytic_account_id.id],
             'default_account_id': project.analytic_account_id.id,
         }
-        help = _("""<p class="oe_view_nocontent_create">Record your timesheets for the project '%s'.</p>""")
+        help = _("""<p class="oe_view_nocontent_create">Record your timesheets for the project '%s'.</p>""") % (project.name,)
         try:
             if project.to_invoice and project.partner_id:
                 help+= _("""<p>Timesheets on this project may be invoiced to %s, according to the terms defined in the contract.</p>""" ) % (project.partner_id.name,)
@@ -59,16 +62,13 @@ class project_project(osv.osv):
             # if the user do not have access rights on the partner
             pass
 
-        return {
-            'type': 'ir.actions.act_window',
-            'name': _('Timesheets'),
-            'res_model': 'hr.analytic.timesheet',
-            'view_type': 'form',
-            'view_mode': 'tree,form',
-            'context': view_context,
-            'nodestroy': True,
-            'help': help
-        }
+        res = mod_obj.get_object_reference(cr, uid, 'hr_timesheet', 'act_hr_timesheet_line_evry1_all_form')
+        id = res and res[1] or False
+        result = act_obj.read(cr, uid, [id], context=context)[0]
+        result['name'] = _('Timesheets')
+        result['context'] = view_context
+        result['help'] = help
+        return result
 
 project_project()
 
@@ -272,6 +272,16 @@ res_partner()
 class account_analytic_line(osv.osv):
    _inherit = "account.analytic.line"
 
+   def get_product(self, cr, uid, context=None):
+        emp_obj = self.pool.get('hr.employee')
+        emp_ids = emp_obj.search(cr, uid, [('user_id', '=', uid)], context=context)
+        if emp_ids:
+            employee = emp_obj.browse(cr, uid, emp_ids, context=context)[0]
+            if employee.product_id:return employee.product_id.id
+        return False
+   
+   _defaults = {'product_id': get_product,}
+   
    def on_change_account_id(self, cr, uid, ids, account_id):
        res = {}
        if not account_id:
index c7d6ab1..a4e2a38 100644 (file)
@@ -71,7 +71,7 @@
             <field name="inherit_id" ref="account.view_account_analytic_line_tree"/>
             <field name="arch" type="xml">
                 <field name="account_id"  position="replace">
-                    <field name="account_id" string="Analytic account/project"/>
+                    <field name="account_id" string="Analytic account/project" on_change="on_change_account_id(account_id)"/>
                 </field>
             </field>
         </record>
index 4d273d9..1ec1cd4 100644 (file)
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_purchase_order"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_purchase_order_unread" model="ir.values">
             <field name="name">action_purchase_order_unread</field>
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_purchase_order"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_purchase_order_read" model="ir.values">
             <field name="name">action_purchase_order_read</field>
                     <button name="picking_ok" states="except_picking" string="Manually Corrected"/>
                     <button name="invoice_ok" states="except_invoice" string="Manually Corrected"/>
                     <button name="purchase_approve" states="confirmed" string="Approve Order" class="oe_highlight" groups="purchase.group_purchase_manager"/>
-                    <button name="view_invoice" string="Receive Invoice" type="object" attrs="{'invisible': ['|', ('invoice_method','=','picking'), '|', ('state','!=', 'approved'), ('invoiced','=',True) ]}" class="oe_highlight"/>
                     <button name="view_picking" string="Receive Products" type="object" attrs="{'invisible': ['|', ('shipped','=',True), ('state','!=', 'approved')]}" class="oe_highlight"/>
+                    <button name="view_invoice" string="Receive Invoice" type="object" attrs="{'invisible': ['|', ('invoice_method','=','picking'), '|', ('state','!=', 'approved'), ('invoiced','=',True) ]}" class="oe_highlight"/>
                     <button name="action_cancel_draft" states="cancel,sent,confirmed" string="Set to Draft" type="object" />
                     <button name="purchase_cancel" states="draft,confirmed,sent" string="Cancel"/>
                     <field name="state" widget="statusbar" statusbar_visible="draft,sent,approved,done" statusbar_colors='{"except_picking":"red","except_invoice":"red","confirmed":"blue"}' readonly="1"/>
index 7a7f5e8..a5192a8 100644 (file)
@@ -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: 2012-05-10 18:26+0000\n"
+"PO-Revision-Date: 2012-10-23 18:55+0000\n"
 "Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
 "Language-Team: Russian <ru@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-10-19 05:30+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-10-24 04:55+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
 
 #. module: resource
 #: help:resource.calendar.leaves,resource_id:0
@@ -107,7 +107,7 @@ msgstr "Рабочее время начнется с"
 #. module: resource
 #: constraint:resource.calendar.leaves:0
 msgid "Error! leave start-date must be lower then leave end-date."
-msgstr ""
+msgstr "Ошибка! Дата начала отгула должна быть раньше даты завершения."
 
 #. module: resource
 #: model:ir.model,name:resource.model_resource_calendar
@@ -324,7 +324,7 @@ msgstr "(отпуск)"
 #: code:addons/resource/resource.py:392
 #, python-format
 msgid "Configuration Error!"
-msgstr ""
+msgstr "Ошибка конфигурации!"
 
 #. module: resource
 #: selection:resource.resource,resource_type:0
index e562e41..ee50143 100644 (file)
@@ -7,14 +7,13 @@ msgstr ""
 "Project-Id-Version: OpenERP Server 6.0dev\n"
 "Report-Msgid-Bugs-To: support@openerp.com\n"
 "POT-Creation-Date: 2012-09-20 07:29+0000\n"
-"PO-Revision-Date: 2012-05-10 17:41+0000\n"
-"Last-Translator: NOVOTRADE RENDSZERHÁZ ( novotrade.hu ) "
-"<openerp@novotrade.hu>\n"
+"PO-Revision-Date: 2012-10-19 17:22+0000\n"
+"Last-Translator: Herczeg Péter <herczegp@gmail.com>\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-10-19 05:11+0000\n"
+"X-Launchpad-Export-Date: 2012-10-20 05:07+0000\n"
 "X-Generator: Launchpad (build 16165)\n"
 
 #. module: sale
@@ -400,7 +399,7 @@ msgstr "Rendelés"
 #. module: sale
 #: field:sale.order,message_ids:0
 msgid "Messages"
-msgstr ""
+msgstr "Üzenetek"
 
 #. module: sale
 #: selection:sale.report,month:0
@@ -634,7 +633,7 @@ msgstr "Megerősítés"
 #. module: sale
 #: view:sale.order:0
 msgid "Unread messages"
-msgstr ""
+msgstr "Olvasatlan üzenetek"
 
 #. module: sale
 #: field:sale.order,partner_shipping_id:0
@@ -672,7 +671,7 @@ msgstr ""
 #. module: sale
 #: field:sale.order,message_unread:0
 msgid "Unread Messages"
-msgstr ""
+msgstr "Olvasatlan üzenetek"
 
 #. module: sale
 #: view:sale.order:0
@@ -1105,7 +1104,7 @@ msgstr ""
 #. module: sale
 #: model:ir.model,name:sale.model_mail_message
 msgid "Message"
-msgstr ""
+msgstr "Üzenet"
 
 #. module: sale
 #: field:sale.config.settings,module_warning:0
@@ -1323,7 +1322,7 @@ msgstr ""
 #. module: sale
 #: field:sale.order,message_is_follower:0
 msgid "Is a Follower"
-msgstr ""
+msgstr "követő"
 
 #. module: sale
 #: code:addons/sale/sale.py:261
@@ -1638,7 +1637,7 @@ msgstr "Mégsem"
 #. module: sale
 #: field:sale.order,message_follower_ids:0
 msgid "Followers"
-msgstr ""
+msgstr "Követők"
 
 #. module: sale
 #: code:addons/sale/sale.py:947
@@ -2012,7 +2011,7 @@ msgstr ""
 #. module: sale
 #: help:sale.order,message_ids:0
 msgid "Messages and communication history"
-msgstr ""
+msgstr "Üzenetek és kommunikáció történet"
 
 #. module: sale
 #: view:sale.order:0
index 46158f9..bf590d7 100644 (file)
@@ -7,14 +7,14 @@ msgstr ""
 "Project-Id-Version: OpenERP Server 6.0dev_rc3\n"
 "Report-Msgid-Bugs-To: support@openerp.com\n"
 "POT-Creation-Date: 2012-09-20 07:29+0000\n"
-"PO-Revision-Date: 2010-12-14 21:49+0000\n"
-"Last-Translator: qdp (OpenERP) <qdp-launchpad@tinyerp.com>\n"
+"PO-Revision-Date: 2012-10-22 17:52+0000\n"
+"Last-Translator: ignas <ignassladkevicius@yahoo.com>\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-10-19 05:12+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-10-23 04:48+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
 
 #. module: sale
 #: code:addons/sale/wizard/sale_make_invoice_advance.py:215
@@ -160,14 +160,14 @@ msgstr ""
 #. module: sale
 #: field:sale.order,date_confirm:0
 msgid "Confirmation Date"
-msgstr ""
+msgstr "Patvirtinimo data"
 
 #. module: sale
 #: view:sale.order:0
 #: view:sale.order.line:0
 #: view:sale.report:0
 msgid "Group By..."
-msgstr ""
+msgstr "Grupuoti pagal..."
 
 #. module: sale
 #: view:sale.order.line:0
@@ -322,7 +322,7 @@ msgstr ""
 #. module: sale
 #: help:sale.order,amount_total:0
 msgid "The total amount."
-msgstr ""
+msgstr "Bendra suma."
 
 #. module: sale
 #: view:sale.report:0
@@ -652,7 +652,7 @@ msgstr ""
 #: view:board.board:0
 #: model:ir.actions.act_window,name:sale.action_turnover_by_month
 msgid "Monthly Turnover"
-msgstr ""
+msgstr "Mėnesinė apyvarta"
 
 #. module: sale
 #: view:sale.report:0
@@ -716,7 +716,7 @@ msgstr "Bendra kaina"
 #. module: sale
 #: model:ir.actions.act_window,name:sale.action_order_tree
 msgid "Old Quotations"
-msgstr ""
+msgstr "Seni pasiūlymai"
 
 #. module: sale
 #: help:sale.config.settings,module_sale_journal:0
@@ -816,7 +816,7 @@ msgstr "Iš viso :"
 #. module: sale
 #: view:sale.report:0
 msgid "My Sales"
-msgstr ""
+msgstr "Mano pardavimai"
 
 #. module: sale
 #: code:addons/sale/sale.py:253
@@ -1233,7 +1233,7 @@ msgstr "Grupuoti sąskaitas faktūras"
 #. module: sale
 #: help:sale.order,amount_tax:0
 msgid "The tax amount."
-msgstr ""
+msgstr "Mokesčiai"
 
 #. module: sale
 #: view:sale.order:0
@@ -1252,7 +1252,7 @@ msgstr ""
 #. module: sale
 #: selection:sale.report,month:0
 msgid "August"
-msgstr ""
+msgstr "Rugpjūtis"
 
 #. module: sale
 #: view:sale.order:0
@@ -1282,7 +1282,7 @@ msgstr ""
 #. module: sale
 #: selection:sale.report,month:0
 msgid "June"
-msgstr ""
+msgstr "Birželis"
 
 #. module: sale
 #: model:ir.actions.act_window,name:sale.action_email_templates
@@ -1559,7 +1559,7 @@ msgstr ""
 #: view:sale.report:0
 #: field:sale.report,day:0
 msgid "Day"
-msgstr ""
+msgstr "Diena"
 
 #. module: sale
 #: view:sale.order:0
@@ -1830,7 +1830,7 @@ msgstr ""
 #. module: sale
 #: view:sale.order:0
 msgid "Other Information"
-msgstr ""
+msgstr "Kita informacija"
 
 #. module: sale
 #: view:res.partner:0
index b689b1b..a67f7c7 100644 (file)
@@ -7,14 +7,14 @@ msgstr ""
 "Project-Id-Version: OpenERP Server 6.0dev\n"
 "Report-Msgid-Bugs-To: support@openerp.com\n"
 "POT-Creation-Date: 2012-09-20 07:29+0000\n"
-"PO-Revision-Date: 2012-09-10 14:56+0000\n"
+"PO-Revision-Date: 2012-10-23 18:53+0000\n"
 "Last-Translator: Chertykov Denis <chertykov@gmail.com>\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-10-19 05:12+0000\n"
-"X-Generator: Launchpad (build 16165)\n"
+"X-Launchpad-Export-Date: 2012-10-24 04:55+0000\n"
+"X-Generator: Launchpad (build 16179)\n"
 
 #. module: sale
 #: code:addons/sale/wizard/sale_make_invoice_advance.py:215
@@ -235,7 +235,7 @@ msgstr "В счет"
 #: view:sale.order.line:0
 #: field:sale.report,product_uom:0
 msgid "Unit of Measure"
-msgstr ""
+msgstr "Единицы измерения"
 
 #. module: sale
 #: help:sale.order,date_confirm:0
@@ -264,7 +264,7 @@ msgstr ""
 #. module: sale
 #: selection:sale.advance.payment.inv,advance_payment_method:0
 msgid "Invoice the whole sale order"
-msgstr ""
+msgstr "Выставить счет на весь заказ продажи"
 
 #. module: sale
 #: field:sale.order,project_id:0
@@ -304,12 +304,12 @@ msgstr "Исключение счета"
 #. module: sale
 #: view:account.config.settings:0
 msgid "0"
-msgstr ""
+msgstr "0"
 
 #. module: sale
 #: selection:sale.order,state:0
 msgid "Draft Quotation"
-msgstr ""
+msgstr "Черновик предложения"
 
 #. module: sale
 #: code:addons/sale/wizard/sale_make_invoice_advance.py:124
@@ -359,23 +359,23 @@ msgstr "Вес"
 #. module: sale
 #: view:sale.config.settings:0
 msgid "Warehouse Features"
-msgstr ""
+msgstr "Особенности склада"
 
 #. module: sale
 #: view:sale.order:0
 msgid "Quotation "
-msgstr ""
+msgstr "Предложение "
 
 #. module: sale
 #: field:sale.order.line,product_uom:0
 msgid "Unit of Measure "
-msgstr ""
+msgstr "Единица измерения "
 
 #. module: sale
 #: code:addons/sale/wizard/sale_make_invoice_advance.py:148
 #, python-format
 msgid "Incorrect Data"
-msgstr ""
+msgstr "Неверные данные"
 
 #. module: sale
 #: code:addons/sale/wizard/sale_make_invoice_advance.py:149
@@ -401,7 +401,7 @@ msgstr "Заказ"
 #. module: sale
 #: field:sale.order,message_ids:0
 msgid "Messages"
-msgstr ""
+msgstr "Сообщения"
 
 #. module: sale
 #: selection:sale.report,month:0
@@ -422,7 +422,7 @@ msgstr "Сумма до налогов"
 #. module: sale
 #: field:sale.config.settings,module_project:0
 msgid "Project"
-msgstr ""
+msgstr "Проект"
 
 #. module: sale
 #: code:addons/sale/sale.py:319
@@ -433,7 +433,7 @@ msgstr ""
 #: code:addons/sale/wizard/sale_make_invoice_advance.py:123
 #, python-format
 msgid "Error!"
-msgstr ""
+msgstr "Ошибка!"
 
 #. module: sale
 #: report:sale.order:0
@@ -467,7 +467,7 @@ msgstr "Позиции заказа продаж относящиеся к мо
 #. module: sale
 #: selection:sale.order,state:0
 msgid "Quotation Sent"
-msgstr ""
+msgstr "Предложение отправлено"
 
 #. module: sale
 #: help:sale.order,message_unread:0
@@ -528,12 +528,12 @@ msgstr "Налог"
 #: code:addons/sale/sale.py:986
 #, python-format
 msgid "Invalid Action!"
-msgstr ""
+msgstr "Неверное действие!"
 
 #. module: sale
 #: view:sale.report:0
 msgid "Reference Unit of Measure"
-msgstr ""
+msgstr "Базовая единица измерения"
 
 #. module: sale
 #: field:sale.report,date_confirm:0
@@ -572,7 +572,7 @@ msgstr "Факс :"
 #. module: sale
 #: view:sale.order:0
 msgid "(update)"
-msgstr ""
+msgstr "(обновление)"
 
 #. module: sale
 #: help:sale.config.settings,group_discount_per_so_line:0
@@ -635,7 +635,7 @@ msgstr "Подтвердить"
 #. module: sale
 #: view:sale.order:0
 msgid "Unread messages"
-msgstr ""
+msgstr "Непрочитанные сообщения"
 
 #. module: sale
 #: field:sale.order,partner_shipping_id:0
@@ -673,12 +673,12 @@ msgstr "Заказы продаж, которые еще не были подт
 #. module: sale
 #: field:sale.order,message_unread:0
 msgid "Unread Messages"
-msgstr ""
+msgstr "Непрочитанные сообщения"
 
 #. module: sale
 #: view:sale.order:0
 msgid "Print"
-msgstr ""
+msgstr "Печать"
 
 #. module: sale
 #: report:sale.order:0
@@ -793,12 +793,12 @@ msgstr "Год заказа в заказе продаж"
 #. module: sale
 #: field:sale.config.settings,module_sale_stock:0
 msgid "Sale and Warehouse Management"
-msgstr ""
+msgstr "Управление продажами и складом"
 
 #. module: sale
 #: model:ir.model,name:sale.model_sale_config_settings
 msgid "sale.config.settings"
-msgstr ""
+msgstr "sale.config.settings"
 
 #. module: sale
 #: field:sale.advance.payment.inv,qtty:0
@@ -842,7 +842,7 @@ msgstr ""
 #. module: sale
 #: view:sale.config.settings:0
 msgid "Default Options"
-msgstr ""
+msgstr "Параметры по умолчанию"
 
 #. module: sale
 #: code:addons/sale/sale.py:963
@@ -850,12 +850,12 @@ msgstr ""
 #: code:addons/sale/wizard/sale_make_invoice_advance.py:142
 #, python-format
 msgid "Configuration Error!"
-msgstr ""
+msgstr "Ошибка конфигурации!"
 
 #. module: sale
 #: field:account.config.settings,group_analytic_account_for_sales:0
 msgid "Analytic accounting for sales"
-msgstr ""
+msgstr "Аналитический учет для продаж"
 
 #. module: sale
 #: view:sale.order:0
index cd0536b..58d3373 100644 (file)
@@ -76,7 +76,6 @@
             </field>
         </record>
 
-
     </data>
 </openerp>
 
index 3c984b6..9477b73 100644 (file)
@@ -719,6 +719,8 @@ class sale_order_line(osv.osv):
         'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True),
         'invoiced': fields.boolean('Invoiced', readonly=True),
         'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}),
+        'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
+         help="If 'on order', it triggers a procurement when the sale order is confirmed to create a task, purchase order or manufacturing order linked to this sale order line."),
         'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')),
         'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}),
         'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner'),
@@ -747,6 +749,7 @@ class sale_order_line(osv.osv):
         'sequence': 10,
         'invoiced': 0,
         'state': 'draft',
+        'type': 'make_to_stock',
         'price_unit': 0.0,
     }
 
index 37323bf..4d57dfc 100644 (file)
@@ -73,7 +73,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_sale_order"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_unread(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_unread(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_sale_order_unread" model="ir.values">
             <field name="name">action_sale_order_unread</field>
@@ -91,7 +91,7 @@
             <field name="type">ir.actions.server</field>
             <field name="model_id" ref="model_sale_order"/>
             <field name="state">code</field>
-            <field name="code">self.message_check_and_set_read(cr, uid, context.get('active_ids'), context=context)</field>
+            <field name="code">self.message_mark_as_read(cr, uid, context.get('active_ids'), context=context)</field>
         </record>
         <record id="action_sale_order_read" model="ir.values">
             <field name="name">action_sale_order_read</field>
             <field name="arch" type="xml">
                 <form string="Sales Order" version="7.0">
                     <header>
-                        <span groups="base.group_user">
-                            <button name="invoice_recreate" states="invoice_except" string="Recreate Invoice"/>
-                            <button name="invoice_corrected" states="invoice_except" string="Ignore Exception"/>
-                            <button name="action_quotation_send" string="Send by Mail" type="object" states="draft" class="oe_highlight"/>
-                            <button name="action_quotation_send" string="Send by Mail" type="object" states="sent"/>
-                            <button name="print_quotation" string="Print" type="object" states="draft" class="oe_highlight"/>
-                            <button name="print_quotation" string="Print" type="object" states="sent"/>
-                            <button name="action_button_confirm" states="draft" string="Confirm" type="object"/>
-                            <button name="action_button_confirm" states="sent" string="Confirm" class="oe_highlight" type="object"/>
-                            <button name="action_view_invoice" string="View Invoice" type="object" class="oe_highlight"
-                              attrs="{'invisible': [('invoice_exists', '=', False)]}"/>
-                            <button name="%(action_view_sale_advance_payment_inv)d" string="Create Invoice"
-                                type="action" states="manual" class="oe_highlight"/>
-                            <button name="cancel" states="draft,sent" string="Cancel"/>
-                            <button name="action_cancel" states="manual,progress" string="Cancel" type="object"/>
-                            <button name="invoice_cancel" states="invoice_except" string="Cancel"/>
-                        </span>
+                        <button name="invoice_recreate" states="invoice_except" string="Recreate Invoice" groups="base.group_user"/>
+                        <button name="invoice_corrected" states="invoice_except" string="Ignore Exception" groups="base.group_user"/>
+                        <button name="action_quotation_send" string="Send by Mail" type="object" states="draft" class="oe_highlight" groups="base.group_user"/>
+                        <button name="action_quotation_send" string="Send by Mail" type="object" states="sent" groups="base.group_user"/>
+                        <button name="print_quotation" string="Print" type="object" states="draft" class="oe_highlight" groups="base.group_user"/>
+                        <button name="print_quotation" string="Print" type="object" states="sent" groups="base.group_user"/>
+                        <button name="action_button_confirm" states="draft" string="Confirm" type="object" groups="base.group_user"/>
+                        <button name="action_button_confirm" states="sent" string="Confirm" class="oe_highlight" type="object" groups="base.group_user"/>
+                        <button name="action_view_invoice" string="View Invoice" type="object" class="oe_highlight"
+                            attrs="{'invisible': [('invoice_exists', '=', False)]}" groups="base.group_user"/>
+                        <button name="%(action_view_sale_advance_payment_inv)d" string="Create Invoice"
+                            type="action" states="manual" class="oe_highlight" groups="base.group_user"/>
+                        <button name="cancel" states="draft,sent" string="Cancel" groups="base.group_user"/>
+                        <button name="action_cancel" states="manual,progress" string="Cancel" type="object" groups="base.group_user"/>
+                        <button name="invoice_cancel" states="invoice_except" string="Cancel" groups="base.group_user"/>
                         <field name="state" widget="statusbar" statusbar_visible="draft,sent,invoiced,done" statusbar_colors='{"invoice_except":"red","waiting_date":"blue"}'/>
                 </header>
                 <sheet>
                                         </group>
                                         <group>
                                             <field name="tax_id" widget="many2many_tags" domain="[('parent_id','=',False),('type_tax_use','&lt;&gt;','purchase')]"/>
+                                            <field name="type"/>
                                             <field name="th_weight"/>
-
                                             <!-- we should put a config wizard for these two fields -->
                                             <field name="address_allotment_id"/>
                                         </group>
             <field name="arch" type="xml">
                 <form string="Sales Order Lines" version="7.0">
                     <header>
-                        <span groups="base.group_user">
-                            <button name="button_cancel" string="Cancel" type="object" states="confirmed,exception"/>
-                            <button name="%(action_view_sale_order_line_make_invoice)d" string="Create Invoice" type="action" attrs="{'invisible': ['|',('invoiced', '=', 1), ('state', 'not in', ('confirmed', 'draft'))]}" class="oe_highlight"/>
-                            <button name="button_done" string="Done" type="object"  attrs="{'invisible': ['|',('invoiced', '=', 0), ('state', 'not in', ('confirmed', 'exception'))]}" class="oe_highlight"/>
-                        </span>
+                        <button name="button_cancel" string="Cancel" type="object" states="confirmed,exception" groups="base.group_user"/>
+                        <button name="%(action_view_sale_order_line_make_invoice)d" string="Create Invoice" type="action" attrs="{'invisible': ['|',('invoiced', '=', 1), ('state', 'not in', ('confirmed', 'draft'))]}" class="oe_highlight" groups="base.group_user"/>
+                        <button name="button_done" string="Done" type="object"  attrs="{'invisible': ['|',('invoiced', '=', 0), ('state', 'not in', ('confirmed', 'exception'))]}" class="oe_highlight" groups="base.group_user"/>
                         <field name="state" widget="statusbar" statusbar_visible="draft,confirmed,done" statusbar_colors='{"exception":"red","cancel":"red"}'/>
                     </header>
                     <sheet>
                     <label for="order_id" class="oe_edit_only"/>
-                    <h1><field name="order_id"/></h1>
+                    <h1><field name="order_id" domain="[('state','!=','done')]"/></h1>
                     <label for="order_partner_id" class="oe_edit_only"/>
                     <h2><field name="order_partner_id"/></h2>
                     <group>
                         <group>
-                            <field name="product_id" readonly="1"/>
+                            <field name="product_id"/>
                             <label for="product_uom_qty"/>
                             <div>
                                 <field name="product_uom_qty" readonly="1" class="oe_inline"/>
index ce68943..9611c97 100644 (file)
@@ -490,8 +490,6 @@ class sale_order_line(osv.osv):
     _columns = { 
         'delay': fields.float('Delivery Lead Time', required=True, help="Number of days between the order confirmation the shipping of the products to the customer", readonly=True, states={'draft': [('readonly', False)]}),
         'procurement_id': fields.many2one('procurement.order', 'Procurement'),
-        'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
-            help="If 'on order', it triggers a procurement when the sale order is confirmed to create a task, purchase order or manufacturing order linked to this sale order line."),
         'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]}),
         'product_packaging': fields.many2one('product.packaging', 'Packaging'),
         'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True),
@@ -499,7 +497,6 @@ class sale_order_line(osv.osv):
     }
     _defaults = {
         'delay': 0.0,
-        'type': 'make_to_stock',
         'product_packaging': False,
     }
 
index 73b9d33..668f037 100644 (file)
                            </tree>
                        </field>
                    </field>
-                   <xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='th_weight']" position="before">                   
+                   <xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='type']" position="before">                   
                        <label for="delay"/>
                        <div>
                            <field name="delay" class="oe_inline"/> days
                        </div>
-                       <field name="type"/>
                    </xpath>
                    <xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='address_allotment_id']" position="after">
                        <field name="property_ids" widget="many2many_tags"
                             groups="sale.group_mrp_properties"/>
                    </xpath>
                    <xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='tax_id']" position="before">
-                       <field name="product_packaging" context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'shop':parent.shop_id, 'uom':product_uom}" on_change="product_packaging_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, parent.partner_id, product_packaging, True, context)" domain="[('product_id','=',product_id)]" groups="product.group_stock_packaging" colspan="3"/>
+                       <field name="product_packaging" context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'shop':parent.shop_id, 'uom':product_uom}" on_change="product_packaging_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, parent.partner_id, product_packaging, True, context)" domain="[('product_id','=',product_id)]" groups="product.group_stock_packaging"  />
                    </xpath>
                    <xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/div/field[@name='invoice_lines']" position="after">
                        <label for="move_ids"/>
index c9f8a03..f052c45 100644 (file)
@@ -5,6 +5,7 @@
     <record id="group_stock_user" model="res.groups">
         <field name="name">User</field>
         <field name="category_id" ref="base.module_category_warehouse_management"/>
+        <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
     </record>
     <record id="group_stock_manager" model="res.groups">
         <field name="name">Manager</field>
index 3294251..806c723 100644 (file)
             <field name="arch" type="xml">
                 <form string="Internal Picking List" version="7.0">
                 <header>
-                    <span groups="base.group_user">
-                        <button name="draft_force_assign" states="draft" string="Confirm" type="object" class="oe_highlight"/>
-                        <button name="draft_validate" states="draft" string="Confirm &amp; Transfer" type="object" class="oe_highlight"/>
-                        <!-- <button name="action_assign" states="confirmed" string="Check Availability" type="object"/> -->
-                        <button name="force_assign" states="confirmed" string="Force Availability" type="object" class="oe_highlight"/>
-                        <button name="action_process" states="assigned" string="Confirm &amp; Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight"/>
-                        <button name="%(action_stock_invoice_onshipping)d" string="Create Invoice/Refund"  attrs="{'invisible': ['|','|',('state','&lt;&gt;','done'),('invoice_state','=','invoiced'),('invoice_state','=','none')]}"  type="action" class="oe_highlight"/>
-                        <button name="%(act_stock_return_picking)d" string="Reverse Transfer" states="done" type="action"/>
-                        <button name="button_cancel" states="assigned,confirmed,draft" string="_Cancel"/>
-                    </span>
+                    <button name="draft_force_assign" states="draft" string="Confirm" type="object" class="oe_highlight" groups="base.group_user"/>
+                    <button name="draft_validate" states="draft" string="Confirm &amp; Transfer" type="object" class="oe_highlight" groups="base.group_user"/>
+                    <!-- <button name="action_assign" states="confirmed" string="Check Availability" type="object"/> -->
+                    <button name="force_assign" states="confirmed" string="Force Availability" type="object" class="oe_highlight" groups="base.group_user"/>
+                    <button name="action_process" states="assigned" string="Confirm &amp; Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight"/>
+                    <button name="%(action_stock_invoice_onshipping)d" string="Create Invoice/Refund"  attrs="{'invisible': ['|','|',('state','&lt;&gt;','done'),('invoice_state','=','invoiced'),('invoice_state','=','none')]}"  type="action" class="oe_highlight" groups="base.group_user"/>
+                    <button name="%(act_stock_return_picking)d" string="Reverse Transfer" states="done" type="action" groups="base.group_user"/>
+                    <button name="button_cancel" states="assigned,confirmed,draft" string="_Cancel" groups="base.group_user"/>
                     <field name="state" widget="statusbar" statusbar_visible="draft,assigned,done" statusbar_colors='{"shipping_except":"red","invoice_except":"red","waiting_date":"blue"}'/>
                 </header>
                 <sheet>
             <field name="arch" type="xml">
             <form string="Stock Moves" version="7.0">
                 <header>
-                    <span groups="base.group_user">
-                        <button name="force_assign" states="confirmed" string="Force Availability" type="object"/>
-                        <button name="action_confirm" states="draft" string="Confirm" type="object"/>
-                        <button name="cancel_assign" states="assigned" string="Cancel Availability" type="object"/>
-                    </span>
+                        <button name="force_assign" states="confirmed" string="Force Availability" type="object" groups="base.group_user"/>
+                        <button name="action_confirm" states="draft" string="Confirm" type="object" groups="base.group_user"/>
+                        <button name="cancel_assign" states="assigned" string="Cancel Availability" type="object" groups="base.group_user"/>
                         <field name="state" widget="statusbar" statusbar_visible="draft,assigned,done"/>
                 </header>
                 <group>
index d011400..b57f778 100644 (file)
@@ -77,6 +77,7 @@ class survey(osv.osv):
         'tot_comp_survey': lambda * a: 0,
         'send_response': lambda * a: 1,
         'response_user': lambda * a:1,
+        'date_open': fields.datetime.now,
     }
 
     def survey_open(self, cr, uid, ids, arg):
@@ -151,8 +152,7 @@ class survey(osv.osv):
             pages = sur['page_ids']
             if not pages:
                 raise osv.except_osv(_('Warning!'), _('This survey has no question defined. Please define the questions and answers first.'))
-            else:
-                context.update({'active':False,'survey_id': ids[0]})
+            context.update({'active':False,'survey_id': ids[0]})
         return {
             'view_type': 'form',
             'view_mode': 'form',
@@ -163,9 +163,12 @@ class survey(osv.osv):
             'context': context
         }
     def test_survey(self, cr, uid, ids, context=None):
-        sur_obj = self.read(cr, uid, ids,['title'], context=context)
+        sur_obj = self.read(cr, uid, ids,['title','page_ids'], context=context)
         for sur in sur_obj:
             name = sur['title']
+            pages = sur['page_ids']
+            if not pages:
+                raise osv.except_osv(_('Warning!'), _('This survey has no pages defined. Please define pages first.'))
             context.update({'active':True,'survey_id': ids[0]})
         return {
             'view_type': 'form',
index 0247a20..c01e8b4 100644 (file)
                     <div class="oe_title">
                         <label for="title" class="oe_edit_only"/>
                         <h1>
-                            <field name="title"/>
+                            <field name="title" attrs="{'readonly':[('state','=','close')]}"/>
                         </h1>
                     </div>
                     <group>
                         <group>
                             <field name="id" invisible="1"/>
-                            <field name="responsible_id" class="oe_inline"/>
-                            <field name="send_response"/>
-                            <field name="type"/>
+                            <field name="responsible_id" class="oe_inline" attrs="{'readonly':[('state','=','close')]}"/>
+                            <field name="send_response" attrs="{'readonly':[('state','=','close')]}"/>
+                            <field name="type" attrs="{'readonly':[('state','=','close')]}"/>
                         </group>
                         <group>
-                            <field name="max_response_limit" attrs="{'readonly':[('state','in',('open','close'))]}"/>
-                            <field name="response_user" attrs="{'readonly':[('state','in',('open','close'))]}"/>
+                            <field name="max_response_limit" attrs="{'readonly':[('state','=','close')]}"/>
+                            <field name="response_user" attrs="{'readonly':[('state','=','close')]}"/>
                         </group>
                      </group>
                      <notebook>
                         <page string="Survey Details">
-                            <field name="page_ids" colspan="4" mode="tree">
+                            <field name="page_ids" colspan="4" mode="tree" attrs="{'readonly':[('state','=','close')]}">
                                 <form string="Survey Page" version="7.0">
                                     <sheet>
                                     <label for="title" class="oe_edit_only"/>
                                     </sheet>
                                     </form>
                                 </field>
-                            <field name="note" placeholder="Survey description..."/>
+                            <field name="note" placeholder="Survey description..." attrs="{'readonly':[('state','=','close')]}"/>
                         </page>
                         <page string="Invited User">
                             <field name="invited_user_ids" readonly="1"/>
index 8ece1e1..f1a96fa 100644 (file)
@@ -134,6 +134,8 @@ class survey_question_wiz(osv.osv_memory):
                         page_number += 1
                     if sur_name_rec.page_no > - 1:
                         pre_button = True
+                    else:
+                        flag = True
                 else:
                     if sur_name_rec.page_no != 0:
                         p_id = p_id[sur_name_rec.page_no - 1]
@@ -146,7 +148,15 @@ class survey_question_wiz(osv.osv_memory):
                         pre_button = True
                 if flag:
                     pag_rec = page_obj.browse(cr, uid, p_id, context=context)
-                    xml_form = etree.Element('form', {'string': tools.ustr(pag_rec.title or sur_rec.title)})
+                    note = False
+                    question_ids = []
+                    if pag_rec:
+                        title = pag_rec.title
+                        note = pag_rec.note
+                        question_ids = pag_rec.question_ids
+                    else:
+                        title = sur_rec.title
+                    xml_form = etree.Element('form', {'string': tools.ustr(title)})
                     if context.has_key('active') and context.get('active',False) and context.has_key('edit'):
                         context.update({'page_id' : tools.ustr(p_id),'page_number' : sur_name_rec.page_no , 'transfer' : sur_name_read.transfer})
                         xml_group3 = etree.SubElement(xml_form, 'group', {'col': '4', 'colspan': '4'})
@@ -174,10 +184,10 @@ class survey_question_wiz(osv.osv_memory):
                         fields["wizardid_" + str(wiz_id)] = {'type':'char', 'size' : 255, 'string':"", 'views':{}}
                         etree.SubElement(xml_form, 'field', {'invisible':'1','name': "wizardid_" + str(wiz_id),'default':str(lambda *a: 0),'modifiers':'{"invisible":true}'})
 
-                    if pag_rec.note:
-                        for que_test in pag_rec.note.split('\n'):
+                    if note:
+                        for que_test in note.split('\n'):
                             etree.SubElement(xml_form, 'label', {'string': to_xml(tools.ustr(que_test)), 'align':"0.0"})
-                    que_ids = pag_rec.question_ids
+                    que_ids = question_ids
                     qu_no = 0
 
                     for que in que_ids:
@@ -429,13 +439,13 @@ class survey_question_wiz(osv.osv_memory):
                                 vals['attachment_ids'] = [(0,0,{'name': a_name,
                                                                 'datas_fname': a_name,
                                                                 'datas': str(a_content).encode('base64')})
-                                                                for a_name, a_content in attachments]
+                                                                for a_name, a_content in attachments.items()]
                             self.pool.get('mail.mail').create(cr, uid, vals, context=context)
 
                     xml_form = etree.Element('form', {'string': _('Complete Survey Answer')})
                     xml_footer = etree.SubElement(xml_form, 'footer', {'col': '6', 'colspan': '4' ,'class': 'oe_survey_title_height'})
 
-                    etree.SubElement(xml_form, 'separator', {'string': 'Complete Survey', 'colspan': "4"})
+                    etree.SubElement(xml_form, 'separator', {'string': 'Survey Completed', 'colspan': "4"})
                     etree.SubElement(xml_form, 'label', {'string': 'Thanks for your Answer'})
                     etree.SubElement(xml_form, 'newline')
                     etree.SubElement(xml_footer, 'button', {'special':"cancel",'string':"OK",'colspan':"2",'class':'oe_highlight'})
index 5677a98..936e336 100644 (file)
@@ -50,9 +50,6 @@ class survey_send_invitation(osv.osv_memory):
     _defaults = {
         'send_mail': lambda *a: 1,
         'send_mail_existing': lambda *a: 1,
-        'mail_subject': lambda *a: "Invitation",
-        'mail_subject_existing': lambda *a: "Invitation",
-        'mail_from': lambda *a: tools.config['email_from']
     }
 
     def genpasswd(self):
@@ -67,14 +64,23 @@ class survey_send_invitation(osv.osv_memory):
         msg = ""
         name = ""
         for sur in survey_obj.browse(cr, uid, context.get('active_ids', []), context=context):
-            name += "\t --> " + sur.title + "\n"
+            name += "\n --> " + sur.title + "\n"
             if sur.state != 'open':
                 msg +=  sur.title + "\n"
+            data['mail_subject'] = _("Invitation for %s") % (sur.title)
+            data['mail_subject_existing'] = _("Invitation for %s") % (sur.title)
+            data['mail_from'] = sur.responsible_id.email
         if msg:
-            raise osv.except_osv(_('Warning!'), _('%sSurvey is not in open state') % msg)
-        data['mail'] = '''Hello %(name)s, \n\n We are inviting you for following survey. \
-                    \n  ''' + name + '''\n Your login ID: %(login)s, Your password: %(passwd)s
-                    \n link :- http://'''+ str(socket.gethostname()) + ''':8080 \n\n Thanks,'''
+            raise osv.except_osv(_('Warning!'), _('The following surveys are not in open state: %s') % msg)
+        data['mail'] = _('''
+Hello %%(name)s, \n\n
+Would you please spent some of your time to fill-in our survey: \n%s\n
+You can access this survey with the following parameters:
+ URL: %s
+ Your login ID: %%(login)s\n
+ Your password: %%(passwd)s\n
+\n\n
+Thanks,''') % (name, self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context))
         return data
 
     def create_report(self, cr, uid, res_ids, report_name=False, file_name=False):
@@ -176,7 +182,7 @@ class survey_send_invitation(osv.osv_memory):
                     vals['attachment_ids'] = [(0,0,{'name': a_name,
                                                     'datas_fname': a_name,
                                                     'datas': str(a_content).encode('base64')})
-                                                    for a_name, a_content in attachments]
+                                                    for a_name, a_content in attachments.items()]
                 ans = self.pool.get('mail.mail').create(cr, uid, vals, context=context)
                 if ans:
                     res_data = {'name': partner.name or _('Unknown'),
index 340cb58..a611973 100644 (file)
@@ -16,7 +16,7 @@
                     </header>
                     <group col="4">
                         <separator string="Select Partner" colspan="4"/>
-                        <field name="partner_ids" nolabel="1"  colspan="4"/>
+                        <field name="partner_ids" nolabel="1" colspan="4" widget="many2many_tags"/>
                         <separator colspan="4" string="Send Mail for New User"/>
                         <field name="send_mail" nolabel="1"/>
                         <field name="mail_subject" colspan="3"/>