diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index e117b31346d..5b653e4c61f 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -47,7 +47,19 @@ You could use this simplified accounting in case you work with an (external) acc 'report/account_invoice_report_view.xml', 'report/inherited_layouts.xml', 'views/account_journal_dashboard_view.xml', + 'views/report_overdue.xml', 'views/web_planner_data.xml', + 'views/report_overdue.xml', + 'wizard/account_report_common_view.xml', + 'wizard/account_report_general_ledger_view.xml', + 'views/report_generalledger.xml', + 'wizard/account_report_trial_balance_view.xml', + 'views/report_trialbalance.xml', + 'views/account_financial_report_data.xml', + 'wizard/account_financial_report_view.xml', + 'views/report_financial.xml', + 'wizard/account_report_aged_partner_balance_view.xml', + 'views/report_agedpartnerbalance.xml', ], 'demo': [ 'demo/account_demo.xml', diff --git a/addons/account/i18n/account.pot b/addons/account/i18n/account.pot index 0569b6131b0..66566c1e270 100644 --- a/addons/account/i18n/account.pot +++ b/addons/account/i18n/account.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 9.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-09-07 14:40+0000\n" -"PO-Revision-Date: 2015-09-07 14:40+0000\n" +"POT-Creation-Date: 2015-09-10 10:19+0000\n" +"PO-Revision-Date: 2015-09-10 10:19+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -192,7 +192,7 @@ msgstr "" msgid "\n" " \n" " Import a file
\n" -" Recommanded if >100 products\n" +" Recommended if >100 products\n" "
" msgstr "" @@ -219,7 +219,7 @@ msgstr "" msgid "\n" " \n" " Create manually
\n" -" Recommanded if <100 products\n" +" Recommended if <100 products\n" "
" msgstr "" @@ -368,12 +368,12 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "Automated documents sending: automatically print, send and deliver your invoices & letters by regular mail or email." +msgid "Automated documents sending: automatically send your invoices by email or regular mail," msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "Bank interface: your bank statements are automatically synchronized with your bank." +msgid "Bank interface: with bank feeds synchronization or bank statement import." msgstr "" #. module: account @@ -394,7 +394,7 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "Clean customer invoices: easy to create, beautiful and fully featured invoices (payment terms, multiple taxes, discounts, etc)." +msgid "Clean customer invoices: easy to create, beautiful and full featured invoices," msgstr "" #. module: account @@ -471,7 +471,7 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "On-the-fly payment reconciliation: automatic suggestion of outstanding payments when creating an invoice." +msgid "On-the-fly payment reconciliation: automatic suggestion of outstanding payments when creating an invoice," msgstr "" #. module: account @@ -526,7 +526,7 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "Reduced data entry: no need to manually create every invoice, register bank statements, follow-up payments, etc." +msgid "Reduced data entry: no need to manually create invoices, register bank statements, follow-up payments," msgstr "" #. module: account @@ -919,7 +919,6 @@ msgstr "" #. module: account #: model:ir.ui.menu,name:account.account_account_menu -#: model:ir.ui.menu,name:account.menu_finance #: model:ir.ui.view,arch_db:account.product_template_form_view #: model:ir.ui.view,arch_db:account.view_partner_property_form msgid "Accounting" @@ -1351,9 +1350,9 @@ msgstr "" #. module: account #: model:ir.model.fields,help:account.field_account_config_settings_module_account_asset -msgid "Asset management: This allows you to manage the assets owned by a company or a person.It keeps track of the depreciation occurred on those assets, and creates account move for those depreciation lines.\n" +msgid "Asset management: This allows you to manage the assets owned by a company or a person. It keeps track of the depreciation occurred on those assets, and creates account move for those depreciation lines.\n" "\n" -"Revenue recognition: This allows you to manage the Revenue recognition on selling product.It keeps track of the installment occurred on those revenue recognition, and creates account move for those installment lines.\n" +"Revenue recognition: This allows you to manage the Revenue recognition on selling product. It keeps track of the installment occurred on those revenue recognition, and creates account move for those installment lines.\n" "-This installs the module account_asset. If you do not check this box, you will be able to do invoicing & payments, but not accounting (Journal Items, Chart of Accounts, ...)" msgstr "" @@ -2235,6 +2234,11 @@ msgid "Configuration error!\n" "The currency of the journal should be the same than the default debit account." msgstr "" +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "Configuration menu" +msgstr "" + #. module: account #: model:ir.actions.act_window,name:account.action_account_config #: model:ir.ui.view,arch_db:account.view_account_config_settings @@ -2578,6 +2582,11 @@ msgstr "" msgid "Current Year Earnings" msgstr "" +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "Current account balances" +msgstr "" + #. module: account #: selection:account.abstract.payment,partner_type:0 #: selection:account.payment,partner_type:0 @@ -3369,6 +3378,11 @@ msgid "For the Odoo Team,
\n" " Fabien Pinckaers, Founder" msgstr "" +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "For the setup, you will need to get access to the following information:" +msgstr "" + #. module: account #: model:ir.model.fields,help:account.field_account_account_currency_id msgid "Forces all moves for this account to have this account currency." @@ -3639,7 +3653,7 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "If you have less than 200 contacts, we recommand you\n" +msgid "If you have less than 200 contacts, we recommend you\n" " to create them manually." msgstr "" @@ -3693,7 +3707,9 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "If you'd like some help on any subject dont hesitate to contact our Accounting experts by using the icon on the top bar." +msgid "If you'd like some help on any subject dont hesitate to\n" +" contact our Accounting experts by using the \n" +" icon on the top bar." msgstr "" #. module: account @@ -4007,6 +4023,11 @@ msgstr "" msgid "Invoices to validate" msgstr "" +#. module: account +#: model:ir.ui.menu,name:account.menu_finance +msgid "Invoicing" +msgstr "" + #. module: account #: model:ir.model.fields,field_description:account.field_account_bank_statement_message_is_follower #: model:ir.model.fields,field_description:account.field_account_invoice_message_is_follower @@ -5007,11 +5028,6 @@ msgid "Once draft invoices are confirmed, you will not be able\n" " of accounts." msgstr "" -#. module: account -#: model:ir.ui.view,arch_db:account.account_planner -msgid "Once you're done, you'll benefit from:" -msgstr "" - #. module: account #: model:ir.ui.view,arch_db:account.account_planner msgid "Once your bank accounts are registered, you will be able to\n" @@ -5171,6 +5187,11 @@ msgstr "" msgid "Outstanding debits" msgstr "" +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "Outstanding invoices, payments and undeposited funds" +msgstr "" + #. module: account #: model:ir.ui.view,arch_db:account.view_account_invoice_filter msgid "Overdue" @@ -5834,12 +5855,6 @@ msgstr "" msgid "Put Money In" msgstr "" -#. module: account -#: selection:account.tax,amount_type:0 -#: selection:account.tax.template,amount_type:0 -msgid "Python Code" -msgstr "" - #. module: account #: model:ir.model.fields,field_description:account.field_account_invoice_line_quantity #: model:ir.model.fields,field_description:account.field_account_move_line_quantity @@ -6140,6 +6155,7 @@ msgid "Residual Amount in Currency" msgstr "" #. module: account +#: model:ir.model.fields,field_description:account.field_account_bank_statement_user_id #: model:ir.ui.view,arch_db:account.invoice_supplier_form msgid "Responsible" msgstr "" @@ -6189,7 +6205,7 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "Review the list of available currencies (from the Configuration menu)" +msgid "Review the list of available currencies (from the" msgstr "" #. module: account @@ -7221,7 +7237,8 @@ msgstr "" #. module: account #: model:ir.ui.view,arch_db:account.account_planner -msgid "This guide will help you get started with Odoo Accounting." +msgid "This guide will help you get started with Odoo Accounting.\n" +" Once you're done, you'll benefit from:" msgstr "" #. module: account @@ -7656,11 +7673,6 @@ msgstr "" msgid "Used to register a profit when the ending balance of a cash register differs from what the system computes" msgstr "" -#. module: account -#: model:ir.model.fields,field_description:account.field_account_bank_statement_user_id -msgid "User" -msgstr "" - #. module: account #: model:ir.model.fields,help:account.field_account_bank_statement_line_journal_currency_id #: model:ir.model.fields,help:account.field_account_move_line_company_currency_id @@ -7811,18 +7823,6 @@ msgstr "" msgid "We hope this tool helped you implement our accounting application." msgstr "" -#. module: account -#: model:ir.model.fields,field_description:account.field_account_bank_statement_website_message_ids -#: model:ir.model.fields,field_description:account.field_account_invoice_website_message_ids -msgid "Website Messages" -msgstr "" - -#. module: account -#: model:ir.model.fields,help:account.field_account_bank_statement_website_message_ids -#: model:ir.model.fields,help:account.field_account_invoice_website_message_ids -msgid "Website communication history" -msgstr "" - #. module: account #: model:ir.ui.view,arch_db:account.account_planner msgid "When inviting users, you need to define which access and rights they are allowed.
This is done by attributing a role to each users." @@ -8087,6 +8087,26 @@ msgstr "" msgid "You will find more options in your company details: address for the header and footer, overdue payments texts, etc." msgstr "" +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "Your bank accounts: one statement per bank account" +msgstr "" + +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "Your company: legal name, Tax ID, address, logo." +msgstr "" + +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "Your usual payment terms" +msgstr "" + +#. module: account +#: model:ir.ui.view,arch_db:account.account_planner +msgid "Your usual tax rates" +msgstr "" + #. module: account #: model:ir.ui.view,arch_db:account.view_account_position_form msgid "Zip Range" diff --git a/addons/account/models/company.py b/addons/account/models/company.py index d329003480b..1a5e8ff5551 100644 --- a/addons/account/models/company.py +++ b/addons/account/models/company.py @@ -35,7 +35,15 @@ class ResCompany(models.Model): property_stock_account_output_categ_id = fields.Many2one('account.account', oldname="property_stock_account_output_categ") property_stock_valuation_account_id = fields.Many2one('account.account') bank_journal_ids = fields.One2many('account.journal', 'company_id', domain=[('type', '=', 'bank')], string='Bank Journals') + overdue_msg = fields.Text(string='Overdue Payments Message', translate=True, + default='''Dear Sir/Madam, +Our records indicate that some payments on your account are still due. Please find details below. +If the amount has already been paid, please disregard this notice. Otherwise, please forward us the total amount stated below. +If you have any queries regarding your account, Please contact us. + +Thank you in advance for your cooperation. +Best Regards,''') @api.multi def compute_fiscalyear_dates(self, date): diff --git a/addons/account/models/res_config.py b/addons/account/models/res_config.py index 53414da5992..b072f6258bc 100644 --- a/addons/account/models/res_config.py +++ b/addons/account/models/res_config.py @@ -73,9 +73,9 @@ class AccountConfigSettings(models.TransientModel): help="""If you do not check this box, you will be able to do invoicing & payments, but not accounting (Journal Items, Chart of Accounts, ...)""") module_account_asset = fields.Boolean(string='Assets management & Revenue recognition', - help='Asset management: This allows you to manage the assets owned by a company or a person.' + help='Asset management: This allows you to manage the assets owned by a company or a person. ' 'It keeps track of the depreciation occurred on those assets, and creates account move for those depreciation lines.\n\n' - 'Revenue recognition: This allows you to manage the Revenue recognition on selling product.' + 'Revenue recognition: This allows you to manage the Revenue recognition on selling product. ' 'It keeps track of the installment occurred on those revenue recognition, and creates account move for those installment lines.\n' '-This installs the module account_asset. If you do not check this box, you will be able to do invoicing & payments, ' 'but not accounting (Journal Items, Chart of Accounts, ...)') diff --git a/addons/account/report/__init__.py b/addons/account/report/__init__.py index e6d7f3e0c9c..95c6abf0dcf 100644 --- a/addons/account/report/__init__.py +++ b/addons/account/report/__init__.py @@ -3,3 +3,8 @@ import account_financial_report import account_invoice_report +import account_overdue_report +import account_general_ledger +import account_balance +import account_report_financial +import account_aged_partner_balance diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py new file mode 100644 index 00000000000..d7670f2f621 --- /dev/null +++ b/addons/account/report/account_aged_partner_balance.py @@ -0,0 +1,299 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +class ReportAgedPartnerBalance(models.AbstractModel): + + _name = 'report.account.report_agedpartnerbalance' + + def _get_partner_move_lines(self, form, account_type, date_from, target_move): + res = [] + self.total_account = [] + cr = self.env.cr + move_state = ['draft', 'posted'] + if target_move == 'posted': + move_state = ['posted'] + cr.execute('SELECT DISTINCT res_partner.id AS id,\ + res_partner.name AS name \ + FROM res_partner,account_move_line AS l, account_account, account_move am\ + WHERE (l.account_id = account_account.id) \ + AND (l.move_id = am.id) \ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND l.reconciled IS FALSE\ + AND (l.partner_id = res_partner.id)\ + AND (l.date <= %s)\ + ORDER BY res_partner.name', (tuple(move_state), tuple(account_type), date_from)) + + partners = cr.dictfetchall() + # put a total of 0 + for i in range(7): + self.total_account.append(0) + + # Build a string like (1,2,3) for easy use in SQL query + partner_ids = [partner['id'] for partner in partners] + if not partner_ids: + return [] + + # This dictionary will store the debit-credit for all partners, using partner_id as key. + totals = {} + cr.execute('SELECT l.partner_id, SUM(l.debit-l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) \ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND (l.partner_id IN %s)\ + AND (l.date <= %s)\ + GROUP BY l.partner_id ', (tuple(move_state), tuple(account_type), tuple(partner_ids), date_from,)) + partner_totals = cr.fetchall() + for partner_id, amount in partner_totals: + totals[partner_id] = amount + + # This dictionary will store the future or past of all partners + future_past = {} + cr.execute('SELECT l.partner_id, SUM(l.debit - l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND (COALESCE(l.date_maturity,l.date) > %s)\ + AND (l.partner_id IN %s)\ + AND l.reconciled IS FALSE\ + AND (l.date <= %s)\ + GROUP BY l.partner_id', (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from,)) + partner_totals = cr.fetchall() + for partner_id, amount in partner_totals: + future_past[partner_id] = amount + + # Use one query per period and store results in history (a list variable) + # Each history will contain: history[1] = {'': } + history = [] + for i in range(5): + args_list = (tuple(move_state), tuple(account_type), tuple(partner_ids),) + dates_query = '(COALESCE(l.date_maturity,l.date)' + + if form[str(i)]['start'] and form[str(i)]['stop']: + dates_query += ' BETWEEN %s AND %s)' + args_list += (form[str(i)]['start'], form[str(i)]['stop']) + elif form[str(i)]['start']: + dates_query += ' >= %s)' + args_list += (form[str(i)]['start'],) + else: + dates_query += ' <= %s)' + args_list += (form[str(i)]['stop'],) + args_list += (date_from,) + + cr.execute('''SELECT l.partner_id, SUM(l.debit - l.credit), l.id + FROM account_move_line AS l, account_account, account_move am + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND (l.partner_id IN %s) + AND l.reconciled IS FALSE + AND ''' + dates_query + ''' + AND (l.date <= %s) + GROUP BY l.partner_id, l.id''', args_list) + partners_partial = cr.fetchall() + partners_amount = dict((partner_id, 0) for partner_id, amount, line_id in partners_partial) + + for partner_id, amount, line_id in partners_partial: + partial_reconcile_ids = [] + line = self.env['account.move.line'].browse(line_id) + for partial_line in (line.matched_debit_ids + line.matched_credit_ids): + if not partial_line.credit_move_id.id in partial_reconcile_ids: + partial_reconcile_ids.append(partial_line.credit_move_id.id) + if not partial_line.debit_move_id.id in partial_reconcile_ids: + partial_reconcile_ids.append(partial_line.debit_move_id.id) + if partial_reconcile_ids: + # in case of partial reconciliation, we want to keep the left amount in the oldest period + cr.execute('''SELECT MIN(COALESCE(date_maturity, date)) from account_move_line where id = %s''', (line_id,)) + date = cr.fetchall() + partial = False + if 'BETWEEN' in dates_query: + partial = date and args_list[-3] <= date[0][0] <= args_list[-2] + elif '>=' in dates_query: + partial = date and date[0][0] >= form[str(i)]['start'] + else: + partial = date and date[0][0] <= form[str(i)]['stop'] + if partial: + # partial reconcilation + limit_date = 'COALESCE(l.date_maturity, l.date) <= %s' + cr.execute('''SELECT SUM(l.debit - l.credit) + FROM account_move_line AS l, account_move AS am + WHERE l.move_id = am.id AND am.state IN %s + AND l.id IN %s + AND ''' + limit_date, (tuple(move_state), tuple(partial_reconcile_ids), date_from)) + unreconciled_amount = cr.fetchall() + partners_amount[partner_id] += unreconciled_amount[0][0] + else: + partners_amount[partner_id] += amount + history.append(partners_amount) + + for partner in partners: + values = {} + # Query here is replaced by one query which gets the all the partners their 'after' value + after = False + if future_past.has_key(partner['id']): # Making sure this partner actually was found by the query + after = [ future_past[partner['id']] ] + + self.total_account[6] = self.total_account[6] + (after and after[0] or 0.0) + values['direction'] = after and after[0] or 0.0 + + for i in range(5): + during = False + if history[i].has_key(partner['id']): + during = [ history[i][partner['id']] ] + # Adding counter + self.total_account[(i)] = self.total_account[(i)] + (during and during[0] or 0) + values[str(i)] = during and during[0] or 0.0 + total = False + if totals.has_key( partner['id'] ): + total = [ totals[partner['id']] ] + values['total'] = total and total[0] or 0.0 + ## Add for total + self.total_account[(i+1)] = self.total_account[(i+1)] + (total and total[0] or 0.0) + values['name'] = partner['name'] + + res.append(values) + + total = 0.0 + totals = {} + for r in res: + total += float(r['total'] or 0.0) + for i in range(5)+['direction']: + totals.setdefault(str(i), 0.0) + totals[str(i)] += float(r[str(i)] or 0.0) + return res + + def _get_move_lines_with_out_partner(self, form, account_type, date_from, target_move): + res = [] + cr = self.env.cr + move_state = ['draft', 'posted'] + if target_move == 'posted': + move_state = ['posted'] + + ## put a total of 0 + for i in range(7): + self.total_account.append(0) + totals = {} + cr.execute('SELECT SUM(l.debit - l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (l.partner_id IS NULL)\ + AND (account_account.internal_type IN %s)\ + AND l.reconciled IS FALSE \ + AND (l.date <= %s)\ + ',(tuple(move_state), tuple(account_type), date_from,)) + total_amount = cr.fetchall() + for amount in total_amount: + totals['Unknown Partner'] = amount[0] + future_past = {} + cr.execute('SELECT SUM(l.debit-l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (l.partner_id IS NULL)\ + AND (account_account.internal_type IN %s)\ + AND (COALESCE(l.date_maturity,l.date) > %s)\ + AND l.reconciled IS FALSE\ + ', (tuple(move_state), tuple(account_type), date_from,)) + total_amount = cr.fetchall() + for amount in total_amount: + future_past['Unknown Partner'] = amount[0] + + history = [] + for i in range(5): + args_list = (tuple(move_state), tuple(account_type)) + dates_query = '(COALESCE(l.date_maturity,l.date)' + if form[str(i)]['start'] and form[str(i)]['stop']: + dates_query += ' BETWEEN %s AND %s)' + args_list += (form[str(i)]['start'], form[str(i)]['stop']) + elif form[str(i)]['start']: + dates_query += ' > %s)' + args_list += (form[str(i)]['start'],) + else: + dates_query += ' < %s)' + args_list += (form[str(i)]['stop'],) + args_list += (date_from,) + cr.execute('SELECT SUM(l.debit - l.credit)\ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND (l.partner_id IS NULL)\ + AND l.reconciled IS FALSE\ + AND ' + dates_query + '\ + AND (l.date <= %s)\ + GROUP BY l.partner_id', args_list) + total_amount = cr.fetchall() + history_data = {} + for amount in total_amount: + history_data['Unknown Partner'] = amount[0] + history.append(history_data) + + values = {} + after = False + if future_past.has_key('Unknown Partner'): + after = [ future_past['Unknown Partner'] ] + self.total_account[6] = self.total_account[6] + (after and after[0] or 0.0) + values['direction'] = after and after[0] or 0.0 + + for i in range(5): + during = False + if history[i].has_key('Unknown Partner'): + during = [ history[i]['Unknown Partner'] ] + self.total_account[(i)] = self.total_account[(i)] + (during and during[0] or 0) + values[str(i)] = during and during[0] or 0.0 + + total = False + if totals.has_key( 'Unknown Partner' ): + total = [ totals['Unknown Partner'] ] + values['total'] = total and total[0] or 0.0 + ## Add for total + self.total_account[(i+1)] = self.total_account[(i+1)] + (total and total[0] or 0.0) + values['name'] = 'Unknown Partner' + + if values['total']: + res.append(values) + + total = 0.0 + totals = {} + for r in res: + total += float(r['total'] or 0.0) + for i in range(5)+['direction']: + totals.setdefault(str(i), 0.0) + totals[str(i)] += float(r[str(i)] or 0.0) + return res + + @api.multi + def render_html(self, data): + self.total_account = [] + model = self.env.context.get('active_model') + docs = self.env[model].browse(self.env.context.get('active_id')) + + target_move = data['form'].get('target_move', 'all') + date_from = data['form'].get('date_from', time.strftime('%Y-%m-%d')) + + if data['form']['result_selection'] == 'customer': + account_type = ['receivable'] + elif data['form']['result_selection'] == 'supplier': + account_type = ['payable'] + else: + account_type = ['payable','receivable'] + + without_partner_movelines = self._get_move_lines_with_out_partner(data['form'], account_type, date_from, target_move) + partner_movelines = self._get_partner_move_lines(data['form'], account_type, date_from, target_move) + movelines = partner_movelines + without_partner_movelines + docargs = { + 'doc_ids': self.ids, + 'doc_model': model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'get_partner_lines': movelines, + 'get_direction': self.total_account, + } + return self.env['report'].render('account.report_agedpartnerbalance', docargs) diff --git a/addons/account/report/account_balance.py b/addons/account/report/account_balance.py new file mode 100644 index 00000000000..825b978931c --- /dev/null +++ b/addons/account/report/account_balance.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +class ReportTrialBalance(models.AbstractModel): + _name = 'report.account.report_trialbalance' + + def _get_accounts(self, accounts, display_account): + """ compute the balance, debit and credit for the provided accounts + :Arguments: + `accounts`: list of accounts record, + `display_account`: it's used to display either all accounts or those accounts which balance is > 0 + :Returns a list of dictionary of Accounts with following key and value + `name`: Account name, + `code`: Account code, + `credit`: total amount of credit, + `debit`: total amount of debit, + `balance`: total amount of balance, + """ + + account_result = {} + # Prepare sql query base on selected parameters from wizard + tables, where_clause, where_params = self.env['account.move.line']._query_get() + tables = tables.replace('"','') + if not tables: + tables = 'account_move_line' + wheres = [""] + if where_clause.strip(): + wheres.append(where_clause.strip()) + filters = " AND ".join(wheres) + # compute the balance, debit and credit for the provided accounts + request = ("SELECT account_id AS id, SUM(debit) AS debit, SUM(credit) AS credit, (SUM(debit) - SUM(credit)) AS balance" +\ + " FROM " + tables + " WHERE account_id IN %s " + filters + " GROUP BY account_id") + params = (tuple(accounts.ids),) + tuple(where_params) + self.env.cr.execute(request, params) + for row in self.env.cr.dictfetchall(): + account_result[row.pop('id')] = row + + account_res = [] + for account in accounts: + res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance']) + currency = account.currency_id and account.currency_id or account.company_id.currency_id + res['code'] = account.code + res['name'] = account.name + if account.id in account_result.keys(): + res['debit'] = account_result[account.id].get('debit') + res['credit'] = account_result[account.id].get('credit') + res['balance'] = account_result[account.id].get('balance') + if display_account == 'all': + account_res.append(res) + if display_account in ['movement', 'not_zero'] and not currency.is_zero(res['balance']): + account_res.append(res) + return account_res + + + @api.multi + def render_html(self, data): + self.model = self.env.context.get('active_model') + docs = self.env[self.model].browse(self.env.context.get('active_id')) + display_account = data['form'].get('display_account') + accounts = self.env['account.account'].search([]) + account_res = self.with_context(data['form'].get('used_context'))._get_accounts(accounts, display_account) + + docargs = { + 'doc_ids': self.ids, + 'doc_model': self.model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'Accounts': account_res, + } + return self.env['report'].render('account.report_trialbalance', docargs) diff --git a/addons/account/report/account_general_ledger.py b/addons/account/report/account_general_ledger.py new file mode 100644 index 00000000000..363a52bfe72 --- /dev/null +++ b/addons/account/report/account_general_ledger.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +class ReportGeneralLedger(models.AbstractModel): + _name = 'report.account.report_generalledger' + + def _get_account_move_entry(self, accounts, init_balance, sortby, display_account): + """ + :param: + accounts: the recordset of accounts + init_balance: boolean value of initial_balance + sortby: sorting by date or partner and journal + display_account: type of account(receivable, payable and both) + + Returns a dictionary of accounts with following key and value { + 'code': account code, + 'name': account name, + 'debit': sum of total debit amount, + 'credit': sum of total credit amount, + 'balance': total balance, + 'amount_currency': sum of amount_currency, + 'move_lines': list of move line + } + """ + cr = self.env.cr + MoveLine = self.env['account.move.line'] + move_lines = dict(map(lambda x: (x, []), accounts.ids)) + + # Prepare initial sql query and Get the initial move lines + if init_balance: + init_tables, init_where_clause, init_where_params = MoveLine.with_context(date_to=self.env.context.get('date_from'), date_from=False)._query_get() + init_wheres = [""] + if init_where_clause.strip(): + init_wheres.append(init_where_clause.strip()) + init_filters = " AND ".join(init_wheres) + filters = init_filters.replace('account_move_line__move_id', 'm').replace('account_move_line', 'l') + sql = ("SELECT 0 AS lid, l.account_id AS account_id, '' AS ldate, '' AS lcode, NULL AS amount_currency, '' AS lref, 'Initial Balance' AS lname, COALESCE(SUM(l.debit),0.0) AS debit, COALESCE(SUM(l.credit),0.0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance, '' AS lpartner_id,\ + '' AS move_name, '' AS mmove_id, '' AS currency_code,\ + NULL AS currency_id,\ + '' AS invoice_id, '' AS invoice_type, '' AS invoice_number,\ + '' AS partner_name\ + FROM account_move_line l\ + LEFT JOIN account_move m ON (l.move_id=m.id)\ + LEFT JOIN res_currency c ON (l.currency_id=c.id)\ + LEFT JOIN res_partner p ON (l.partner_id=p.id)\ + LEFT JOIN account_invoice i ON (m.id =i.move_id)\ + JOIN account_journal j ON (l.journal_id=j.id)\ + WHERE l.account_id IN %s" + filters + ' GROUP BY l.account_id') + params = (tuple(accounts.ids),) + tuple(init_where_params) + cr.execute(sql, params) + for row in cr.dictfetchall(): + move_lines[row.pop('account_id')].append(row) + + sql_sort = 'l.date, l.move_id' + if sortby == 'sort_journal_partner': + sql_sort = 'j.code, p.name, l.move_id' + + # Prepare sql query base on selected parameters from wizard + tables, where_clause, where_params = MoveLine._query_get() + wheres = [""] + if where_clause.strip(): + wheres.append(where_clause.strip()) + filters = " AND ".join(wheres) + filters = filters.replace('account_move_line__move_id', 'm').replace('account_move_line', 'l') + + # Get move lines base on sql query and Calculate the total balance of move lines + sql = ('SELECT l.id AS lid, l.account_id AS account_id, l.date AS ldate, j.code AS lcode, l.currency_id, l.amount_currency, l.ref AS lref, l.name AS lname, COALESCE(l.debit,0) AS debit, COALESCE(l.credit,0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) AS balance,\ + m.name AS move_name, c.symbol AS currency_code, p.name AS partner_name\ + FROM account_move_line l\ + JOIN account_move m ON (l.move_id=m.id)\ + LEFT JOIN res_currency c ON (l.currency_id=c.id)\ + LEFT JOIN res_partner p ON (l.partner_id=p.id)\ + JOIN account_journal j ON (l.journal_id=j.id)\ + JOIN account_account acc ON (l.account_id = acc.id) \ + WHERE l.account_id IN %s ' + filters + ' GROUP BY l.id, l.account_id, l.date, j.code, l.currency_id, l.amount_currency, l.ref, l.name, m.name, c.symbol, p.name ORDER BY ' + sql_sort) + params = (tuple(accounts.ids),) + tuple(where_params) + cr.execute(sql, params) + + for row in cr.dictfetchall(): + balance = 0 + for line in move_lines.get(row['account_id']): + balance += line['debit'] - line['credit'] + row['balance'] += balance + move_lines[row.pop('account_id')].append(row) + + # Calculate the debit, credit and balance for Accounts + account_res = [] + for account in accounts: + currency = account.currency_id and account.currency_id or account.company_id.currency_id + res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance']) + res['code'] = account.code + res['name'] = account.name + res['move_lines'] = move_lines[account.id] + for line in res.get('move_lines'): + res['debit'] += line['debit'] + res['credit'] += line['credit'] + res['balance'] = line['balance'] + if display_account == 'all': + account_res.append(res) + if display_account == 'movement' and res.get('move_lines'): + account_res.append(res) + if display_account == 'not_zero' and not currency.is_zero(res['balance']): + account_res.append(res) + + return account_res + + @api.multi + def render_html(self, data): + self.model = self.env.context.get('active_model') + docs = self.env[self.model].browse(self.env.context.get('active_id')) + + init_balance = data['form'].get('initial_balance', True) + sortby = data['form'].get('sortby', 'sort_date') + display_account = data['form']['display_account'] + codes = [] + if data['form'].get('journal_ids', False): + codes = [journal.code for journal in self.env['account.journal'].search([('id', 'in', data['form']['journal_ids'])])] + + accounts = self.env['account.account'].search([]) + accounts_res = self.with_context(data['form'].get('used_context',{}))._get_account_move_entry(accounts, init_balance, sortby, display_account) + docargs = { + 'doc_ids': self.ids, + 'doc_model': self.model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'Accounts': accounts_res, + 'print_journal': codes, + } + return self.env['report'].render('account.report_generalledger', docargs) diff --git a/addons/account/report/account_overdue_report.py b/addons/account/report/account_overdue_report.py new file mode 100644 index 00000000000..6cfd79b1bbb --- /dev/null +++ b/addons/account/report/account_overdue_report.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, fields, models + + +class ReportOverdue(models.AbstractModel): + _name = 'report.account.report_overdue' + + def _get_account_move_lines(self, partner_ids): + res = dict(map(lambda x:(x,[]), partner_ids)) + self.env.cr.execute("SELECT m.name AS move_id, l.date, l.name, l.ref, l.date_maturity, l.partner_id, l.blocked, l.amount_currency, l.currency_id, " + "CASE WHEN at.type = 'receivable' " + "THEN SUM(l.debit) " + "ELSE SUM(l.credit * -1) " + "END AS debit, " + "CASE WHEN at.type = 'receivable' " + "THEN SUM(l.credit) " + "ELSE SUM(l.debit * -1) " + "END AS credit, " + "CASE WHEN l.date_maturity < %s " + "THEN SUM(l.debit - l.credit) " + "ELSE 0 " + "END AS mat " + "FROM account_move_line l " + "JOIN account_account_type at ON (l.user_type_id = at.id) " + "JOIN account_move m ON (l.move_id = m.id) " + "WHERE l.partner_id IN %s AND at.type IN ('receivable', 'payable') GROUP BY l.date, l.name, l.ref, l.date_maturity, l.partner_id, at.type, l.blocked, l.amount_currency, l.currency_id, l.move_id, m.name", (((fields.date.today(), ) + (tuple(partner_ids),)))) + for row in self.env.cr.dictfetchall(): + res[row.pop('partner_id')].append(row) + return res + + @api.multi + def render_html(self, data): + totals = {} + lines = self._get_account_move_lines(self.ids) + lines_to_display = {} + company_currency = self.env.user.company_id.currency_id + for partner_id in self.ids: + lines_to_display[partner_id] = {} + totals[partner_id] = {} + for line_tmp in lines[partner_id]: + line = line_tmp.copy() + currency = line['currency_id'] and self.env['res.currency'].browse(line['currency_id']) or company_currency + if currency not in lines_to_display[partner_id]: + lines_to_display[partner_id][currency] = [] + totals[partner_id][currency] = dict((fn, 0.0) for fn in ['due', 'paid', 'mat', 'total']) + if line['debit'] and line['currency_id']: + line['debit'] = line['amount_currency'] + if line['credit'] and line['currency_id']: + line['credit'] = line['amount_currency'] + if line['mat'] and line['currency_id']: + line['mat'] = line['amount_currency'] + lines_to_display[partner_id][currency].append(line) + if not line['blocked']: + totals[partner_id][currency]['due'] += line['debit'] + totals[partner_id][currency]['paid'] += line['credit'] + totals[partner_id][currency]['mat'] += line['mat'] + totals[partner_id][currency]['total'] += line['debit'] - line['credit'] + docargs = { + 'doc_ids': self.ids, + 'doc_model': 'res.partner', + 'docs': self.env['res.partner'].browse(self.ids), + 'time': time, + 'Lines': lines_to_display, + 'Totals': totals, + 'Date': fields.date.today(), + } + return self.env['report'].render('account.report_overdue', values=docargs) diff --git a/addons/account/report/account_report_financial.py b/addons/account/report/account_report_financial.py new file mode 100644 index 00000000000..c5139dadd98 --- /dev/null +++ b/addons/account/report/account_report_financial.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +class ReportFinancial(models.AbstractModel): + _name = 'report.account.report_financial' + + def _compute_account_balance(self, accounts): + """ compute the balance, debit and credit for the provided accounts + """ + mapping = { + 'balance': "COALESCE(SUM(debit),0) - COALESCE(SUM(credit), 0) as balance", + 'debit': "COALESCE(SUM(debit), 0) as debit", + 'credit': "COALESCE(SUM(credit), 0) as credit", + } + + res = {} + for account in accounts: + res[account.id] = dict((fn, 0.0) for fn in mapping.keys()) + if accounts: + tables, where_clause, where_params = self.env['account.move.line']._query_get() + tables = tables.replace('"', '') if tables else "account_move_line" + wheres = [""] + if where_clause.strip(): + wheres.append(where_clause.strip()) + filters = " AND ".join(wheres) + request = "SELECT account_id as id, " + ', '.join(mapping.values()) + \ + " FROM " + tables + \ + " WHERE account_id IN %s " \ + + filters + \ + " GROUP BY account_id" + params = (tuple(accounts._ids),) + tuple(where_params) + self.env.cr.execute(request, params) + for row in self.env.cr.dictfetchall(): + res[row['id']] = row + return res + + def _compute_report_balance(self, reports): + '''returns a dictionary with key=the ID of a record and value=the credit, debit and balance amount + computed for this record. If the record is of type : + 'accounts' : it's the sum of the linked accounts + 'account_type' : it's the sum of leaf accoutns with such an account_type + 'account_report' : it's the amount of the related report + 'sum' : it's the sum of the children of this record (aka a 'view' record)''' + res = {} + fields = ['credit', 'debit', 'balance'] + for report in reports: + if report.id in res: + continue + res[report.id] = dict((fn, 0.0) for fn in fields) + if report.type == 'accounts': + # it's the sum of the linked accounts + res[report.id]['account'] = self._compute_account_balance(report.account_ids) + for value in res[report.id]['account'].values(): + for field in fields: + res[report.id][field] += value.get(field) + elif report.type == 'account_type': + # it's the sum the leaf accounts with such an account type + accounts = self.env['account.account'].search([('user_type_id', 'in', report.account_type_ids.ids)]) + res[report.id]['account'] = self._compute_account_balance(accounts) + for value in res[report.id]['account'].values(): + for field in fields: + res[report.id][field] += value.get(field) + elif report.type == 'account_report' and report.account_report_id: + # it's the amount of the linked report + res2 = self._compute_report_balance(report.account_report_id) + for key, value in res2.items(): + for field in fields: + res[report.id][field] += value[field] + elif report.type == 'sum': + # it's the sum of the children of this account.report + res2 = self._compute_report_balance(report.children_ids) + for key, value in res2.items(): + for field in fields: + res[report.id][field] += value[field] + return res + + def get_account_lines(self, data): + lines = [] + account_report = self.env['account.financial.report'].search([('id', '=', data['account_report_id'][0])]) + child_reports = account_report._get_children_by_order() + res = self.with_context(data.get('used_context'))._compute_report_balance(child_reports) + if data['enable_filter']: + comparison_res = self.with_context(data.get('comparison_context'))._compute_report_balance(child_reports) + for report_id, value in comparison_res.items(): + res[report_id]['comp_bal'] = value['balance'] + report_acc = res[report_id].get('account') + if report_acc: + for account_id, val in comparison_res[report_id].get('account').items(): + report_acc[account_id]['comp_bal'] = val['balance'] + + for report in child_reports: + vals = { + 'name': report.name, + 'balance': res[report.id]['balance'] * report.sign, + 'type': 'report', + 'level': bool(report.style_overwrite) and report.style_overwrite or report.level, + 'account_type': report.type or False, #used to underline the financial report balances + } + if data['debit_credit']: + vals['debit'] = res[report.id]['debit'] + vals['credit'] = res[report.id]['credit'] + + if data['enable_filter']: + vals['balance_cmp'] = res[report.id]['comp_bal'] * report.sign + + lines.append(vals) + if report.display_detail == 'no_detail': + #the rest of the loop is used to display the details of the financial report, so it's not needed here. + continue + + if res[report.id].get('account'): + for account_id, value in res[report.id]['account'].items(): + #if there are accounts to display, we add them to the lines with a level equals to their level in + #the COA + 1 (to avoid having them with a too low level that would conflicts with the level of data + #financial reports for Assets, liabilities...) + flag = False + account = self.env['account.account'].browse(account_id) + vals = { + 'name': account.code + ' ' + account.name, + 'balance': value['balance'] * report.sign or 0.0, + 'type': 'account', + 'level': report.display_detail == 'detail_with_hierarchy' and 4, + 'account_type': account.internal_type, + } + if data['debit_credit']: + vals['debit'] = value['debit'] + vals['credit'] = value['credit'] + if not account.company_id.currency_id.is_zero(vals['debit']) or not account.company_id.currency_id.is_zero(vals['credit']): + flag = True + if not account.company_id.currency_id.is_zero(vals['balance']): + flag = True + if data['enable_filter']: + vals['balance_cmp'] = value['comp_bal'] * report.sign + if not account.company_id.currency_id.is_zero(vals['balance_cmp']): + flag = True + if flag: + lines.append(vals) + return lines + + @api.multi + def render_html(self, data): + self.model = self.env.context.get('active_model') + docs = self.env[self.model].browse(self.env.context.get('active_id')) + report_lines = self.get_account_lines(data.get('form')) + docargs = { + 'doc_ids': self.ids, + 'doc_model': self.model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'get_account_lines': report_lines, + } + return self.env['report'].render('account.report_financial', docargs) diff --git a/addons/account/test/account_report.yml b/addons/account/test/account_report.yml index 3383bfcc93a..1ca246e6ce7 100644 --- a/addons/account/test/account_report.yml +++ b/addons/account/test/account_report.yml @@ -72,18 +72,10 @@ from openerp.tools import test_reports test_reports.try_report_action(cr, uid, 'action_account_general_journal',wiz_data=data_dict, context=ctx, our_module='account') - - Print the General Ledger Report in Normal Mode + Print the General Ledger Report (in Landscape Mode) - !python {model: account.account}: | ctx={} - data_dict = {'chart_account_id':ref('account.chart0'),'landscape':False} - from openerp.tools import test_reports - test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu',wiz_data=data_dict, context=ctx, our_module='account') -- - Print the General Ledger Report in Landscape Mode -- - !python {model: account.account}: | - ctx={'landscape': True} data_dict = {'chart_account_id':ref('account.chart0')} from openerp.tools import test_reports test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu',wiz_data=data_dict, context=ctx, our_module='account') diff --git a/addons/account/views/account_financial_report_data.xml b/addons/account/views/account_financial_report_data.xml new file mode 100644 index 00000000000..fc224a0f1b5 --- /dev/null +++ b/addons/account/views/account_financial_report_data.xml @@ -0,0 +1,68 @@ + + + + + + Profit and Loss + + sum + + + + Income + + + detail_with_hierarchy + account_type + + + + + Expense + + + detail_with_hierarchy + account_type + + + + + Balance Sheet + sum + + + + Assets + + detail_with_hierarchy + account_type + + + + + Liability + + no_detail + sum + + + + Liability + + detail_with_hierarchy + account_type + + + + + Profit (Loss) to report + + no_detail + account_report + + + + + diff --git a/addons/account/views/account_invoice_view.xml b/addons/account/views/account_invoice_view.xml index f53b08c6c45..0580a4a460f 100644 --- a/addons/account/views/account_invoice_view.xml +++ b/addons/account/views/account_invoice_view.xml @@ -153,6 +153,7 @@ +
@@ -160,8 +161,8 @@
-
- +
+
diff --git a/addons/account/views/account_menuitem.xml b/addons/account/views/account_menuitem.xml index f01ad344c3e..732a9e956d3 100644 --- a/addons/account/views/account_menuitem.xml +++ b/addons/account/views/account_menuitem.xml @@ -27,6 +27,9 @@ + + + diff --git a/addons/account/views/account_report.xml b/addons/account/views/account_report.xml index 49137185597..0b601b0a655 100644 --- a/addons/account/views/account_report.xml +++ b/addons/account/views/account_report.xml @@ -23,5 +23,51 @@ attachment_use="False" /> + + + + + + + + + + diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 27196e9d72f..f6621a6197d 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -1798,6 +1798,99 @@ parent="menu_finance_payables" action="base.action_partner_supplier_form" sequence="100"/> + + + + account.financial.report.form + account.financial.report + +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + account.financial.report.tree + account.financial.report + + + + + + + + + + + + account.financial.report.search + account.financial.report + + + + + + + + + + + + + + + Financial Reports + ir.actions.act_window + account.financial.report + form + tree,form + + + + + + + + account.report.hierarchy + account.financial.report + children_ids + + + + + + + + + + + + Financial Reports Hierarchy + account.financial.report + tree + + [('parent_id','=',False)] + + + diff --git a/addons/account/views/company_view.xml b/addons/account/views/company_view.xml index 98753231cda..06e1648b4a3 100644 --- a/addons/account/views/company_view.xml +++ b/addons/account/views/company_view.xml @@ -14,6 +14,12 @@ + + + + + + diff --git a/addons/account/views/report_agedpartnerbalance.xml b/addons/account/views/report_agedpartnerbalance.xml new file mode 100644 index 00000000000..e4e3a8451b3 --- /dev/null +++ b/addons/account/views/report_agedpartnerbalance.xml @@ -0,0 +1,95 @@ + + + + diff --git a/addons/account/views/report_financial.xml b/addons/account/views/report_financial.xml new file mode 100644 index 00000000000..2647ed10fa7 --- /dev/null +++ b/addons/account/views/report_financial.xml @@ -0,0 +1,110 @@ + + + + diff --git a/addons/account/views/report_generalledger.xml b/addons/account/views/report_generalledger.xml new file mode 100644 index 00000000000..9e2300098b1 --- /dev/null +++ b/addons/account/views/report_generalledger.xml @@ -0,0 +1,107 @@ + + + + + diff --git a/addons/account/views/report_overdue.xml b/addons/account/views/report_overdue.xml new file mode 100644 index 00000000000..d92a5c8c67d --- /dev/null +++ b/addons/account/views/report_overdue.xml @@ -0,0 +1,88 @@ + + + + + + diff --git a/addons/account/views/report_trialbalance.xml b/addons/account/views/report_trialbalance.xml new file mode 100644 index 00000000000..5470f6385ed --- /dev/null +++ b/addons/account/views/report_trialbalance.xml @@ -0,0 +1,68 @@ + + + + diff --git a/addons/account/views/web_planner_data.xml b/addons/account/views/web_planner_data.xml index a3b0ea37eeb..a163762849a 100644 --- a/addons/account/views/web_planner_data.xml +++ b/addons/account/views/web_planner_data.xml @@ -195,7 +195,7 @@

To use the multi-currency option:

  1. Activate the option in the Accounting Settings
  2. -
  3. Review the list of available currencies (from the Configuration menu)
  4. +
  5. Review the list of available currencies (from the Configuration menu)

@@ -225,14 +225,14 @@

- If you have less than 200 contacts, we recommand you + If you have less than 200 contacts, we recommend you to create them manually.

@@ -284,7 +284,7 @@
diff --git a/addons/account/wizard/__init__.py b/addons/account/wizard/__init__.py index 185cab9ac96..b5eadcd620f 100644 --- a/addons/account/wizard/__init__.py +++ b/addons/account/wizard/__init__.py @@ -9,3 +9,10 @@ import account_invoice_state import account_validate_account_move import pos_box import account_move_reversal +import account_report_common +import account_report_common_account +import account_report_common_partner +import account_report_general_ledger +import account_report_trial_balance +import account_financial_report +import account_report_aged_partner_balance diff --git a/addons/account/wizard/account_financial_report.py b/addons/account/wizard/account_financial_report.py new file mode 100644 index 00000000000..040093a4531 --- /dev/null +++ b/addons/account/wizard/account_financial_report.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +from openerp import api, fields, models + + +class AccountingReport(models.TransientModel): + _name = "accounting.report" + _inherit = "account.common.report" + _description = "Accounting Report" + + @api.model + def _get_account_report(self): + reports = [] + if self._context.get('active_id'): + menu = self.env['ir.ui.menu'].browse(self._context.get('active_id')).name + reports = self.env['account.financial.report'].search([('name', 'ilike', menu)]) + return reports and reports[0] or False + + enable_filter = fields.Boolean(string='Enable Comparison') + account_report_id = fields.Many2one('account.financial.report', string='Account Reports', required=True, default=_get_account_report) + label_filter = fields.Char(string='Column Label', help="This label will be displayed on report to show the balance computed for the given comparison filter.") + filter_cmp = fields.Selection([('filter_no', 'No Filters'), ('filter_date', 'Date')], string='Filter by', required=True, default='filter_no') + date_from_cmp = fields.Date(string='Start Date') + date_to_cmp = fields.Date(string='End Date') + debit_credit = fields.Boolean(string='Display Debit/Credit Columns', help="This option allows you to get more details about the way your balances are computed. Because it is space consuming, we do not allow to use it while doing a comparison.") + + def _build_comparison_context(self, data): + result = {} + result['journal_ids'] = 'journal_ids' in data['form'] and data['form']['journal_ids'] or False + result['state'] = 'target_move' in data['form'] and data['form']['target_move'] or '' + if data['form']['filter_cmp'] == 'filter_date': + result['date_from'] = data['form']['date_from_cmp'] + result['date_to'] = data['form']['date_to_cmp'] + result['strict_range'] = True + return result + + @api.multi + def check_report(self): + res = super(AccountingReport, self).check_report() + data = {} + data['form'] = self.read(['account_report_id', 'date_from_cmp', 'date_to_cmp', 'journal_ids', 'filter_cmp', 'target_move'])[0] + for field in ['account_report_id']: + if isinstance(data['form'][field], tuple): + data['form'][field] = data['form'][field][0] + comparison_context = self._build_comparison_context(data) + res['data']['form']['comparison_context'] = comparison_context + return res + + def _print_report(self, data): + data['form'].update(self.read(['date_from_cmp', 'debit_credit', 'date_to_cmp', 'filter_cmp', 'account_report_id', 'enable_filter', 'label_filter', 'target_move'])[0]) + return self.env['report'].get_action(self, 'account.report_financial', data=data) diff --git a/addons/account/wizard/account_financial_report_view.xml b/addons/account/wizard/account_financial_report_view.xml new file mode 100644 index 00000000000..395b65331bd --- /dev/null +++ b/addons/account/wizard/account_financial_report_view.xml @@ -0,0 +1,72 @@ + + + + + Accounting Report + accounting.report + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Balance Sheet + accounting.report + ir.actions.act_window + form + form + + new + + + + + + + Profit and Loss + accounting.report + ir.actions.act_window + form + form + + new + + + + + + + Financial Reports + accounting.report + ir.actions.act_window + form + form + + new + + + + + diff --git a/addons/account/wizard/account_report_aged_partner_balance.py b/addons/account/wizard/account_report_aged_partner_balance.py new file mode 100644 index 00000000000..c5579a32a56 --- /dev/null +++ b/addons/account/wizard/account_report_aged_partner_balance.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +import time +from datetime import datetime +from dateutil.relativedelta import relativedelta +from openerp import api, fields, models, _ +from openerp.exceptions import UserError + + +class AccountAgedTrialBalance(models.TransientModel): + + _name = 'account.aged.trial.balance' + _inherit = 'account.common.partner.report' + _description = 'Account Aged Trial balance Report' + + period_length = fields.Integer(string='Period Length (days)', required=True, default=30) + journal_ids = fields.Many2many('account.journal', string='Journals', required=True) + date_from = fields.Date(default=lambda *a: time.strftime('%Y-%m-%d')) + + def _print_report(self, data): + res = {} + data = self.pre_print_report(data) + data['form'].update(self.read(['period_length'])[0]) + period_length = data['form']['period_length'] + if period_length<=0: + raise UserError(_('You must set a period length greater than 0.')) + if not data['form']['date_from']: + raise UserError(_('You must set a start date.')) + + start = datetime.strptime(data['form']['date_from'], "%Y-%m-%d") + + for i in range(5)[::-1]: + stop = start - relativedelta(days=period_length) + res[str(i)] = { + 'name': (i!=0 and (str((5-(i+1)) * period_length) + '-' + str((5-i) * period_length)) or ('+'+str(4 * period_length))), + 'stop': start.strftime('%Y-%m-%d'), + 'start': (i!=0 and stop.strftime('%Y-%m-%d') or False), + } + start = stop - relativedelta(days=1) + data['form'].update(res) + return self.env['report'].with_context(landscape=True).get_action(self, 'account.report_agedpartnerbalance', data=data) diff --git a/addons/account/wizard/account_report_aged_partner_balance_view.xml b/addons/account/wizard/account_report_aged_partner_balance_view.xml new file mode 100644 index 00000000000..133f20c0347 --- /dev/null +++ b/addons/account/wizard/account_report_aged_partner_balance_view.xml @@ -0,0 +1,44 @@ + + + + + Aged Partner Balance + account.aged.trial.balance + +
+ +
+ + + Aged Partner Balance + account.aged.trial.balance + ir.actions.act_window + form + tree,form + + {} + new + + + + +
diff --git a/addons/account/wizard/account_report_common.py b/addons/account/wizard/account_report_common.py new file mode 100644 index 00000000000..a11404a34bd --- /dev/null +++ b/addons/account/wizard/account_report_common.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +from openerp import api, fields, models, _ + + +class AccountCommonReport(models.TransientModel): + _name = "account.common.report" + _description = "Account Common Report" + + company_id = fields.Many2one('res.company', string='Company', readonly=True, default=lambda self: self.env.user.company_id) + journal_ids = fields.Many2many('account.journal', string='Journals', required=True, default=lambda self: self.env['account.journal'].search([])) + date_from = fields.Date(string='Start Date') + date_to = fields.Date(string='End Date') + target_move = fields.Selection([('posted', 'All Posted Entries'), + ('all', 'All Entries'), + ], string='Target Moves', required=True, default='posted') + + def _build_contexts(self, data): + result = {} + result['journal_ids'] = 'journal_ids' in data['form'] and data['form']['journal_ids'] or False + result['state'] = 'target_move' in data['form'] and data['form']['target_move'] or '' + result['date_from'] = data['form']['date_from'] or False + result['date_to'] = data['form']['date_to'] or False + result['strict_range'] = True if result['date_from'] else False + return result + + def _print_report(self, data): + raise (_('Error!'), _('Not implemented.')) + + @api.multi + def check_report(self): + self.ensure_one() + data = {} + data['ids'] = self.env.context.get('active_ids', []) + data['model'] = self.env.context.get('active_model', 'ir.ui.menu') + data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move'])[0] + used_context = self._build_contexts(data) + data['form']['used_context'] = dict(used_context, lang=self.env.context.get('lang', 'en_US')) + return self._print_report(data) diff --git a/addons/account/wizard/account_report_common_account.py b/addons/account/wizard/account_report_common_account.py new file mode 100644 index 00000000000..e483b408d8b --- /dev/null +++ b/addons/account/wizard/account_report_common_account.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from openerp import api, fields, models + + +class AccountCommonAccountReport(models.TransientModel): + _name = 'account.common.account.report' + _description = 'Account Common Account Report' + _inherit = "account.common.report" + + display_account = fields.Selection([('all','All'), ('movement','With movements'), + ('not_zero','With balance is not equal to 0'),], + string='Display Accounts', required=True, default='movement') + + @api.multi + def pre_print_report(self, data): + data['form'].update(self.read(['display_account'])[0]) + return data diff --git a/addons/account/wizard/account_report_common_partner.py b/addons/account/wizard/account_report_common_partner.py new file mode 100644 index 00000000000..c4ca6e8dad2 --- /dev/null +++ b/addons/account/wizard/account_report_common_partner.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from openerp import fields, models + + +class AccountingCommonPartnerReport(models.TransientModel): + _name = 'account.common.partner.report' + _description = 'Account Common Partner Report' + _inherit = "account.common.report" + + result_selection = fields.Selection([('customer', 'Receivable Accounts'), + ('supplier', 'Payable Accounts'), + ('customer_supplier', 'Receivable and Payable Accounts') + ], string="Partner's", required=True, default='customer') + + def pre_print_report(self, data): + data['form'].update(self.read(['result_selection'])[0]) + return data diff --git a/addons/account/wizard/account_report_common_view.xml b/addons/account/wizard/account_report_common_view.xml new file mode 100644 index 00000000000..5f210eff9e7 --- /dev/null +++ b/addons/account/wizard/account_report_common_view.xml @@ -0,0 +1,36 @@ + + + + + Common Report + account.common.report + +
+ + + + + + + + + +
+
+ +
+
+ + + Common Report + account.common.report + form + form + + new + + +
diff --git a/addons/account/wizard/account_report_general_ledger.py b/addons/account/wizard/account_report_general_ledger.py new file mode 100644 index 00000000000..0f9d959c7f7 --- /dev/null +++ b/addons/account/wizard/account_report_general_ledger.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from openerp import fields, models, _ +from openerp.exceptions import UserError + + +class AccountReportGeneralLedger(models.TransientModel): + _inherit = "account.common.account.report" + _name = "account.report.general.ledger" + _description = "General Ledger Report" + + initial_balance = fields.Boolean(string='Include Initial Balances', + help='If you selected date, this field allow you to add a row to display the amount of debit/credit/balance that precedes the filter you\'ve set.') + sortby = fields.Selection([('sort_date', 'Date'), ('sort_journal_partner', 'Journal & Partner')], string='Sort by', required=True, default='sort_date') + journal_ids = fields.Many2many('account.journal', 'account_report_general_ledger_journal_rel', 'account_id', 'journal_id', string='Journals', required=True) + + def _print_report(self, data): + data = self.pre_print_report(data) + data['form'].update(self.read(['initial_balance', 'sortby'])[0]) + if data['form'].get('initial_balance') and not data['form'].get('date_from'): + raise UserError(_("You must define a Start Date")) + return self.env['report'].with_context(landscape=True).get_action(self, 'account.report_generalledger', data=data) diff --git a/addons/account/wizard/account_report_general_ledger_view.xml b/addons/account/wizard/account_report_general_ledger_view.xml new file mode 100644 index 00000000000..91fbdc9cb6b --- /dev/null +++ b/addons/account/wizard/account_report_general_ledger_view.xml @@ -0,0 +1,47 @@ + + + + + General Ledger + account.report.general.ledger + + + + + + + + + + + + + + + General Ledger + ir.actions.act_window + account.report.general.ledger + form + form + + new + + + + + General Ledger + client_print_multi + + action + account.account + + + + + diff --git a/addons/account/wizard/account_report_trial_balance.py b/addons/account/wizard/account_report_trial_balance.py new file mode 100644 index 00000000000..251c8c09dbc --- /dev/null +++ b/addons/account/wizard/account_report_trial_balance.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from openerp import fields, models + + +class AccountBalanceReport(models.TransientModel): + _inherit = "account.common.account.report" + _name = 'account.balance.report' + _description = 'Trial Balance Report' + + journal_ids = fields.Many2many('account.journal', 'account_balance_report_journal_rel', 'account_id', 'journal_id', string='Journals', required=True, default=[]) + + def _print_report(self, data): + data = self.pre_print_report(data) + return self.env['report'].get_action(self, 'account.report_trialbalance', data=data) diff --git a/addons/account/wizard/account_report_trial_balance_view.xml b/addons/account/wizard/account_report_trial_balance_view.xml new file mode 100644 index 00000000000..a610d5e863d --- /dev/null +++ b/addons/account/wizard/account_report_trial_balance_view.xml @@ -0,0 +1,44 @@ + + + + + + Trial Balance + account.balance.report + + + + + + + + + + + + + + Trial Balance + ir.actions.act_window + account.balance.report + form + form + + new + + + + + + + Trial Balance + client_print_multi + + action + account.account + + + diff --git a/addons/account_asset/views/account_asset_view.xml b/addons/account_asset/views/account_asset_view.xml index fb8f009fdd2..8f60c4b0b3a 100644 --- a/addons/account_asset/views/account_asset_view.xml +++ b/addons/account_asset/views/account_asset_view.xml @@ -236,11 +236,6 @@ domain="[('type', '=', 'purchase')]" context="{'default_type': 'purchase'}"/>
- - - diff --git a/addons/account_check_printing/account_journal.py b/addons/account_check_printing/account_journal.py index 9ae6f680f93..1d10d358498 100644 --- a/addons/account_check_printing/account_journal.py +++ b/addons/account_check_printing/account_journal.py @@ -37,25 +37,26 @@ class AccountJournal(models.Model): @api.model def create(self, vals): - if not vals.get('check_sequence_id'): - vals.update({'check_sequence_id': self._create_check_sequence(vals).id}) - return super(AccountJournal, self).create(vals) + rec = super(AccountJournal, self).create(vals) + if not rec.check_sequence_id: + rec._create_check_sequence() + return rec @api.one def copy(self, default=None): rec = super(AccountJournal, self).copy(default) - rec.write({'check_sequence_id': self._create_check_sequence({'name': rec.name, 'company_id': rec.company_id.id}).id}) + rec._create_check_sequence() return rec - @api.model - def _create_check_sequence(self, vals): + @api.one + def _create_check_sequence(self): """ Create a check sequence for the journal """ - return self.env['ir.sequence'].sudo().create({ - 'name': vals['name'] + _(" : Check Number Sequence"), + self.check_sequence_id = self.env['ir.sequence'].sudo().create({ + 'name': self.name + _(" : Check Number Sequence"), 'implementation': 'no_gap', 'padding': 5, 'number_increment': 1, - 'company_id': vals.get('company_id', self.env.user.company_id.id), + 'company_id': self.company_id.id, }) def _default_outbound_payment_methods(self): @@ -70,8 +71,7 @@ class AccountJournal(models.Model): check_printing = self.env.ref('account_check_printing.account_payment_method_check') bank_journals = self.search([('type', '=', 'bank')]) for bank_journal in bank_journals: - check_sequence = self._create_check_sequence({'name': bank_journal.name, 'company_id': bank_journal.company_id.id}) + bank_journal._create_check_sequence() bank_journal.write({ 'outbound_payment_method_ids': [(4, check_printing.id, None)], - 'check_sequence_id': check_sequence.id, }) diff --git a/addons/analytic/models/analytic.py b/addons/analytic/models/analytic.py index 35ec3a0992b..1ea482e1601 100644 --- a/addons/analytic/models/analytic.py +++ b/addons/analytic/models/analytic.py @@ -41,14 +41,6 @@ class account_analytic_account(models.Model): account.credit = data_credit.get(account.id, 0.0) account.balance = account.credit - account.debit - @api.model - def _default_company(self): - return self.env.user.company_id.id - - @api.model - def _default_user(self): - return self.env.user.id - name = fields.Char(string='Analytic Account', index=True, required=True, track_visibility='onchange') code = fields.Char(string='Reference', index=True, track_visibility='onchange') account_type = fields.Selection([ @@ -58,7 +50,7 @@ class account_analytic_account(models.Model): tag_ids = fields.Many2many('account.analytic.tag', 'account_analytic_account_tag_rel', 'account_id', 'tag_id', string='Tags', copy=True) line_ids = fields.One2many('account.analytic.line', 'account_id', string="Analytic Lines") - company_id = fields.Many2one('res.company', string='Company', required=True, default=_default_company) + company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.user.company_id) partner_id = fields.Many2one('res.partner', string='Customer') balance = fields.Monetary(compute='_compute_debit_credit_balance', string='Balance') diff --git a/addons/auth_signup/views/auth_signup_login.xml b/addons/auth_signup/views/auth_signup_login.xml index fb201c98d81..149c490ad69 100644 --- a/addons/auth_signup/views/auth_signup_login.xml +++ b/addons/auth_signup/views/auth_signup_login.xml @@ -89,7 +89,7 @@ diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index dae722e70ac..5e7955c88ba 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -1197,6 +1197,8 @@ Update your business card, phone book, social media,... Send an email right now res['done']['target'] = user.target_sales_done res['won']['target'] = user.target_sales_won + res['currency_id'] = user.company_id.currency_id.id + return res def modify_target_sales_dashboard(self, cr, uid, target_name, target_value, context=None): diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index ed21c793d48..71b21f4518a 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -292,6 +292,7 @@ + @@ -317,7 +318,7 @@
- - + -
oe_kanban_text_red diff --git a/addons/crm/i18n/crm.pot b/addons/crm/i18n/crm.pot index e0b9037125d..72bcfcdc1c9 100644 --- a/addons/crm/i18n/crm.pot +++ b/addons/crm/i18n/crm.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 9.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-09-07 14:39+0000\n" -"PO-Revision-Date: 2015-09-07 14:39+0000\n" +"POT-Creation-Date: 2015-09-10 10:19+0000\n" +"PO-Revision-Date: 2015-09-10 10:19+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -63,11 +63,6 @@ msgstr "" msgid " Install Events" msgstr "" -#. module: crm -#: model:ir.ui.view,arch_db:crm.crm_planner -msgid " Install Live Chat" -msgstr "" - #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid " Install Mailing" @@ -83,6 +78,11 @@ msgstr "" msgid " Install Surveys" msgstr "" +#. module: crm +#: model:ir.ui.view,arch_db:crm.crm_planner +msgid " Install Website Live Chat" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid " Install e-Commerce" @@ -101,7 +101,7 @@ msgid "\n" " Using templates can boost the quality of your\n" " quotations and their success rate. However,\n" " creating such templates can be a huge effort.\n" -" We recommand to start with standard quotations\n" +" We recommend to start with standard quotations\n" " and upgrade later." msgstr "" @@ -185,7 +185,7 @@ msgstr "" msgid "\n" " \n" " Import a file
\n" -" Recommanded if >100 products\n" +" Recommended if >100 products\n" "
" msgstr "" @@ -221,7 +221,7 @@ msgstr "" msgid "\n" " \n" " Create manually
\n" -" Recommanded if <100 products\n" +" Recommended if <100 products\n" "
" msgstr "" @@ -336,11 +336,6 @@ msgid "Forecast future revenues
\n" " accurate expected revenues by closing date." msgstr "" -#. module: crm -#: model:ir.ui.view,arch_db:crm.crm_planner -msgid "Live Chat" -msgstr "" - #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "Mass mailing" @@ -446,6 +441,11 @@ msgid "Trainings
\n" " apps of Odoo:" msgstr "" +#. module: crm +#: model:ir.ui.view,arch_db:crm.crm_planner +msgid "Website Live Chat" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "You called the prospect for a follow up on your offer" @@ -453,7 +453,7 @@ msgstr "" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner -msgid "You understand the customer need, it's budget and his pain points" +msgid "You understand the customer's needs and pain points, and you have a fairly good idea of his budget to spend" msgstr "" #. module: crm @@ -503,6 +503,16 @@ msgstr "" msgid "Accept Emails From" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_property_account_payable_id +msgid "Account Payable" +msgstr "" + +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_property_account_receivable_id +msgid "Account Receivable" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_activity_view_search msgid "Action Search" @@ -709,6 +719,11 @@ msgstr "" msgid "B2C" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_bank_account_count +msgid "Bank" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "Better structure the sales process" @@ -902,6 +917,11 @@ msgstr "" msgid "Color Index" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_ref_company_ids +msgid "Companies that refers to partner" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_activity_report_company_id #: model:ir.model.fields,field_description:crm.field_crm_lead_company_id @@ -957,6 +977,12 @@ msgstr "" msgid "Contacts" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_contract_ids +#: model:ir.model.fields,field_description:crm.field_res_users_contracts_count +msgid "Contracts" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead2opportunity_partner_mass_name #: model:ir.model.fields,field_description:crm.field_crm_lead2opportunity_partner_name @@ -1119,6 +1145,11 @@ msgstr "" msgid "Currency" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_currency_id +msgid "Currency id" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_opportunity_report_view_search msgid "Current" @@ -1154,6 +1185,11 @@ msgstr "" msgid "Customer Name" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_property_payment_term_id +msgid "Customer Payment Term" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.view_crm_lead2opportunity_partner #: model:ir.ui.view,arch_db:crm.view_crm_lead2opportunity_partner_mass @@ -1477,6 +1513,11 @@ msgstr "" msgid "Finished" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_property_account_position_id +msgid "Fiscal Position" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_stage_fold msgid "Folded in Pipeline" @@ -1606,6 +1647,11 @@ msgstr "" msgid "Happy Selling!
- The Odoo Team" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_has_unreconciled_entries +msgid "Has unreconciled entries" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "Have clear forecasts on sales" @@ -1618,7 +1664,7 @@ msgstr "" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner -msgid "Here are a few examples of document you should provide to your sales team based on the sales stage:" +msgid "Here are a few examples of documents you should provide to your sales team based on the sales stage:" msgstr "" #. module: crm @@ -1701,7 +1747,7 @@ msgstr "" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner -msgid "If you have less than 200 contacts, we recommand you\n" +msgid "If you have less than 200 contacts, we recommend you\n" " to create them manually." msgstr "" @@ -1737,6 +1783,12 @@ msgstr "" msgid "In Odoo, there are 3 different ways to manage your products prices.
" msgstr "" +#. module: crm +#: code:addons/crm/sales_team.py:15 +#, python-format +msgid "Incoming" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "Incoming email create leads automatically when a new prospect contacts you.\n" @@ -1759,6 +1811,11 @@ msgstr "" msgid "Invoice Analysis" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_invoice_ids +msgid "Invoices" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_base_partner_merge_automatic_wizard_group_by_is_company msgid "Is Company" @@ -1769,6 +1826,12 @@ msgstr "" msgid "Is Follower" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_issued_total +#: model:ir.model.fields,field_description:crm.field_res_users_journal_item_count +msgid "Journal Items" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_base_partner_merge_automatic_wizard_exclude_journal_item msgid "Journal Items associated to the contact" @@ -1849,6 +1912,21 @@ msgstr "" msgid "Last Updated on" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_calendar_last_notif_ack +msgid "Last notification marked as read from base Calendar" +msgstr "" + +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_last_time_entries_checked +msgid "Last time the invoices & payments matching was performed for this partner. It is set either if there's not at least an unreconciled debit and an unreconciled credit or if you click the \"Done\" button." +msgstr "" + +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_last_time_entries_checked +msgid "Latest Invoices & Payments Matching Date" +msgstr "" + #. module: crm #: code:addons/crm/crm_lead.py:834 #: selection:crm.activity.report,lead_type:0 @@ -2297,10 +2375,8 @@ msgid "Negotiation" msgstr "" #. module: crm -#: code:addons/crm/sales_team.py:15 #: model:crm.stage,name:crm.crm_stage_2_1 #: model:crm.stage,name:crm.stage_lead1 -#, python-format msgid "New" msgstr "" @@ -2415,7 +2491,7 @@ msgstr "" #. module: crm #: model:ir.model.fields,help:crm.field_crm_activity_days -msgid "Number of days before doing fulfilling the action, allowing to plan the action date." +msgid "Number of days before executing the action, allowing you to plan the date of the action." msgstr "" #. module: crm @@ -2448,7 +2524,7 @@ msgstr "" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner -msgid "Odoo is the world's only software to have a full integration of Marketing Apps your sales channel: insight sales, point of sale, ecommerce." +msgid "Odoo is the world's only software to have a full integration of Marketing Apps for your sales channel: insight sales, point of sale, ecommerce." msgstr "" #. module: crm @@ -2641,12 +2717,12 @@ msgstr "" #. module: crm #: model:ir.model.fields,help:crm.field_crm_team_alias_parent_model_id -msgid "Parent model holding the alias. The model holding the alias referenceis not necessarily the model given by alias_model_id(example: project (parent_model) and task (model))" +msgid "Parent model holding the alias. The model holding the alias reference is not necessarily the model given by alias_model_id (example: project (parent_model) and task (model))" msgstr "" #. module: crm #: model:ir.model.fields,help:crm.field_crm_activity_parent_id -msgid "Parent subtype, used for automatic subscription. This field is notcorrectly named. For example on a project, project subtypes haveparent_id to task-related subtypes." +msgid "Parent subtype, used for automatic subscription. This field is not correctly named. For example on a project, the parent_id of project subtypes refers to task-related subtypes." msgstr "" #. module: crm @@ -2677,6 +2753,11 @@ msgstr "" msgid "Partners" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_debit_limit +msgid "Payable Limit" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead_phone msgid "Phone" @@ -2705,12 +2786,20 @@ msgstr "" #. module: crm #: model:ir.actions.act_window,help:crm.crm_opportunity_report_action +msgid "Pipeline Analysis gives you an instant access to\n" +"your opportunities with information such as the expected revenue, planned cost,\n" +"missed deadlines or the number of interactions per opportunity. This report is\n" +"mainly used by the sales manager in order to do the periodic review with the\n" +"teams of the sales pipeline." +msgstr "" + +#. module: crm #: model:ir.actions.act_window,help:crm.crm_opportunity_report_action_graph msgid "Pipeline Analysis gives you an instant access to\n" "your opportunities with information such as the expected revenue, planned cost,\n" -"µmissed deadlines or the number of interactions per opportunity. This report is\n" -"mainly used by the sales manager in order to do the periodic review with the\n" -"teams of the sales pipeline." +"missed deadlines or the number of interactions per opportunity. This report is\n" +"mainly used by the sales manager in order to periodically review the pipeline\n" +"with the the sales teams." msgstr "" #. module: crm @@ -3008,7 +3097,7 @@ msgstr "" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner -msgid "Show advanced filters and options by clicking on next to the search bar." +msgid "Show advanced filters and options by clicking on the magnifying glass icon next to the search bar." msgstr "" #. module: crm @@ -3220,6 +3309,11 @@ msgstr "" msgid "The first stage is usually \"New\" and the last one is \"Won\"" msgstr "" +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_property_account_position_id +msgid "The fiscal position will determine taxes and accounts used for the partner." +msgstr "" + #. module: crm #: model:ir.model.fields,help:crm.field_crm_team_alias_model_id msgid "The model (Odoo Document Kind) to which this alias corresponds. Any incoming email that does not reply to an existing record will cause the creation of a new record of this model (e.g. a Project Task)" @@ -3240,6 +3334,11 @@ msgstr "" msgid "The owner of records created upon receiving emails on this alias. If this field is not set the system will attempt to find the right owner based on the sender (From) address, or will use the Administrator account if no system user is found for that address." msgstr "" +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_has_unreconciled_entries +msgid "The partner has at least one unreconciled debit and credit since last time the invoices & payments matching was performed." +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "The point of contact for all your prospects" @@ -3274,6 +3373,16 @@ msgstr "" msgid "These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma" msgstr "" +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_property_account_payable_id +msgid "This account will be used instead of the default one as the payable account for the current partner" +msgstr "" + +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_property_account_receivable_id +msgid "This account will be used instead of the default one as the receivable account for the current partner" +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "This email address has been preconfigured as the default\n" @@ -3314,6 +3423,16 @@ msgstr "" msgid "This is the source of the link Ex: Search Engine, another domain, or name of email list" msgstr "" +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_property_supplier_payment_term_id +msgid "This payment term will be used instead of the default one for purchase orders and vendor bills" +msgstr "" + +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_property_payment_term_id +msgid "This payment term will be used instead of the default one for sale orders and customer invoices" +msgstr "" + #. module: crm #: model:ir.model.fields,help:crm.field_crm_stage_probability msgid "This percentage depicts the default/average probability of the Case for this stage to be a success" @@ -3353,11 +3472,36 @@ msgstr "" msgid "Title" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_total_invoiced +msgid "Total Invoiced" +msgstr "" + +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_debit +msgid "Total Payable" +msgstr "" + +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_credit +msgid "Total Receivable" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_opportunity_report_total_revenue msgid "Total Revenue" msgstr "" +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_credit +msgid "Total amount this customer owes you." +msgstr "" + +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_debit +msgid "Total amount you have to pay to this vendor." +msgstr "" + #. module: crm #: model:ir.ui.view,arch_db:crm.crm_case_form_view_leads msgid "Tracking" @@ -3499,6 +3643,11 @@ msgstr "" msgid "Users" msgstr "" +#. module: crm +#: model:ir.model.fields,help:crm.field_res_users_currency_id +msgid "Utility field to express amount currency" +msgstr "" + #. module: crm #: model:ir.model.fields,field_description:crm.field_base_partner_merge_automatic_wizard_group_by_vat msgid "VAT" @@ -3509,6 +3658,11 @@ msgstr "" msgid "VIP letter to potential sponsors" msgstr "" +#. module: crm +#: model:ir.model.fields,field_description:crm.field_res_users_property_supplier_payment_term_id +msgid "Vendor Payment Term" +msgstr "" + #. module: crm #: selection:crm.lead,priority:0 #: selection:crm.opportunity.report,priority:0 @@ -3557,16 +3711,6 @@ msgstr "" msgid "We hope this process helped you improve your sales strategy." msgstr "" -#. module: crm -#: model:ir.model.fields,field_description:crm.field_crm_lead_website_message_ids -msgid "Website Messages" -msgstr "" - -#. module: crm -#: model:ir.model.fields,help:crm.field_crm_lead_website_message_ids -msgid "Website communication history" -msgstr "" - #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner msgid "What kind of proposals do you usually send to your customers ?" @@ -3574,7 +3718,7 @@ msgstr "" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner -msgid "What are the main KPIs you need to track the sales actities?" +msgid "What are the main KPIs you need to track for your the sales actities?" msgstr "" #. module: crm @@ -3656,8 +3800,8 @@ msgstr "" #. module: crm #: model:ir.ui.view,arch_db:crm.crm_planner -msgid "You may have different sale price for different\n" -" group of customers:" +msgid "You may have a different sale price for different\n" +" groups of customers:" msgstr "" #. module: crm diff --git a/addons/crm/models/crm_activity.py b/addons/crm/models/crm_activity.py index c496f7f80bf..b2f211d6fdb 100644 --- a/addons/crm/models/crm_activity.py +++ b/addons/crm/models/crm_activity.py @@ -25,7 +25,7 @@ class CrmActivity(models.Model): _order = "sequence" days = fields.Integer('Number of days', default=0, - help='Number of days before doing fulfilling the action, allowing to plan the action date.') + help='Number of days before executing the action, allowing you to plan the date of the action.') sequence = fields.Integer('Sequence', default=0) team_id = fields.Many2one('crm.team', string='Sales Team') subtype_id = fields.Many2one('mail.message.subtype', string='Message Subtype', required=True, ondelete='cascade') diff --git a/addons/crm/report/crm_opportunity_report_view.xml b/addons/crm/report/crm_opportunity_report_view.xml index 4e2362479c7..97f91dfe2dd 100644 --- a/addons/crm/report/crm_opportunity_report_view.xml +++ b/addons/crm/report/crm_opportunity_report_view.xml @@ -161,7 +161,7 @@ (0, 0, {'view_mode': 'graph', 'view_id': ref('crm_opportunity_report_view_graph')})]"/> Pipeline Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, -µmissed deadlines or the number of interactions per opportunity. This report is +missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline. @@ -180,9 +180,9 @@ teams of the sales pipeline. (0, 0, {'view_mode': 'pivot', 'view_id': ref('crm_opportunity_report_view_pivot')})]"/> Pipeline Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, -µmissed deadlines or the number of interactions per opportunity. This report is -mainly used by the sales manager in order to do the periodic review with the -teams of the sales pipeline. +missed deadlines or the number of interactions per opportunity. This report is +mainly used by the sales manager in order to periodically review the pipeline +with the the sales teams. diff --git a/addons/crm/web_planner_data.xml b/addons/crm/web_planner_data.xml index 15c887cd729..13a855fbf06 100644 --- a/addons/crm/web_planner_data.xml +++ b/addons/crm/web_planner_data.xml @@ -84,7 +84,7 @@

- What are the main KPIs you need to track the sales actities? + What are the main KPIs you need to track for your the sales actities?

@@ -403,7 +403,7 @@ Using templates can boost the quality of your quotations and their success rate. However, creating such templates can be a huge effort. - We recommand to start with standard quotations + We recommend to start with standard quotations and upgrade later.
@@ -425,14 +425,14 @@

- If you have less than 200 contacts, we recommand you + If you have less than 200 contacts, we recommend you to create them manually.

@@ -491,7 +491,7 @@
@@ -525,7 +525,7 @@
@@ -560,8 +560,8 @@

- You may have different sale price for different - group of customers: + You may have a different sale price for different + groups of customers:

  • Consumers
  • @@ -726,7 +726,7 @@ @@ -826,7 +826,7 @@

-

Here are a few examples of document you should provide to your sales team based on the sales stage:

+

Here are a few examples of documents you should provide to your sales team based on the sales stage:

New:

@@ -862,7 +862,7 @@

- Odoo is the world's only software to have a full integration of Marketing Apps your sales channel: insight sales, point of sale, ecommerce. + Odoo is the world's only software to have a full integration of Marketing Apps for your sales channel: insight sales, point of sale, ecommerce.

To boost your leads acquisition, you should have a look at our marketing apps: diff --git a/addons/crm_partner_assign/i18n/crm_partner_assign.pot b/addons/crm_partner_assign/i18n/crm_partner_assign.pot index 340bdd9ac7f..50aa1795aa5 100644 --- a/addons/crm_partner_assign/i18n/crm_partner_assign.pot +++ b/addons/crm_partner_assign/i18n/crm_partner_assign.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 9.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-09-07 14:40+0000\n" -"PO-Revision-Date: 2015-09-07 14:40+0000\n" +"POT-Creation-Date: 2015-09-10 10:20+0000\n" +"PO-Revision-Date: 2015-09-10 10:20+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -68,9 +68,15 @@ msgid "

I am interested by this lead.

" msgstr "" #. module: crm_partner_assign -#: code:addons/crm_partner_assign/wizard/crm_channel_interested.py:34 +#: code:addons/crm_partner_assign/wizard/crm_channel_interested.py:35 #, python-format -msgid "

I am not interested by this lead. I %scontacted the lead.

" +msgid "

I am not interested by this lead. I contacted the lead.

" +msgstr "" + +#. module: crm_partner_assign +#: code:addons/crm_partner_assign/wizard/crm_channel_interested.py:37 +#, python-format +msgid "

I am not interested by this lead. I have not contacted the lead.

" msgstr "" #. module: crm_partner_assign @@ -519,7 +525,7 @@ msgid "Leads Analysis" msgstr "" #. module: crm_partner_assign -#: model:ir.model.fields,field_description:crm_partner_assign.field_res_partner_grade_id_9493 +#: model:ir.model.fields,field_description:crm_partner_assign.field_res_partner_grade_id_4327 #: model:ir.ui.view,arch_db:crm_partner_assign.view_partner_grade_form msgid "Level" msgstr "" diff --git a/addons/crm_partner_assign/test/partner_assign.yml b/addons/crm_partner_assign/test/partner_assign.yml index cc3a9aa64ac..35f0adb9b02 100644 --- a/addons/crm_partner_assign/test/partner_assign.yml +++ b/addons/crm_partner_assign/test/partner_assign.yml @@ -22,7 +22,6 @@ - !python {model: crm.lead}: | lead = self.browse(cr, uid, ref('crm.crm_case_21')) - # import pdb; pdb.set_trace() assert lead.partner_assigned_id.id == ref('base.res_partner_18') , "Opportuniy is not assigned nearest partner" assert 50 < lead.partner_latitude < 55, "Latitude is wrong: 50 < %s < 55" % lead.partner_latitude assert -4 < lead.partner_longitude < -1, "Longitude is wrong: -4 < %s < -1" % lead.partner_longitude diff --git a/addons/crm_partner_assign/wizard/crm_channel_interested.py b/addons/crm_partner_assign/wizard/crm_channel_interested.py index 32bbe1f547a..76dc52b30f3 100644 --- a/addons/crm_partner_assign/wizard/crm_channel_interested.py +++ b/addons/crm_partner_assign/wizard/crm_channel_interested.py @@ -31,7 +31,10 @@ class crm_lead_forward_to_partner(osv.TransientModel): values = {} else: stage = 'stage_portal_lead_recycle' - message = _('

I am not interested by this lead. I %scontacted the lead.

') % (not wizard.contacted and 'have not ' or '') + if wizard.contacted: + message = _('

I am not interested by this lead. I contacted the lead.

') + else: + message = _('

I am not interested by this lead. I have not contacted the lead.

') values = {'partner_assigned_id': False} user = self.pool.get('res.users').browse(cr, uid, uid, context=context) partner_ids = self.pool.get('res.partner').search(cr, SUPERUSER_ID, [('id', 'child_of', user.partner_id.commercial_partner_id.id)], context=context) diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py index b6b9f291d71..344828b27a2 100644 --- a/addons/delivery/models/stock_picking.py +++ b/addons/delivery/models/stock_picking.py @@ -6,6 +6,22 @@ from openerp.exceptions import UserError import openerp.addons.decimal_precision as dp +class StockQuantPackage(models.Model): + _inherit = "stock.quant.package" + + @api.one + @api.depends('quant_ids', 'children_ids') + def _compute_weight(self): + weight = 0 + for quant in self.quant_ids: + weight += quant.qty * quant.product_id.weight + for pack in self.children_ids: + pack._compute_weight() + weight += pack.weight + self.weight = weight + + weight = fields.Float(compute='_compute_weight') + class StockPicking(models.Model): _inherit = 'stock.picking' @@ -14,6 +30,28 @@ class StockPicking(models.Model): uom_categ_id = self.env.ref('product.product_uom_categ_kgm').id return self.env['product.uom'].search([('category_id', '=', uom_categ_id), ('factor', '=', 1)], limit=1) + @api.one + @api.depends('pack_operation_ids') + def _compute_packages(self): + self.ensure_one() + packs = set() + for packop in self.pack_operation_ids: + if packop.result_package_id: + packs.add(packop.result_package_id.id) + elif packop.package_id and not packop.product_id: + packs.add(packop.package_id.id) + self.package_ids = list(packs) + + @api.one + @api.depends('pack_operation_ids') + def _compute_bulk_weight(self): + weight = 0.0 + uom_obj = self.env['product.uom'] + for packop in self.pack_operation_ids: + if packop.product_id and not packop.result_package_id: + weight += uom_obj._compute_qty_obj(packop.product_uom_id , packop.product_qty, packop.product_id.uom_id) * packop.product_id.weight + self.weight_bulk = weight + carrier_price = fields.Float(string="Shipping Cost", readonly=True) delivery_type = fields.Selection(related='carrier_id.delivery_type', readonly=True) carrier_id = fields.Many2one("delivery.carrier", string="Carrier") @@ -22,6 +60,8 @@ class StockPicking(models.Model): carrier_tracking_ref = fields.Char(string='Carrier Tracking Ref', copy=False) number_of_packages = fields.Integer(string='Number of Packages', copy=False) weight_uom_id = fields.Many2one('product.uom', string='Unit of Measure', required=True, readonly="1", help="Unit of measurement for Weight", default=_default_uom) + package_ids = fields.Many2many('stock.quant.package', compute='_compute_packages', string='Packages') + weight_bulk = fields.Float('Bulk Weight', compute='_compute_bulk_weight') @api.depends('product_id', 'move_lines') def _cal_weight(self): diff --git a/addons/delivery/views/delivery_view.xml b/addons/delivery/views/delivery_view.xml index 6d7525be2b8..2b6fbae5902 100644 --- a/addons/delivery/views/delivery_view.xml +++ b/addons/delivery/views/delivery_view.xml @@ -195,6 +195,17 @@ + + stock.quant.package.weight.form + stock.quant.package + + + + + + + + stock.move.form.weight stock.move diff --git a/addons/event/data/event_data_tip.xml b/addons/event/data/event_data_tip.xml index 02b32f128f1..1bb7eb4afd3 100644 --- a/addons/event/data/event_data_tip.xml +++ b/addons/event/data/event_data_tip.xml @@ -2,7 +2,7 @@ - By clicking here, you can create and manage registration(s) for this event, send emails to attendee(s) and print identification badges. + Create and manage registrations for this event, send emails to attendees and print identification badges. event.event form diff --git a/addons/event/models/event.py b/addons/event/models/event.py index a83f4fe8f36..f73257b8a01 100644 --- a/addons/event/models/event.py +++ b/addons/event/models/event.py @@ -29,7 +29,7 @@ class event_event(models.Model): _order = 'date_begin' name = fields.Char( - string='Name', translate=True, required=True, + string='Event Name', translate=True, required=True, readonly=False, states={'done': [('readonly', True)]}) active = fields.Boolean(default=True, track_visibility="onchange") user_id = fields.Many2one( @@ -60,20 +60,20 @@ class event_event(models.Model): # Seats and computation seats_max = fields.Integer( - string='Maximum Available Seats', oldname='register_max', + string='Maximum Attendees Number', oldname='register_max', readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, help="For each event you can define a maximum registration of seats(number of attendees), above this numbers the registrations are not accepted.") seats_availability = fields.Selection( [('limited', 'Limited'), ('unlimited', 'Unlimited')], - 'Available Seat', required=True, default='unlimited') + 'Maximum Attendees', required=True, default='unlimited') seats_min = fields.Integer( - string='Minimum Reservation of Seats Required', oldname='register_min', - help="For each event you can define a minimum reserved seats(number of attendees), if it does not reach the mentioned registrations the event can not be confirmed (keep 0 to ignore this rule)") + string='Minimum Attendees', oldname='register_min', + help="For each event you can define a minimum reserved seats (number of attendees), if it does not reach the mentioned registrations the event can not be confirmed (keep 0 to ignore this rule)") seats_reserved = fields.Integer( oldname='register_current', string='Reserved Seats', store=True, readonly=True, compute='_compute_seats') seats_available = fields.Integer( - oldname='register_avail', string='Available Seats', + oldname='register_avail', string='Maximum Attendees', store=True, readonly=True, compute='_compute_seats') seats_unconfirmed = fields.Integer( oldname='register_prospect', string='Unconfirmed Seat Reservations', @@ -158,7 +158,7 @@ class event_event(models.Model): ('confirm', 'Confirmed'), ('done', 'Done')], string='Status', default='draft', readonly=True, required=True, copy=False, help="If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'.") - auto_confirm = fields.Boolean(string='Auto Confirmation Activated', compute='_compute_auto_confirm') + auto_confirm = fields.Boolean(string='Confirmation not required', compute='_compute_auto_confirm') @api.one def _compute_auto_confirm(self): diff --git a/addons/event/views/event_views.xml b/addons/event/views/event_views.xml index a9659970ed6..750716ef858 100644 --- a/addons/event/views/event_views.xml +++ b/addons/event/views/event_views.xml @@ -101,10 +101,18 @@ - - - + + + @@ -198,11 +206,11 @@

- Attendees Expected + Attendees expected
- Attendees Confirmed - (Report) + Attendees confirmed + (stats)

diff --git a/addons/hr/__openerp__.py b/addons/hr/__openerp__.py index 6fecf886d24..9ae2782d2fd 100644 --- a/addons/hr/__openerp__.py +++ b/addons/hr/__openerp__.py @@ -32,6 +32,7 @@ You can manage: 'mail', 'resource', 'web_kanban', + 'web_tip', ], 'data': [ 'security/hr_security.xml', diff --git a/addons/hr_applicant_document/views/hr_applicant.xml b/addons/hr_applicant_document/views/hr_applicant.xml deleted file mode 100644 index 49ebec5946b..00000000000 --- a/addons/hr_applicant_document/views/hr_applicant.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - hr.applicant.document.search.inherit - hr.applicant - - - - ['|','|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self),('attachment_ids.index_content', 'ilike', self)] - - - - - - Resumes and Letters - ir.attachment - form - kanban,tree,form - - [('res_model','=','hr.applicant')] - - -

- Search through resumes and motivation letters. -

-
-
- - - -
-
diff --git a/addons/hr_equipment/__openerp__.py b/addons/hr_equipment/__openerp__.py index 43eb8e63509..bb61a7798c7 100644 --- a/addons/hr_equipment/__openerp__.py +++ b/addons/hr_equipment/__openerp__.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- { - 'name': 'Track Employees Equipment', + 'name': 'IT Assets', 'version': '1.0', 'sequence': 125, 'description': """ - Track employees' equipment and manage its allocation """, + Track employees' IT assets: computers, printers, software licenses and manage makntenance requests.""", 'author': 'Odoo S.A.', 'depends': ['hr'], - 'summary': 'Internal Equipments, Allocation Tracking', + 'summary': 'Equipments, IT Assets, Internal Hardware', 'data': [ 'security/hr_equipment.xml', 'security/ir.model.access.csv', diff --git a/addons/hr_equipment/data/hr_equipment_data.xml b/addons/hr_equipment/data/hr_equipment_data.xml index a14e345409a..4048e864a90 100644 --- a/addons/hr_equipment/data/hr_equipment_data.xml +++ b/addons/hr_equipment/data/hr_equipment_data.xml @@ -17,11 +17,13 @@ Repaired + Scrap + @@ -68,5 +70,15 @@ category_id + + Computers + + + Software + + + Printers + + diff --git a/addons/hr_equipment/data/hr_equipment_demo.xml b/addons/hr_equipment/data/hr_equipment_demo.xml index f2c277933f0..ec77c10f478 100644 --- a/addons/hr_equipment/data/hr_equipment_demo.xml +++ b/addons/hr_equipment/data/hr_equipment_demo.xml @@ -3,23 +3,11 @@ - - Computers - - Monitors 3 - - Softwares - - - - Printers - - Phones diff --git a/addons/hr_equipment/models/hr_equipment.py b/addons/hr_equipment/models/hr_equipment.py index 4fe146b3d38..8f5b0a2d522 100644 --- a/addons/hr_equipment/models/hr_equipment.py +++ b/addons/hr_equipment/models/hr_equipment.py @@ -9,19 +9,20 @@ class HrEquipmentStage(models.Model): """ Model for case stages. This models the main stages of a Maintenance Request management flow. """ _name = 'hr.equipment.stage' - _description = 'Equipment Stage' + _description = 'Maintenance Stage' _order = 'sequence, id' name = fields.Char('Name', required=True, translate=True) sequence = fields.Integer('Sequence', default=20) fold = fields.Boolean('Folded in Recruitment Pipe') + done = fields.Boolean('Request Done') class HrEquipmentCategory(models.Model): _name = 'hr.equipment.category' _inherits = {"mail.alias": "alias_id"} _inherit = ['mail.thread'] - _description = 'Equipment Category' + _description = 'Asset Category' @api.one @api.depends('equipment_ids') @@ -34,7 +35,7 @@ class HrEquipmentCategory(models.Model): note = fields.Text('Comments', translate=True) equipment_ids = fields.One2many('hr.equipment', 'category_id', string='Equipments', copy=False) equipment_count = fields.Integer(string="Equipment", compute='_compute_equipment_count') - maintenance_ids = fields.One2many('hr.equipment.request', 'category_id', copy=False, domain=[('stage_id.fold', '=', False)]) + maintenance_ids = fields.One2many('hr.equipment.request', 'category_id', copy=False) maintenance_count = fields.Integer(string="Maintenance", compute='_compute_maintenance_count') alias_id = fields.Many2one( 'mail.alias', 'Alias', ondelete='cascade', required=True, @@ -75,7 +76,7 @@ class HrEquipmentCategory(models.Model): class HrEquipment(models.Model): _name = 'hr.equipment' _inherit = ['mail.thread'] - _description = 'Equipment' + _description = 'IT Assets' @api.multi def _track_subtype(self, init_values): @@ -104,32 +105,37 @@ class HrEquipment(models.Model): recs = self.search([('name', operator, name)] + args, limit=limit) return recs.name_get() - name = fields.Char('Name', required=True, translate=True) + name = fields.Char('Asset Name', required=True, translate=True) user_id = fields.Many2one('res.users', string='Technician', track_visibility='onchange') employee_id = fields.Many2one('hr.employee', string='Assigned to Employee', track_visibility='onchange') department_id = fields.Many2one('hr.department', string='Assigned to Department', track_visibility='onchange') - category_id = fields.Many2one('hr.equipment.category', string='Equipment Category', track_visibility='onchange') + category_id = fields.Many2one('hr.equipment.category', string='Asset Category', track_visibility='onchange') partner_id = fields.Many2one('res.partner', string='Vendor', domain="[('supplier', '=', 1)]") + partner_ref = fields.Char('Vendor Reference') + location = fields.Char('Location') model = fields.Char('Model') serial_no = fields.Char('Serial Number', copy=False) assign_date = fields.Date('Assigned Date', track_visibility='onchange') cost = fields.Float('Cost') note = fields.Text('Note') + warranty = fields.Date('Warranty') color = fields.Integer('Color Index') scrap_date = fields.Date('Scrap Date') equipment_assign_to = fields.Selection( - [('department', 'By Department'), ('employee', 'By Employee')], - string='Allocate To', - help='By Employee: equipment assigned to individual Employee, By Department: equipment assigned to group of employees in department', + [('department', 'Department'), ('employee', 'Employee')], + string='Used By', required=True, default='employee') - maintenance_ids = fields.One2many('hr.equipment.request', 'equipment_id', domain=[('stage_id.fold', '=', False)]) - maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Maintenance") + maintenance_ids = fields.One2many('hr.equipment.request', 'equipment_id') + maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Maintenance", store=True) + maintenance_open_count = fields.Integer(compute='_compute_maintenance_count', string="Current Maintenance", store=True) @api.one - @api.depends('maintenance_ids') + @api.depends('maintenance_ids.stage_id.done') def _compute_maintenance_count(self): self.maintenance_count = len(self.maintenance_ids) + self.maintenance_open_count = len(self.maintenance_ids.filtered(lambda x: not x.stage_id.done)) + @api.onchange('equipment_assign_to') def _onchange_equipment_assign_to(self): @@ -144,7 +150,7 @@ class HrEquipment(models.Model): self.user_id = self.category_id.user_id _sql_constraints = [ - ('serial_no', 'unique(serial_no)', "The serial number of this equipment must be unique !"), + ('serial_no', 'unique(serial_no)', "Another asset already exists with this serial number!"), ] @api.model @@ -205,7 +211,7 @@ class HrEquipment(models.Model): class HrEquipmentRequest(models.Model): _name = 'hr.equipment.request' _inherit = ['mail.thread'] - _description = 'Equipment Request' + _description = 'Maintenance Requests' @api.returns('self') def _default_employee_get(self): @@ -230,7 +236,7 @@ class HrEquipmentRequest(models.Model): employee_id = fields.Many2one('hr.employee', string='Employee', default=_default_employee_get) department_id = fields.Many2one('hr.department', string='Department') category_id = fields.Many2one('hr.equipment.category', string='Category') - equipment_id = fields.Many2one('hr.equipment', string='Equipment', select=True) + equipment_id = fields.Many2one('hr.equipment', string='Asset', select=True) user_id = fields.Many2one('res.users', string='Assigned to', track_visibility='onchange') stage_id = fields.Many2one('hr.equipment.stage', string='Stage', track_visibility='onchange', default=_default_stage) priority = fields.Selection([('0', 'Very Low'), ('1', 'Low'), ('2', 'Normal'), ('3', 'High')], string='Priority') diff --git a/addons/hr_equipment/security/hr_equipment.xml b/addons/hr_equipment/security/hr_equipment.xml index dc0d86a2c82..b52aebd5346 100644 --- a/addons/hr_equipment/security/hr_equipment.xml +++ b/addons/hr_equipment/security/hr_equipment.xml @@ -18,14 +18,14 @@ - Employee is allowed to see its own maintenance requests + Employees are allowed to access their own maintenance requests ['|', ('user_id.id', '=', user.id), ('employee_id.user_id.id', '=', user.id)] - Employee is allowed to see its own equipments + Employees are allowed to access their own equipments [('employee_id.user_id.id', '=', user.id)] diff --git a/addons/hr_equipment/tests/test_hr_equipment.py b/addons/hr_equipment/tests/test_hr_equipment.py index f1c9e923692..6660260ac90 100644 --- a/addons/hr_equipment/tests/test_hr_equipment.py +++ b/addons/hr_equipment/tests/test_hr_equipment.py @@ -24,6 +24,7 @@ class TestHrEquipment(TransactionCase): email="empuser@yourcompany.example.com", groups_id=[(6, 0, [res_hr_user.id])] )) + self.env.ref('hr.employee_qdp').write({'user_id': self.hr_user.id}) self.hr_manager = self.user.create(dict( name="HR Manager", @@ -40,7 +41,7 @@ class TestHrEquipment(TransactionCase): equipment_01 = self.equipment.sudo(self.hr_manager).create({ 'name': 'Samsung Monitor "15', 'category_id': self.ref('hr_equipment.hr_equipment_monitor'), - 'employee_id': self.ref('hr.employee_al'), + 'employee_id': self.ref('hr.employee_qdp'), 'user_id': self.ref('base.user_root'), 'assign_date': time.strftime('%Y-%m-%d'), 'serial_no': 'MT/127/18291015', diff --git a/addons/hr_equipment/views/hr_equipment_views.xml b/addons/hr_equipment/views/hr_equipment_views.xml index 7db2f163b89..dae1d8d9485 100644 --- a/addons/hr_equipment/views/hr_equipment_views.xml +++ b/addons/hr_equipment/views/hr_equipment_views.xml @@ -199,6 +199,10 @@ hr.equipment
+
+ +
-
@@ -621,7 +621,7 @@ @@ -639,7 +639,7 @@

Billing

Create bills automatically based on Time & Material.

- Install now @@ -1017,7 +1017,7 @@ diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 8b53d399b90..52ce8c01524 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -16,7 +16,7 @@ class PurchaseOrder(models.Model): _description = "Purchase Order" _order = 'date_order desc, id desc' - @api.depends('order_line.product_qty', 'order_line.price_unit', 'order_line.taxes_id') + @api.depends('order_line.price_total') def _amount_all(self): amount_untaxed = amount_tax = 0.0 for line in self.order_line: @@ -117,7 +117,7 @@ class PurchaseOrder(models.Model): ('purchase', 'Purchase Order'), ('done', 'Done'), ('cancel', 'Cancelled') - ], string='Status', readonly=True, select=True, copy=False, default='draft') + ], string='Status', readonly=True, select=True, copy=False, default='draft', track_visibility='onchange') order_line = fields.One2many('purchase.order.line', 'order_id', string='Order Lines', states=READONLY_STATES, copy=True) notes = fields.Text('Terms and Conditions') diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml index 36b298e1bcd..6a7da530de9 100644 --- a/addons/purchase/purchase_view.xml +++ b/addons/purchase/purchase_view.xml @@ -296,7 +296,7 @@ - + purchase.order.kanban purchase.order @@ -306,6 +306,7 @@ +
@@ -313,8 +314,8 @@
-
- +
+
diff --git a/addons/sale/report/sale_report_view.xml b/addons/sale/report/sale_report_view.xml index c91414f76bf..ec87e15eb8b 100644 --- a/addons/sale/report/sale_report_view.xml +++ b/addons/sale/report/sale_report_view.xml @@ -59,7 +59,7 @@ - + diff --git a/addons/sale/res_config.py b/addons/sale/res_config.py index b56cd418ca4..bd2a0206498 100644 --- a/addons/sale/res_config.py +++ b/addons/sale/res_config.py @@ -64,7 +64,15 @@ class sale_configuration(osv.TransientModel): ('order', 'Invoice ordered quantities'), ('delivery', 'Invoice delivered quantities'), ('cost', 'Invoice based on costs (time and material, expenses)') - ], 'Default Invoicing', default_model='product.template') + ], 'Default Invoicing', default_model='product.template'), + 'deposit_property_account_income_id': fields.property( + type="many2one", + relation="account.account", + string="Income Account", + domain=[('deprecated', '=', False)], + help="This account will be used for invoices instead of the default one to value sales for the deposit."), + 'deposit_taxes_ids': fields.many2many('account.tax', 'product_taxes_rel', 'prod_id', 'tax_id', string='Customer Taxes', + domain=[('type_tax_use', '=', 'sale')]), } _defaults = { @@ -84,6 +92,23 @@ class sale_configuration(osv.TransientModel): return {'value': {'group_pricelist_item': True, 'group_sale_pricelist': True, 'group_product_pricelist': False}} return {'value': {'group_pricelist_item': False, 'group_sale_pricelist': False, 'group_product_pricelist': False}} + def get_default_deposit_values(self, cr, uid, fields, context=None): + deposit_product_template = self.pool['ir.model.data'].xmlid_to_object(cr, uid, 'sale.advance_product_1', context=context) + return { + 'deposit_property_account_income_id': deposit_product_template.product_variant_ids.property_account_income_id.id, + 'deposit_taxes_ids': deposit_product_template.product_variant_ids.taxes_id.ids + } + + def set_deposit_values(self, cr, uid, ids, context=None): + if context is None: + context = {} + config_value = self.browse(cr, uid, ids, context=context) + deposit_product_template = self.pool['ir.model.data'].xmlid_to_object(cr, uid, 'sale.advance_product_1', context=context) + deposit_product_template.product_variant_ids.write({ + 'property_account_income_id': config_value.deposit_property_account_income_id.id, + 'taxes_id': [(6, 0, config_value.deposit_taxes_ids.ids)], + }) + class account_config_settings(osv.osv_memory): _inherit = 'account.config.settings' _columns = { diff --git a/addons/sale/res_config_view.xml b/addons/sale/res_config_view.xml index 1b911178797..a08c7a25584 100644 --- a/addons/sale/res_config_view.xml +++ b/addons/sale/res_config_view.xml @@ -29,6 +29,12 @@
+ + + + + +
diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 515cdb393b9..9efaadaa910 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -20,7 +20,7 @@ class SaleOrder(models.Model): _description = "Sales Order" _order = 'date_order desc, id desc' - @api.depends('order_line.product_uom_qty', 'order_line.discount', 'order_line.price_unit', 'order_line.tax_id') + @api.depends('order_line.price_total') def _amount_all(self): amount_untaxed = amount_tax = 0.0 for line in self.order_line: @@ -78,7 +78,7 @@ class SaleOrder(models.Model): ('sale', 'Sale Order'), ('done', 'Done'), ('cancel', 'Cancelled'), - ], string='Status', readonly=True, copy=False, index=True, default='draft') + ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='draft') date_order = fields.Datetime(string='Order Date', required=True, readonly=True, index=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, copy=False, default=fields.Date.context_today) validity_date = fields.Date(string='Expiration Date', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}) create_date = fields.Datetime(string='Creation Date', readonly=True, index=True, help="Date on which sales order is created.") @@ -182,7 +182,6 @@ class SaleOrder(models.Model): vals['partner_shipping_id'] = vals.setdefault('partner_shipping_id', addr['delivery']) vals['pricelist_id'] = vals.setdefault('pricelist_id', partner.property_product_pricelist and partner.property_product_pricelist.id) result = super(SaleOrder, self).create(vals) - self.message_post(body=_("Quotation created")) return result @api.multi diff --git a/addons/sale/sale_data.xml b/addons/sale/sale_data.xml index 6464507a083..44a2f3a5afb 100644 --- a/addons/sale/sale_data.xml +++ b/addons/sale/sale_data.xml @@ -74,5 +74,20 @@ team_id
+ + + Deposit + + service + 150.0 + order + 100.0 + + + + + + + diff --git a/addons/sale/sale_demo.xml b/addons/sale/sale_demo.xml index 2fabc306fcb..aa52d24a1a4 100644 --- a/addons/sale/sale_demo.xml +++ b/addons/sale/sale_demo.xml @@ -191,6 +191,7 @@ + sale @@ -209,6 +210,7 @@ + sale @@ -255,6 +257,7 @@ + sale @@ -310,21 +313,6 @@ Thanks! comment - - - - - Deposit - - service - 150.0 - order - 100.0 - - - - - diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index 018f3bb6e54..8cd85068b3d 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -61,6 +61,7 @@ +
@@ -68,8 +69,8 @@
-
- +
+
@@ -184,7 +185,6 @@ @@ -193,7 +193,6 @@
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index 2ebc132a395..83b83c2dacf 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -893,7 +893,7 @@ Sitemap: sitemap.xml