diff --git a/addons/account/__init__.py b/addons/account/__init__.py index 36cc1c85b5a..a243b94c2da 100644 --- a/addons/account/__init__.py +++ b/addons/account/__init__.py @@ -35,5 +35,5 @@ import product import ir_sequence import company import res_currency - +import edi # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index 9445688ec6d..ec61248e147 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -53,7 +53,7 @@ module named account_voucher. 'website': 'http://www.openerp.com', 'images' : ['images/accounts.jpeg','images/bank_statement.jpeg','images/cash_register.jpeg','images/chart_of_accounts.jpeg','images/customer_invoice.jpeg','images/journal_entries.jpeg'], 'init_xml': [], - "depends" : ["base_setup", "product", "analytic", "process","board"], + "depends" : ["base_setup", "product", "analytic", "process", "board", "edi"], 'update_xml': [ 'security/account_security.xml', 'security/ir.model.access.csv', @@ -123,7 +123,9 @@ module named account_voucher. 'board_account_view.xml', "wizard/account_report_profit_loss_view.xml", "wizard/account_report_balance_sheet_view.xml", - "account_bank_view.xml" + "edi/invoice_action_data.xml", + "account_bank_view.xml", + "account_pre_install.yml" ], 'demo_xml': [ 'demo/account_demo.xml', @@ -145,10 +147,9 @@ module named account_voucher. 'test/account_fiscalyear_close.yml', 'test/account_bank_statement.yml', 'test/account_cash_statement.yml', + 'test/test_edi_invoice.yml', 'test/account_report.yml', - - - ], + ], 'installable': True, 'active': False, 'certificate': '0080331923549', diff --git a/addons/account/account.py b/addons/account/account.py index fed71f5aca4..e41a5f2f280 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -404,7 +404,7 @@ class account_account(osv.osv): return True _columns = { - 'name': fields.char('Name', size=128, required=True, select=True), + 'name': fields.char('Name', size=256, required=True, select=True), 'currency_id': fields.many2one('res.currency', 'Secondary Currency', help="Forces all moves for this account to have this secondary currency."), 'code': fields.char('Code', size=64, required=True, select=1), 'type': fields.selection([ @@ -431,9 +431,9 @@ class account_account(osv.osv): 'debit': fields.function(__compute, fnct_inv=_set_credit_debit, digits_compute=dp.get_precision('Account'), string='Debit', multi='balance'), 'foreign_balance': fields.function(__compute, digits_compute=dp.get_precision('Account'), string='Foreign Balance', multi='balance', help="Total amount (in Secondary currency) for transactions held in secondary currency for this account."), - 'adjusted_balance': fields.function(__compute, digits_compute=dp.get_precision('Account'), string='Adjusted Balance', multi='balance', + 'adjusted_balance': fields.function(__compute, digits_compute=dp.get_precision('Account'), string='Adjusted Balance', multi='balance', help="Total amount (in Company currency) for transactions held in secondary currency for this account."), - 'unrealized_gain_loss': fields.function(__compute, digits_compute=dp.get_precision('Account'), string='Unrealized Gain or Loss', multi='balance', + 'unrealized_gain_loss': fields.function(__compute, digits_compute=dp.get_precision('Account'), string='Unrealized Gain or Loss', multi='balance', help="Value of Loss or Gain due to changes in exchange rate when doing multi-currency transactions."), 'reconcile': fields.boolean('Allow Reconciliation', help="Check this box if this account allows reconciliation of journal items."), 'exchange_rate': fields.related('currency_id', 'rate', type='float', string='Exchange Rate', digits=(12,6)), @@ -461,7 +461,7 @@ class account_account(osv.osv): } _defaults = { - 'type': 'view', + 'type': 'other', 'reconcile': False, 'active': True, 'currency_mode': 'current', @@ -716,6 +716,19 @@ class account_journal(osv.osv): _order = 'code' + def _check_currency(self, cr, uid, ids, context=None): + for journal in self.browse(cr, uid, ids, context=context): + if journal.currency: + if journal.default_credit_account_id and not journal.default_credit_account_id.currency_id.id == journal.currency.id: + return False + if journal.default_debit_account_id and not journal.default_debit_account_id.currency_id.id == journal.currency.id: + return False + return True + + _constraints = [ + (_check_currency, 'Configuration error! The currency chosen should be shared by the default accounts too.', ['currency','default_debit_account_id','default_credit_account_id']), + ] + def copy(self, cr, uid, id, default={}, context=None, done_list=[], local=False): journal = self.browse(cr, uid, id, context=context) if not default: @@ -846,21 +859,8 @@ class account_fiscalyear(osv.osv): 'state': 'draft', 'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id, } - _order = "date_start" + _order = "date_start, id" - def _check_fiscal_year(self, cr, uid, ids, context=None): - current_fiscal_yr = self.browse(cr, uid, ids, context=context)[0] - obj_fiscal_ids = self.search(cr, uid, [('company_id', '=', current_fiscal_yr.company_id.id)], context=context) - obj_fiscal_ids.remove(ids[0]) - data_fiscal_yr = self.browse(cr, uid, obj_fiscal_ids, context=context) - - for old_fy in data_fiscal_yr: - if old_fy.company_id.id == current_fiscal_yr['company_id'].id: - # Condition to check if the current fiscal year falls in between any previously defined fiscal year - if old_fy.date_start <= current_fiscal_yr['date_start'] <= old_fy.date_stop or \ - old_fy.date_start <= current_fiscal_yr['date_stop'] <= old_fy.date_stop: - return False - return True def _check_duration(self, cr, uid, ids, context=None): obj_fy = self.browse(cr, uid, ids[0], context=context) @@ -869,8 +869,7 @@ class account_fiscalyear(osv.osv): return True _constraints = [ - (_check_duration, 'Error! The start date of the fiscal year must be before his end date.', ['date_start','date_stop']), - (_check_fiscal_year, 'Error! You can not define overlapping fiscal years for the same company.',['date_start', 'date_stop']) + (_check_duration, 'Error! The start date of the fiscal year must be before his end date.', ['date_start','date_stop']) ] def create_period3(self, cr, uid, ids, context=None): @@ -905,6 +904,10 @@ class account_fiscalyear(osv.osv): return True def find(self, cr, uid, dt=None, exception=True, context=None): + res = self.finds(cr, uid, dt, exception, context=context) + return res and res[0] or False + + def finds(self, cr, uid, dt=None, exception=True, context=None): if context is None: context = {} if not dt: dt = time.strftime('%Y-%m-%d') @@ -919,8 +922,8 @@ class account_fiscalyear(osv.osv): if exception: raise osv.except_osv(_('Error !'), _('No fiscal year defined for this date !\nPlease create one.')) else: - return False - return ids[0] + return [] + return ids def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80): if args is None: @@ -1683,13 +1686,15 @@ class account_tax_code(osv.osv): if context.get('state', 'all') == 'all': move_state = ('draft', 'posted', ) if context.get('fiscalyear_id', False): - fiscalyear_id = context['fiscalyear_id'] + fiscalyear_id = [context['fiscalyear_id']] else: - fiscalyear_id = self.pool.get('account.fiscalyear').find(cr, uid, exception=False) + fiscalyear_id = self.pool.get('account.fiscalyear').finds(cr, uid, exception=False) where = '' where_params = () if fiscalyear_id: - pids = map(lambda x: str(x.id), self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_id).period_ids) + pids = [] + for fy in fiscalyear_id: + pids += map(lambda x: str(x.id), self.pool.get('account.fiscalyear').browse(cr, uid, fy).period_ids) if pids: where = ' AND line.period_id IN %s AND move.state IN %s ' where_params = (tuple(pids), move_state) @@ -2003,7 +2008,7 @@ class account_tax(osv.osv): def compute_all(self, cr, uid, taxes, price_unit, quantity, address_id=None, product=None, partner=None, force_excluded=False): """ - :param force_excluded: boolean used to say that we don't want to consider the value of field price_include of + :param force_excluded: boolean used to say that we don't want to consider the value of field price_include of tax. It's used in encoding by line where you don't matter if you encoded a tax with that boolean to True or False RETURN: { @@ -2186,6 +2191,7 @@ class account_model(osv.osv): account_move_obj = self.pool.get('account.move') account_move_line_obj = self.pool.get('account.move.line') pt_obj = self.pool.get('account.payment.term') + period_obj = self.pool.get('account.period') if context is None: context = {} @@ -2193,14 +2199,14 @@ class account_model(osv.osv): if datas.get('date', False): context.update({'date': datas['date']}) - period_id = self.pool.get('account.period').find(cr, uid, dt=context.get('date', False)) - if not period_id: - raise osv.except_osv(_('No period found !'), _('Unable to find a valid period !')) - period_id = period_id[0] - move_date = context.get('date', time.strftime('%Y-%m-%d')) move_date = datetime.strptime(move_date,"%Y-%m-%d") for model in self.browse(cr, uid, ids, context=context): + ctx = context.copy() + ctx.update({'company_id': model.company_id.id}) + period_ids = period_obj.find(cr, uid, dt=context.get('date', False), context=ctx) + period_id = period_ids and period_ids[0] or False + ctx.update({'journal_id': model.journal_id.id,'period_id': period_id}) try: entry['name'] = model.name%{'year': move_date.strftime('%Y'), 'month': move_date.strftime('%m'), 'date': move_date.strftime('%Y-%m')} except: @@ -2249,9 +2255,7 @@ class account_model(osv.osv): 'date': context.get('date',time.strftime('%Y-%m-%d')), 'date_maturity': date_maturity }) - c = context.copy() - c.update({'journal_id': model.journal_id.id,'period_id': period_id}) - account_move_line_obj.create(cr, uid, val, context=c) + account_move_line_obj.create(cr, uid, val, context=ctx) return move_ids @@ -2398,7 +2402,7 @@ class account_account_template(osv.osv): _description ='Templates for Accounts' _columns = { - 'name': fields.char('Name', size=128, required=True, select=True), + 'name': fields.char('Name', size=256, required=True, select=True), 'currency_id': fields.many2one('res.currency', 'Secondary Currency', help="Forces all moves for this account to have this secondary currency."), 'code': fields.char('Code', size=64, select=1), 'type': fields.selection([ diff --git a/addons/account/account_bank.py b/addons/account/account_bank.py index 2a9e432894f..01eab2fbb01 100644 --- a/addons/account/account_bank.py +++ b/addons/account/account_bank.py @@ -42,8 +42,12 @@ class bank(osv.osv): return (bank.bank_name or '') + ' ' + bank.acc_number def post_write(self, cr, uid, ids, context={}): + if isinstance(ids, (int, long)): + ids = [ids] + obj_acc = self.pool.get('account.account') obj_data = self.pool.get('ir.model.data') + for bank in self.browse(cr, uid, ids, context): if bank.company_id and not bank.journal_id: # Find the code and parent of the bank account to create @@ -104,3 +108,5 @@ class bank(osv.osv): self.write(cr, uid, [bank.id], {'journal_id': journal_id}, context=context) return True + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml index 230078c4e33..e249f8fa872 100644 --- a/addons/account/account_installer.xml +++ b/addons/account/account_installer.xml @@ -57,7 +57,7 @@ Accounting 5 - + diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 4da3a447e38..27881bf1280 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -251,7 +251,7 @@ class account_invoice(osv.osv): 'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'journal_id': fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'company_id': fields.many2one('res.company', 'Company', required=True, change_default=True, readonly=True, states={'draft':[('readonly',False)]}), - 'check_total': fields.float('Total', digits_compute=dp.get_precision('Account'), states={'open':[('readonly',True)],'close':[('readonly',True)]}), + 'check_total': fields.float('Verification Total', digits_compute=dp.get_precision('Account'), states={'open':[('readonly',True)],'close':[('readonly',True)]}), 'reconciled': fields.function(_reconciled, string='Paid/Reconciled', type='boolean', store={ 'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ? @@ -286,6 +286,9 @@ class account_invoice(osv.osv): 'internal_number': False, 'user_id': lambda s, cr, u, c: u, } + _sql_constraints = [ + ('number_uniq', 'unique(number, company_id)', 'Invoice Number must be unique per Company!'), + ] def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False): journal_obj = self.pool.get('account.journal') @@ -795,6 +798,7 @@ class account_invoice(osv.osv): """Creates invoice related analytics and financial move lines""" ait_obj = self.pool.get('account.invoice.tax') cur_obj = self.pool.get('res.currency') + period_obj = self.pool.get('account.period') context = {} for inv in self.browse(cr, uid, ids): if not inv.journal_id.sequence_id: @@ -923,10 +927,10 @@ class account_invoice(osv.osv): 'narration':inv.comment } period_id = inv.period_id and inv.period_id.id or False + ctx.update({'company_id': inv.company_id.id}) if not period_id: - period_ids = self.pool.get('account.period').search(cr, uid, [('date_start','<=',inv.date_invoice or time.strftime('%Y-%m-%d')),('date_stop','>=',inv.date_invoice or time.strftime('%Y-%m-%d')), ('company_id', '=', inv.company_id.id)]) - if period_ids: - period_id = period_ids[0] + period_ids = period_obj.find(cr, uid, inv.date_invoice, context=ctx) + period_id = period_ids and period_ids[0] or False if period_id: move['period_id'] = period_id for i in line: diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index efc7a24031c..4cc1a63db61 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -153,7 +153,7 @@ - - + @@ -237,4 +219,28 @@ + + + \ No newline at end of file diff --git a/addons/point_of_sale/test/01_order_to_payment.yml b/addons/point_of_sale/test/01_order_to_payment.yml index fd8ffbaa3e0..7c6b4817666 100644 --- a/addons/point_of_sale/test/01_order_to_payment.yml +++ b/addons/point_of_sale/test/01_order_to_payment.yml @@ -74,7 +74,7 @@ - I click on the "Make Payment" wizard to pay the PoS order with a partial amount of 100.0 EUR - - !record {model: pos.make.payment, id: pos_make_payment_0, context: {'active_id': ref('pos_order_pos0'), 'active_ids': [ref('pos_order_pos0')]} }: + !record {model: pos.make.payment, id: pos_make_payment_0, context: '{"active_id": ref("pos_order_pos0"), "active_ids": [ref("pos_order_pos0")]}' }: amount: 100.0 - I click on the validate button to register the payment. @@ -95,7 +95,7 @@ - I pay the remaining balance. - - !record {model: pos.make.payment, id: pos_make_payment_1, context: {'active_id': [ref('pos_order_pos0')], 'active_ids': [ref('pos_order_pos0')]} }: + !record {model: pos.make.payment, id: pos_make_payment_1, context: '{"active_id": ref("pos_order_pos0"), "active_ids": [ref("pos_order_pos0")]}' }: amount: !eval > (450*2 + 300*3*1.05)*0.95-100.0 - diff --git a/addons/point_of_sale/test/02_order_to_invoice.yml b/addons/point_of_sale/test/02_order_to_invoice.yml index 3436e176678..0de4e518ebd 100644 --- a/addons/point_of_sale/test/02_order_to_invoice.yml +++ b/addons/point_of_sale/test/02_order_to_invoice.yml @@ -18,7 +18,7 @@ - I click on the "Make Payment" wizard to pay the PoS order - - !record {model: pos.make.payment, id: pos_make_payment_2, context: {'active_id': ref('pos_order_pos1'), 'active_ids': [ref('pos_order_pos1')]} }: + !record {model: pos.make.payment, id: pos_make_payment_2, context: '{"active_id": ref("pos_order_pos1"), "active_ids": [ref("pos_order_pos1")]}' }: amount: !eval > (450*2 + 300*3*1.05)*0.95 - diff --git a/addons/point_of_sale/wizard/pos_box_entries.py b/addons/point_of_sale/wizard/pos_box_entries.py index 0c48aff736f..8313b345834 100644 --- a/addons/point_of_sale/wizard/pos_box_entries.py +++ b/addons/point_of_sale/wizard/pos_box_entries.py @@ -125,3 +125,5 @@ class pos_box_entries(osv.osv_memory): pos_box_entries() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/point_of_sale/wizard/pos_box_out.py b/addons/point_of_sale/wizard/pos_box_out.py index b4298745c35..46f710c7882 100644 --- a/addons/point_of_sale/wizard/pos_box_out.py +++ b/addons/point_of_sale/wizard/pos_box_out.py @@ -110,3 +110,5 @@ class pos_box_out(osv.osv_memory): pos_box_out() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/point_of_sale/wizard/pos_payment.py b/addons/point_of_sale/wizard/pos_payment.py index adf59e3cbce..3a50ac0f7c9 100644 --- a/addons/point_of_sale/wizard/pos_payment.py +++ b/addons/point_of_sale/wizard/pos_payment.py @@ -101,3 +101,5 @@ class pos_make_payment(osv.osv_memory): pos_make_payment() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/point_of_sale/wizard/pos_payment_report_user.py b/addons/point_of_sale/wizard/pos_payment_report_user.py index 02db921618b..05d06f4df29 100644 --- a/addons/point_of_sale/wizard/pos_payment_report_user.py +++ b/addons/point_of_sale/wizard/pos_payment_report_user.py @@ -51,3 +51,5 @@ class pos_payment_report_user(osv.osv_memory): pos_payment_report_user() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/point_of_sale/wizard/pos_receipt.py b/addons/point_of_sale/wizard/pos_receipt.py index 71efee85b7c..f4feee85504 100644 --- a/addons/point_of_sale/wizard/pos_receipt.py +++ b/addons/point_of_sale/wizard/pos_receipt.py @@ -56,3 +56,5 @@ class pos_receipt(osv.osv_memory): } pos_receipt() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/portal/__init__.py b/addons/portal/__init__.py index 89397d2eab5..b35d11bac45 100644 --- a/addons/portal/__init__.py +++ b/addons/portal/__init__.py @@ -24,3 +24,5 @@ import wizard import res_user import ir_ui_menu + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/portal/i18n/cs.po b/addons/portal/i18n/cs.po index ce070425f07..3be439be9b6 100644 --- a/addons/portal/i18n/cs.po +++ b/addons/portal/i18n/cs.po @@ -8,78 +8,80 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2011-07-04 14:16+0000\n" -"PO-Revision-Date: 2011-07-11 09:51+0000\n" -"Last-Translator: FULL NAME \n" -"Language-Team: Czech \n" +"PO-Revision-Date: 2011-11-25 13:27+0000\n" +"Last-Translator: Jiří Hajda \n" +"Language-Team: Czech \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-05 05:57+0000\n" -"X-Generator: Launchpad (build 14231)\n" +"X-Launchpad-Export-Date: 2011-11-26 05:50+0000\n" +"X-Generator: Launchpad (build 14381)\n" +"X-Poedit-Language: Czech\n" #. module: portal #: code:addons/portal/wizard/share_wizard.py:55 #, python-format msgid "Please select at least one user to share with" -msgstr "" +msgstr "Prosíme vyberte nejméně jednoho uživatele, s kterým chcete sdílet" #. module: portal #: code:addons/portal/wizard/share_wizard.py:59 #, python-format msgid "Please select at least one group to share with" -msgstr "" +msgstr "Prosíme vyberte nejméně jednu skupinu, s kterou chcete sdílet" #. module: portal #: field:res.portal,group_id:0 msgid "Group" -msgstr "" +msgstr "Skupina" #. module: portal #: help:res.portal,other_group_ids:0 msgid "Those groups are assigned to the portal's users" -msgstr "" +msgstr "Tyto skupiny jsou přiřazeny k uživatelům portálu" #. module: portal #: view:share.wizard:0 #: field:share.wizard,group_ids:0 msgid "Existing groups" -msgstr "" +msgstr "Existující skupiny" #. module: portal #: model:ir.model,name:portal.model_res_portal_wizard_user msgid "Portal User Config" -msgstr "" +msgstr "Nastavení uživatele portálu" #. module: portal #: view:res.portal.wizard.user:0 msgid "Portal User" -msgstr "" +msgstr "Uživatel portálu" #. module: portal #: help:res.portal,override_menu:0 msgid "Enable this option to override the Menu Action of portal users" -msgstr "" +msgstr "Povolte tuto volbu k přepsání Akcí nabídky uživatelů portálu" #. module: portal #: field:res.portal.wizard.user,user_email:0 msgid "E-mail" -msgstr "" +msgstr "E-mail" #. module: portal #: view:res.portal:0 msgid "Other Groups assigned to Users" -msgstr "" +msgstr "Jiné skupiny přiřazené uživatelům" #. module: portal #: constraint:res.users:0 msgid "The chosen company is not in the allowed companies for this user" msgstr "" +"Vybraná společnost není v povolených společnostech pro tohoto uživatele" #. module: portal #: view:res.portal:0 #: field:res.portal,widget_ids:0 msgid "Widgets" -msgstr "" +msgstr "Udělátka" #. module: portal #: model:ir.module.module,description:portal.module_meta_information @@ -99,71 +101,85 @@ msgid "" "module 'share'.\n" " " msgstr "" +"\n" +"Tento modul určuje 'portály' k přizpůsobení přístupu k vaší databázi " +"OpenERP\n" +"pro vnější uživatele.\n" +"\n" +"Portál určuje přizpůsobení nabídky uživatele a jeho přístupových práv pro " +"skupinu uživatelů\n" +"(těch přiřazených k portálu). Také přidružuje uživatelské skupiny k\n" +"uživatelům portálu (přidáním skupiny v portálu automaticky je přidáte k " +"uživatelům\n" +"portálu, atd.). Tato funkce je velmi užitečný v kombinaci s\n" +"modulem 'sdílení'.\n" +" " #. module: portal #: view:share.wizard:0 msgid "Who do you want to share with?" -msgstr "" +msgstr "S kým chcete sdílet?" #. module: portal #: view:res.portal.wizard:0 msgid "Send Invitations" -msgstr "" +msgstr "Poslat pozvání" #. module: portal #: help:res.portal,url:0 msgid "The url where portal users can connect to the server" -msgstr "" +msgstr "URL, kde uživatelé portálu se mohou připojit k serveru" #. module: portal #: field:res.portal.widget,widget_id:0 msgid "Widget" -msgstr "" +msgstr "Udělátko" #. module: portal #: help:res.portal.wizard,message:0 msgid "This text is included in the welcome email sent to the users" -msgstr "" +msgstr "Tento text je zahrnut v uvítacím emailu zaslatném uživatelům" #. module: portal #: help:res.portal,menu_action_id:0 msgid "If set, replaces the standard menu for the portal's users" msgstr "" +"Pokud je nastaveno, nahrazuje standardní nabídku pro uživatele portálu" #. module: portal #: field:res.portal,parent_menu_id:0 msgid "Parent Menu" -msgstr "" +msgstr "Nadřazené menu" #. module: portal #: view:res.portal:0 msgid "Portal Name" -msgstr "" +msgstr "Jméno portálu" #. module: portal #: view:res.portal.wizard.user:0 msgid "Portal Users" -msgstr "" +msgstr "Uživatelé portálu" #. module: portal #: field:res.portal,override_menu:0 msgid "Override Menu Action of Users" -msgstr "" +msgstr "Přepsat Akce nabídky pro uživatele" #. module: portal #: field:res.portal,menu_action_id:0 msgid "Menu Action" -msgstr "" +msgstr "Akce nabídky" #. module: portal #: field:res.portal.wizard.user,name:0 msgid "User Name" -msgstr "" +msgstr "Uživatelské jméno" #. module: portal #: model:ir.model,name:portal.model_res_portal_widget msgid "Portal Widgets" -msgstr "" +msgstr "Pomůcky portálu" #. module: portal #: model:ir.model,name:portal.model_res_portal @@ -172,47 +188,47 @@ msgstr "" #: field:res.portal.widget,portal_id:0 #: field:res.portal.wizard,portal_id:0 msgid "Portal" -msgstr "" +msgstr "Portál" #. module: portal #: code:addons/portal/wizard/portal_wizard.py:35 #, python-format msgid "Your OpenERP account at %(company)s" -msgstr "" +msgstr "Váš účet OpenERP v %(company)s" #. module: portal #: code:addons/portal/portal.py:110 #: code:addons/portal/portal.py:184 #, python-format msgid "%s Menu" -msgstr "" +msgstr "%s Nabídka" #. module: portal #: help:res.portal.wizard,portal_id:0 msgid "The portal in which new users must be added" -msgstr "" +msgstr "Portál, ve kterém musí být přidání noví uživatelé" #. module: portal #: help:res.portal,widget_ids:0 msgid "Widgets assigned to portal users" -msgstr "" +msgstr "Pomůcky přiřazené k těmto uživatelům portálu" #. module: portal #: code:addons/portal/wizard/portal_wizard.py:163 #, python-format msgid "(missing url)" -msgstr "" +msgstr "(chybějící url)" #. module: portal #: view:share.wizard:0 #: field:share.wizard,user_ids:0 msgid "Existing users" -msgstr "" +msgstr "Existující uživatelé" #. module: portal #: field:res.portal.wizard.user,wizard_id:0 msgid "Wizard" -msgstr "" +msgstr "Průvodce" #. module: portal #: help:res.portal.wizard.user,user_email:0 @@ -220,63 +236,66 @@ msgid "" "Will be used as user login. Also necessary to send the account information " "to new users" msgstr "" +"Bude použito jako přihlašovací jméno uživatele. Také je zapotřebí zaslat " +"informace účtu novým uživatelům" #. module: portal #: field:res.portal.wizard.user,lang:0 msgid "Language" -msgstr "" +msgstr "Jazyk" #. module: portal #: field:res.portal,url:0 msgid "URL" -msgstr "" +msgstr "URL" #. module: portal #: view:res.portal:0 msgid "Widgets assigned to Users" -msgstr "" +msgstr "Pomůcky přiřazené uživatelům" #. module: portal #: help:res.portal.wizard.user,lang:0 msgid "The language for the user's user interface" -msgstr "" +msgstr "Jazyk pro uživatelské rozhraní uživatelů" #. module: portal #: view:res.portal.wizard:0 msgid "Cancel" -msgstr "" +msgstr "Zrušit" #. module: portal #: view:res.portal:0 msgid "Website" -msgstr "" +msgstr "Webová stránka" #. module: portal #: view:res.portal:0 msgid "Create Parent Menu" -msgstr "" +msgstr "Vytvořit nadřazenou nabídku" #. module: portal #: view:res.portal.wizard:0 msgid "" "The following text will be included in the welcome email sent to users." msgstr "" +"Následující text bude zahrnut v uvítacím emailu zalsatném uživatelům." #. module: portal #: code:addons/portal/wizard/portal_wizard.py:135 #, python-format msgid "Email required" -msgstr "" +msgstr "Požadován email" #. module: portal #: model:ir.model,name:portal.model_res_users msgid "res.users" -msgstr "" +msgstr "res.users" #. module: portal #: constraint:res.portal.wizard.user:0 msgid "Invalid email address" -msgstr "" +msgstr "Neplatná emailová adresa" #. module: portal #: code:addons/portal/wizard/portal_wizard.py:136 @@ -284,28 +303,30 @@ msgstr "" msgid "" "You must have an email address in your User Preferences to send emails." msgstr "" +"Musíte mít emailovou adresu ve vašich uživatelských předvolbách pro zasílání " +"emailů." #. module: portal #: model:ir.model,name:portal.model_ir_ui_menu msgid "ir.ui.menu" -msgstr "" +msgstr "ir.ui.menu" #. module: portal #: help:res.portal,group_id:0 msgid "The group extended by this portal" -msgstr "" +msgstr "Skupina rozšířená tímto portálem" #. module: portal #: view:res.portal:0 #: view:res.portal.wizard:0 #: field:res.portal.wizard,user_ids:0 msgid "Users" -msgstr "" +msgstr "Uživatelé" #. module: portal #: field:res.portal,other_group_ids:0 msgid "Other User Groups" -msgstr "" +msgstr "Jiné skupiny uživatelů" #. module: portal #: model:ir.actions.act_window,name:portal.portal_list_action @@ -313,38 +334,38 @@ msgstr "" #: model:ir.ui.menu,name:portal.portal_menu #: view:res.portal:0 msgid "Portals" -msgstr "" +msgstr "Portály" #. module: portal #: help:res.portal,parent_menu_id:0 msgid "The menu action opens the submenus of this menu item" -msgstr "" +msgstr "Akce nabídky otevírající podnabídku této položky nabídky" #. module: portal #: field:res.portal.widget,sequence:0 msgid "Sequence" -msgstr "" +msgstr "Posloupnost" #. module: portal #: field:res.users,partner_id:0 msgid "Related Partner" -msgstr "" +msgstr "Vztažený partner" #. module: portal #: view:res.portal:0 msgid "Portal Menu" -msgstr "" +msgstr "Nabídka portálu" #. module: portal #: sql_constraint:res.users:0 msgid "You can not have two users with the same login !" -msgstr "" +msgstr "Nemůžete mít dva uživatele se stejným přihlašovacím jménem !" #. module: portal #: view:res.portal.wizard:0 #: field:res.portal.wizard,message:0 msgid "Invitation message" -msgstr "" +msgstr "Zpráva pozvánky" #. module: portal #: code:addons/portal/wizard/portal_wizard.py:36 @@ -365,28 +386,42 @@ msgid "" "OpenERP - Open Source Business Applications\n" "http://www.openerp.com\n" msgstr "" +"Vážený %(name)s,\n" +"\n" +"Byl vám vytvořen OpenERP účet na %(url)s.\n" +"\n" +"Váše přihlašovací údaje účtu jsou:\n" +"Databáze: %(db)s\n" +"Uživatel: %(login)s\n" +"Heslo: %(password)s\n" +"\n" +"%(message)s\n" +"\n" +"--\n" +"OpenERP - Open Source Business Applications\n" +"http://www.openerp.com\n" #. module: portal #: model:ir.model,name:portal.model_res_portal_wizard msgid "Portal Wizard" -msgstr "" +msgstr "Průvodce portálu" #. module: portal #: help:res.portal.wizard.user,name:0 msgid "The user's real name" -msgstr "" +msgstr "Skutečné jméno uživatele" #. module: portal #: model:ir.actions.act_window,name:portal.address_wizard_action #: model:ir.actions.act_window,name:portal.partner_wizard_action #: view:res.portal.wizard:0 msgid "Add Portal Access" -msgstr "" +msgstr "Přidat přístup portálu" #. module: portal #: field:res.portal.wizard.user,partner_id:0 msgid "Partner" -msgstr "" +msgstr "Partner" #. module: portal #: model:ir.actions.act_window,help:portal.portal_list_action @@ -398,8 +433,14 @@ msgid "" "the portal's users.\n" " " msgstr "" +"\n" +"Portál pomáhá stanovit určité pohledy a pravidla pro skupiny uživatelů\n" +"(skupinu protálu). Nabídka portálu, pomůcky a určité skupiny mohou být " +"přiřazeny k\n" +"uživatelům portálu.\n" +" " #. module: portal #: model:ir.model,name:portal.model_share_wizard msgid "Share Wizard" -msgstr "" +msgstr "Průvodce sdílením" diff --git a/addons/portal/ir_ui_menu.py b/addons/portal/ir_ui_menu.py index a4fe364a4fd..c8f59ca8bd1 100644 --- a/addons/portal/ir_ui_menu.py +++ b/addons/portal/ir_ui_menu.py @@ -56,3 +56,5 @@ class portal_menu(osv.osv): portal_menu() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/portal/portal.py b/addons/portal/portal.py index 1c7f84c363a..de39944e69f 100644 --- a/addons/portal/portal.py +++ b/addons/portal/portal.py @@ -226,3 +226,5 @@ portal_widget() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/portal/res_user.py b/addons/portal/res_user.py index 2f32a65b761..127c3079b29 100644 --- a/addons/portal/res_user.py +++ b/addons/portal/res_user.py @@ -32,3 +32,5 @@ class res_users(osv.osv): res_users() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/portal/wizard/__init__.py b/addons/portal/wizard/__init__.py index 90b71a62c30..9d52ae0db6d 100644 --- a/addons/portal/wizard/__init__.py +++ b/addons/portal/wizard/__init__.py @@ -22,3 +22,5 @@ import portal_wizard import share_wizard + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/portal/wizard/portal_wizard.py b/addons/portal/wizard/portal_wizard.py index 7157f22f129..706d6fd4a7f 100644 --- a/addons/portal/wizard/portal_wizard.py +++ b/addons/portal/wizard/portal_wizard.py @@ -225,3 +225,5 @@ wizard_user() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/portal/wizard/share_wizard.py b/addons/portal/wizard/share_wizard.py index ab639bdeccc..b5c9d165cc6 100644 --- a/addons/portal/wizard/share_wizard.py +++ b/addons/portal/wizard/share_wizard.py @@ -184,3 +184,5 @@ class share_wizard_portal(osv.osv_memory): share_wizard_portal() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/procurement/__init__.py b/addons/procurement/__init__.py index 3420ef1f75e..4634166a9bd 100644 --- a/addons/procurement/__init__.py +++ b/addons/procurement/__init__.py @@ -22,4 +22,6 @@ import procurement import wizard import schedulers -import company \ No newline at end of file +import company + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/procurement/board_mrp_procurement_view.xml b/addons/procurement/board_mrp_procurement_view.xml index bf11fe79166..b45edd3cbdd 100644 --- a/addons/procurement/board_mrp_procurement_view.xml +++ b/addons/procurement/board_mrp_procurement_view.xml @@ -16,8 +16,8 @@ form - - + + diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index 3c22b2838ef..db953c8a319 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -202,6 +202,13 @@ class product_pricelist(osv.osv): else: categ_where = '(categ_id IS NULL)' + if partner: + partner_where = 'base <> -2 OR %s IN (SELECT name FROM product_supplierinfo WHERE product_id = %s) ' + partner_args = (partner, product_id) + else: + partner_where = 'base <> -2 ' + partner_args = () + cr.execute( 'SELECT i.*, pl.currency_id ' 'FROM product_pricelist_item AS i, ' @@ -209,11 +216,12 @@ class product_pricelist(osv.osv): 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) ' 'AND (product_id IS NULL OR product_id = %s) ' 'AND (' + categ_where + ' OR (categ_id IS NULL)) ' + 'AND (' + partner_where + ') ' 'AND price_version_id = %s ' 'AND (min_quantity IS NULL OR min_quantity <= %s) ' 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id ' 'ORDER BY sequence', - (tmpl_id, product_id, pricelist_version_ids[0], qty)) + (tmpl_id, product_id) + partner_args + (pricelist_version_ids[0], qty)) res1 = cr.dictfetchall() uom_price_already_computed = False for res in res1: @@ -296,148 +304,6 @@ class product_pricelist(osv.osv): res.update({'item_id': {ids[-1]: res_multi.get('item_id', ids[-1])}}) return res - def price_get_old(self, cr, uid, ids, prod_id, qty, partner=None, context=None): - ''' - context = { - 'uom': Unit of Measure (int), - 'partner': Partner ID (int), - 'date': Date of the pricelist (%Y-%m-%d), - } - ''' - price = False - item_id = 0 - if context is None: - context = {} - currency_obj = self.pool.get('res.currency') - product_obj = self.pool.get('product.product') - supplierinfo_obj = self.pool.get('product.supplierinfo') - price_type_obj = self.pool.get('product.price.type') - - if context and ('partner_id' in context): - partner = context['partner_id'] - context['partner_id'] = partner - date = time.strftime('%Y-%m-%d') - if context and ('date' in context): - date = context['date'] - result = {} - result['item_id'] = {} - for id in ids: - cr.execute('SELECT * ' \ - 'FROM product_pricelist_version ' \ - 'WHERE pricelist_id = %s AND active=True ' \ - 'AND (date_start IS NULL OR date_start <= %s) ' \ - 'AND (date_end IS NULL OR date_end >= %s) ' \ - 'ORDER BY id LIMIT 1', (id, date, date)) - plversion = cr.dictfetchone() - - if not plversion: - raise osv.except_osv(_('Warning !'), - _('No active version for the selected pricelist !\n' \ - 'Please create or activate one.')) - - cr.execute('SELECT id, categ_id ' \ - 'FROM product_template ' \ - 'WHERE id = (SELECT product_tmpl_id ' \ - 'FROM product_product ' \ - 'WHERE id = %s)', (prod_id,)) - tmpl_id, categ = cr.fetchone() - categ_ids = [] - while categ: - categ_ids.append(str(categ)) - cr.execute('SELECT parent_id ' \ - 'FROM product_category ' \ - 'WHERE id = %s', (categ,)) - categ = cr.fetchone()[0] - if str(categ) in categ_ids: - raise osv.except_osv(_('Warning !'), - _('Could not resolve product category, ' \ - 'you have defined cyclic categories ' \ - 'of products!')) - if categ_ids: - categ_where = '(categ_id IN (' + ','.join(categ_ids) + '))' - else: - categ_where = '(categ_id IS NULL)' - - cr.execute( - 'SELECT i.*, pl.currency_id ' - 'FROM product_pricelist_item AS i, ' - 'product_pricelist_version AS v, product_pricelist AS pl ' - 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) ' - 'AND (product_id IS NULL OR product_id = %s) ' - 'AND (' + categ_where + ' OR (categ_id IS NULL)) ' - 'AND price_version_id = %s ' - 'AND (min_quantity IS NULL OR min_quantity <= %s) ' - 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id ' - 'ORDER BY sequence', - (tmpl_id, prod_id, plversion['id'], qty)) - res1 = cr.dictfetchall() - - for res in res1: - item_id = 0 - if res: - if res['base'] == -1: - if not res['base_pricelist_id']: - price = 0.0 - else: - price_tmp = self.price_get(cr, uid, - [res['base_pricelist_id']], prod_id, - qty, context=context)[res['base_pricelist_id']] - ptype_src = self.browse(cr, uid, - res['base_pricelist_id']).currency_id.id - price = currency_obj.compute(cr, uid, ptype_src, - res['currency_id'], price_tmp, round=False) - break - elif res['base'] == -2: - where = [] - if partner: - where = [('name', '=', partner) ] - sinfo = supplierinfo_obj.search(cr, uid, - [('product_id', '=', tmpl_id)] + where) - price = 0.0 - if sinfo: - cr.execute('SELECT * ' \ - 'FROM pricelist_partnerinfo ' \ - 'WHERE suppinfo_id IN %s' \ - 'AND min_quantity <= %s ' \ - 'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo),qty,)) - res2 = cr.dictfetchone() - if res2: - price = res2['price'] - break - else: - price_type = price_type_obj.browse(cr, uid, int(res['base'])) - price = currency_obj.compute(cr, uid, - price_type.currency_id.id, res['currency_id'], - product_obj.price_get(cr, uid, [prod_id], - price_type.field, context=context)[prod_id], round=False, context=context) - - if price: - price_limit = price - - price = price * (1.0+(res['price_discount'] or 0.0)) - price = rounding(price, res['price_round']) - price += (res['price_surcharge'] or 0.0) - if res['price_min_margin']: - price = max(price, price_limit+res['price_min_margin']) - if res['price_max_margin']: - price = min(price, price_limit+res['price_max_margin']) - item_id = res['id'] - break - - else: - # False means no valid line found ! But we may not raise an - # exception here because it breaks the search - price = False - result[id] = price - result['item_id'] = {id: item_id} - if context and ('uom' in context): - product = product_obj.browse(cr, uid, prod_id) - uom = product.uos_id or product.uom_id - result[id] = self.pool.get('product.uom')._compute_price(cr, - uid, uom.id, result[id], context['uom']) - - return result - product_pricelist() diff --git a/addons/product/pricelist_view.xml b/addons/product/pricelist_view.xml index 2f8982a1faf..d4d274da2d1 100644 --- a/addons/product/pricelist_view.xml +++ b/addons/product/pricelist_view.xml @@ -165,7 +165,7 @@ form tree,form - {"search_default_type":"sale"} + {"default_type":"sale", "search_default_type":"sale"} [('type','=','sale')] A price list contains rules to be evaluated in order to compute the purchase or sales price for all the partners assigned to a price list. Price lists have several versions (2010, 2011, Promotion of February 2010, etc.) and each version has several rules. Example: the customer price of a product category will be based on the supplier price multiplied by 1.80. @@ -176,7 +176,7 @@ form tree,form - {"search_default_type":"purchase"} + {"default_type":"purchase", "search_default_type":"purchase"} [('type','=','purchase')] A price list contains rules to be evaluated in order to compute the purchase or sales price for all the partners assigned to a price list. Price lists have several versions (2010, 2011, Promotion of February 2010, etc.) and each version has several rules. Example: the customer price of a product category will be based on the supplier price multiplied by 1.80. diff --git a/addons/product/product_data.xml b/addons/product/product_data.xml index fc085aab922..122c8594de4 100644 --- a/addons/product/product_data.xml +++ b/addons/product/product_data.xml @@ -23,8 +23,8 @@ + Resource: product.uom + --> PCE diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index a0669795ad5..ac9ae8c5ec3 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -376,7 +376,6 @@ Products by Categories - diff --git a/addons/project/board_project_manager_view.xml b/addons/project/board_project_manager_view.xml index b9ff6331db0..d9340eefb3a 100644 --- a/addons/project/board_project_manager_view.xml +++ b/addons/project/board_project_manager_view.xml @@ -2,20 +2,23 @@ - + + + + diff --git a/addons/project/board_project_view.xml b/addons/project/board_project_view.xml index f2c44fab574..a58557c94ba 100644 --- a/addons/project/board_project_view.xml +++ b/addons/project/board_project_view.xml @@ -81,16 +81,16 @@ form
- - - - - - - - - - + + + + + + + + + +
diff --git a/addons/project/company.py b/addons/project/company.py index 0967d130737..6400450cd3e 100644 --- a/addons/project/company.py +++ b/addons/project/company.py @@ -33,3 +33,5 @@ class res_company(osv.osv): } res_company() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/project/project.py b/addons/project/project.py index 5ab7af9de79..abebd2d35ff 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -78,7 +78,7 @@ class project(osv.osv): return {'value':{'contact_id': False}} addr = partner_obj.address_get(cr, uid, [part], ['contact']) val = {'contact_id': addr['contact']} - if pricelist_id in self._columns: + if 'pricelist_id' in self.fields_get(cr, uid, context=context): pricelist = partner_obj.read(cr, uid, part, ['property_product_pricelist'], context=context) pricelist_id = pricelist.get('property_product_pricelist', False) and pricelist.get('property_product_pricelist')[0] or False val['pricelist_id'] = pricelist_id @@ -424,21 +424,55 @@ class task(osv.osv): _log_create = True _date_name = "date_start" - def _read_group_type_id(self, cr, uid, ids, domain, context=None): - context = context or {} - stage_obj = self.pool.get('project.task.type') - stage_ids = stage_obj.search(cr, uid, ['|',('id','in',ids)] + [('project_default','=',1)], context=context) - return stage_obj.name_get(cr, uid, stage_ids, context=context) - def _read_group_user_id(self, cr, uid, ids, domain, context={}): - context = context or {} - if type(context.get('project_id', None)) not in (int, long): - return None - proj = self.pool.get('project.project').browse(cr, uid, context['project_id'], context=context) - ids += map(lambda x: x.id, proj.members) - stage_obj = self.pool.get('res.users') - stage_ids = stage_obj.search(cr, uid, [('id','in',ids)], context=context) - return stage_obj.name_get(cr, uid, ids, context=context) + def _resolve_project_id_from_context(self, cr, uid, context=None): + """Return ID of project based on the value of 'project_id' + context key, or None if it cannot be resolved to a single project. + """ + if context is None: context = {} + if type(context.get('project_id')) in (int, long): + project_id = context['project_id'] + return project_id + if isinstance(context.get('project_id'), basestring): + project_name = context['project_id'] + project_ids = self.pool.get('project.project').name_search(cr, uid, name=project_name) + if len(project_ids) == 1: + return project_ids[0][0] + + def _read_group_type_id(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None): + stage_obj = self.pool.get('project.task.type') + project_id = self._resolve_project_id_from_context(cr, uid, context=context) + order = stage_obj._order + access_rights_uid = access_rights_uid or uid + if read_group_order == 'type_id desc': + # lame way to allow reverting search, should just work in the trivial case + order = '%s desc' % order + if project_id: + domain = ['|', ('id','in',ids), ('project_ids','in',project_id)] + else: + domain = ['|', ('id','in',ids), ('project_default','=',1)] + stage_ids = stage_obj._search(cr, uid, domain, order=order, access_rights_uid=access_rights_uid, context=context) + result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context) + # restore order of the search + result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) + return result + + def _read_group_user_id(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None): + res_users = self.pool.get('res.users') + project_id = self._resolve_project_id_from_context(cr, uid, context=context) + access_rights_uid = access_rights_uid or uid + if project_id: + ids += self.pool.get('project.project').read(cr, access_rights_uid, project_id, ['members'], context=context)['members'] + order = res_users._order + # lame way to allow reverting search, should just work in the trivial case + if read_group_order == 'user_id desc': + order = '%s desc' % order + # de-duplicate and apply search order + ids = res_users._search(cr, uid, [('id','in',ids)], order=order, access_rights_uid=access_rights_uid, context=context) + result = res_users.name_get(cr, access_rights_uid, ids, context=context) + # restore order of the search + result.sort(lambda x,y: cmp(ids.index(x[0]), ids.index(y[0]))) + return result _group_by_full = { 'type_id': _read_group_type_id, @@ -560,7 +594,12 @@ class task(osv.osv): 'state': fields.selection([('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')], 'State', readonly=True, required=True, help='If the task is created the state is \'Draft\'.\n If the task is started, the state becomes \'In Progress\'.\n If review is needed the task is in \'Pending\' state.\ \n If the task is over, the states is set to \'Done\'.'), - 'kanban_state': fields.selection([('blocked', 'Blocked'),('normal', 'Normal'),('done', 'Done')], 'Kanban State', readonly=True, required=False), + 'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready To Pull')], 'Kanban State', + help="A task's kanban state indicates special situations affecting it:\n" + " * Normal is the default situation\n" + " * Blocked indicates something is preventing the progress of this task\n" + " * Ready To Pull indicates the task is ready to be pulled to the next stage", + readonly=True, required=False), 'create_date': fields.datetime('Create Date', readonly=True,select=True), 'date_start': fields.datetime('Starting Date',select=True), 'date_end': fields.datetime('Ending Date',select=True), @@ -840,37 +879,39 @@ class task(osv.osv): self.write(cr, uid, ids, {'state': 'draft'}, context=context) return True - def do_delegate(self, cr, uid, task_id, delegate_data={}, context=None): + def do_delegate(self, cr, uid, ids, delegate_data={}, context=None): """ Delegate Task to another users. """ - task = self.browse(cr, uid, task_id, context=context) - self.copy(cr, uid, task.id, { - 'name': delegate_data['name'], - 'user_id': delegate_data['user_id'], - 'planned_hours': delegate_data['planned_hours'], - 'remaining_hours': delegate_data['planned_hours'], - 'parent_ids': [(6, 0, [task.id])], - 'state': 'draft', - 'description': delegate_data['new_task_description'] or '', - 'child_ids': [], - 'work_ids': [] - }, context=context) - newname = delegate_data['prefix'] or '' - self.write(cr, uid, [task.id], { - 'remaining_hours': delegate_data['planned_hours_me'], - 'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0), - 'name': newname, - }, context=context) - if delegate_data['state'] == 'pending': - self.do_pending(cr, uid, [task.id], context) - else: - self.do_close(cr, uid, [task.id], context=context) - user_pool = self.pool.get('res.users') - delegate_user = user_pool.browse(cr, uid, delegate_data['user_id'], context=context) - message = _("The task '%s' has been delegated to %s.") % (delegate_data['name'], delegate_user.name) - self.log(cr, uid, task.id, message) - return True + assert delegate_data['user_id'], _("Delegated User should be specified") + delegrated_tasks = {} + for task in self.browse(cr, uid, ids, context=context): + delegrated_task_id = self.copy(cr, uid, task.id, { + 'name': delegate_data['name'], + 'project_id': delegate_data['project_id'] and delegate_data['project_id'][0] or False, + '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': [] + }, context=context) + newname = delegate_data['prefix'] or '' + task.write({ + 'remaining_hours': delegate_data['planned_hours_me'], + 'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0), + 'name': newname, + }, context=context) + if delegate_data['state'] == 'pending': + self.do_pending(cr, uid, task.id, context=context) + elif delegate_data['state'] == 'done': + self.do_close(cr, uid, task.id, context=context) + + message = _("The task '%s' has been delegated to %s.") % (delegate_data['name'], delegate_data['user_id'][1]) + self.log(cr, uid, task.id, message) + delegrated_tasks[task.id] = delegrated_task_id + return delegrated_tasks def do_pending(self, cr, uid, ids, context={}): self.write(cr, uid, ids, {'state': 'pending'}, context=context) @@ -933,6 +974,20 @@ class task(osv.osv): def prev_type(self, cr, uid, ids, *args): return self._change_type(cr, uid, ids, False, *args) + # Overridden to reset the kanban_state to normal whenever + # the stage (type_id) of the task changes. + def write(self, cr, uid, ids, vals, context=None): + if isinstance(ids, (int, long)): + ids = [ids] + if vals and not 'kanban_state' in vals and 'type_id' in vals: + new_stage = vals.get('type_id') + vals_reset_kstate = dict(vals, kanban_state='normal') + for t in self.browse(cr, uid, ids, context=context): + write_vals = vals_reset_kstate if t.type_id != new_stage else vals + super(task,self).write(cr, uid, [t.id], write_vals, context=context) + return True + return super(task,self).write(cr, uid, ids, vals, context=context) + def unlink(self, cr, uid, ids, context=None): if context == None: context = {} diff --git a/addons/project/project_data.xml b/addons/project/project_data.xml index d78f208526a..a3bfe9be673 100644 --- a/addons/project/project_data.xml +++ b/addons/project/project_data.xml @@ -1,30 +1,12 @@ - - - - - Project - project.project - - - - Project task - project.task - - - - + + Projects 3 - - + @@ -47,7 +29,5 @@ Deployment - - diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index d85481a6e5e..50ab84c27f4 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -45,7 +45,7 @@ - +