diff options
| author | Vijaykumar Baladaniya <vba@tinyerp.com> | 2012-07-09 18:31:13 +0530 |
|---|---|---|
| committer | Vijaykumar Baladaniya <vba@tinyerp.com> | 2012-07-09 18:31:13 +0530 |
| commit | be2e95656aaa113addea2b510fcdcf2f890eaaa4 (patch) | |
| tree | abcb3dd4ef350a1b8ad0eaffdd2b9a1cb91521af /addons/account_analytic_analysis | |
| parent | b982ea278b33132def3927417b7a854b98b5028a (diff) | |
| parent | 3925f76ce85854e5d4834902a05f57bcfc5ace85 (diff) | |
[MERGE]merged with trunk-survey-layout-tta
bzr revid: vba@tinyerp.com-20120709130113-3lchipgil9oqpglg
Diffstat (limited to 'addons/account_analytic_analysis')
3 files changed, 224 insertions, 99 deletions
diff --git a/addons/account_analytic_analysis/account_analytic_analysis.py b/addons/account_analytic_analysis/account_analytic_analysis.py index 20c170cb5c0..6e15fe1d5a5 100644 --- a/addons/account_analytic_analysis/account_analytic_analysis.py +++ b/addons/account_analytic_analysis/account_analytic_analysis.py @@ -98,7 +98,7 @@ class account_analytic_account(osv.osv): WHERE account_analytic_account.id IN %s \ AND account_analytic_line.invoice_id IS NULL \ AND account_analytic_line.to_invoice IS NOT NULL \ - AND account_analytic_journal.type IN ('purchase','general') \ + AND account_analytic_journal.type = 'general' \ GROUP BY account_analytic_account.id;""", (parent_ids,)) for account_id, sum in cr.fetchall(): if account_id not in res: @@ -257,6 +257,12 @@ class account_analytic_account(osv.osv): res[id] = round(res.get(id, 0.0),2) return res + def _remaining_hours_to_invoice_calc(self, cr, uid, ids, name, arg, context=None): + res = {} + for account in self.browse(cr, uid, ids, context=context): + res[account.id] = max(account.hours_qtt_est - account.timesheet_ca_invoiced, account.ca_to_invoice) + return res + def _hours_qtt_invoiced_calc(self, cr, uid, ids, name, arg, context=None): res = {} for account in self.browse(cr, uid, ids, context=context): @@ -291,15 +297,34 @@ class account_analytic_account(osv.osv): res[id] = round(res.get(id, 0.0),2) return res + def _fix_price_to_invoice_calc(self, cr, uid, ids, name, arg, context=None): + sale_obj = self.pool.get('sale.order') + res = {} + for account in self.browse(cr, uid, ids, context=context): + res[account.id] = 0.0 + sale_ids = sale_obj.search(cr, uid, [('project_id','=', account.id), ('partner_id', '=', account.partner_id.id)], context=context) + for sale in sale_obj.browse(cr, uid, sale_ids, context=context): + if not sale.invoiced: + res[account.id] += sale.amount_untaxed + for invoice in sale.invoice_ids: + if invoice.state not in ('draft', 'cancel'): + res[account.id] -= invoice.amount_untaxed + return res + + def _timesheet_ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None): + lines_obj = self.pool.get('account.analytic.line') + res = {} + for account in self.browse(cr, uid, ids, context=context): + res[account.id] = 0.0 + line_ids = lines_obj.search(cr, uid, [('account_id','=', account.id), ('invoice_id','!=',False), ('to_invoice','!=', False), ('journal_id.type', '=', 'general')], context=context) + for line in lines_obj.browse(cr, uid, line_ids, context=context): + res[account.id] += line.invoice_id.amount_untaxed + return res + def _remaining_ca_calc(self, cr, uid, ids, name, arg, context=None): res = {} for account in self.browse(cr, uid, ids, context=context): - if account.amount_max != 0: - res[account.id] = account.amount_max - account.ca_invoiced - else: - res[account.id]=0.0 - for id in ids: - res[id] = round(res.get(id, 0.0),2) + res[account.id] = max(account.amount_max - account.ca_invoiced, account.fix_price_to_invoice) return res def _real_margin_calc(self, cr, uid, ids, name, arg, context=None): @@ -333,6 +358,47 @@ class account_analytic_account(osv.osv): result.add(line.account_id.id) return list(result) + def _get_total_estimation(self, account): + tot_est = 0.0 + if account.fix_price_invoices: + tot_est += account.amount_max + if account.invoice_on_timesheets: + tot_est += account.hours_qtt_est + return tot_est + + def _get_total_invoiced(self, account): + total_invoiced = 0.0 + if account.fix_price_invoices: + total_invoiced += account.ca_invoiced + if account.invoice_on_timesheets: + total_invoiced += account.timesheet_ca_invoiced + return total_invoiced + + def _get_total_remaining(self, account): + total_remaining = 0.0 + if account.fix_price_invoices: + total_remaining += account.remaining_ca + if account.invoice_on_timesheets: + total_remaining += account.remaining_hours_to_invoice + return total_remaining + + def _get_total_toinvoice(self, account): + total_toinvoice = 0.0 + if account.fix_price_invoices: + total_toinvoice += account.fix_price_to_invoice + if account.invoice_on_timesheets: + total_toinvoice += account.ca_to_invoice + return total_toinvoice + + def _sum_of_fields(self, cr, uid, ids, name, arg, context=None): + res = dict([(i, {}) for i in ids]) + for account in self.browse(cr, uid, ids, context=context): + res[account.id]['est_total'] = self._get_total_estimation(account) + res[account.id]['invoiced_total'] = self._get_total_invoiced(account) + res[account.id]['remaining_total'] = self._get_total_remaining(account) + res[account.id]['toinvoice_total'] = self._get_total_toinvoice(account) + return res + _columns = { 'is_overdue_quantity' : fields.function(_is_overdue_quantity, method=True, type='boolean', string='Overdue Quantity', store={ @@ -350,7 +416,7 @@ class account_analytic_account(osv.osv): 'ca_theorical': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Theoretical Revenue', help="Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist.", digits_compute=dp.get_precision('Account')), - 'hours_quantity': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Total Time', + 'hours_quantity': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Total Worked Time', help="Number of time you spent on the analytic account (from timesheet). It computes quantities on all journal of type 'general'."), 'last_invoice_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Last Invoice Date', help="If invoice from the costs, this is the date of the latest invoiced."), @@ -363,7 +429,13 @@ class account_analytic_account(osv.osv): 'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, type='float', string='Invoiced Time', help="Number of time (hours/days) that can be invoiced plus those that already have been invoiced."), 'remaining_hours': fields.function(_remaining_hours_calc, type='float', string='Remaining Time', - help="Computed using the formula: Maximum Time - Total Time"), + help="Computed using the formula: Maximum Time - Total Worked Time"), + 'remaining_hours_to_invoice': fields.function(_remaining_hours_to_invoice_calc, type='float', string='Remaining Time', + help="Computed using the formula: Maximum Time - Total Invoiced Time"), + 'fix_price_to_invoice': fields.function(_fix_price_to_invoice_calc, type='float', string='Remaining Time', + help="Sum of quotations for this contract."), + 'timesheet_ca_invoiced': fields.function(_timesheet_ca_invoiced_calc, type='float', string='Remaining Time', + help="Sum of timesheet lines invoiced for this contract."), 'remaining_ca': fields.function(_remaining_ca_calc, type='float', string='Remaining Revenue', help="Computed using the formula: Max Invoice Price - Invoiced Amount.", digits_compute=dp.get_precision('Account')), @@ -379,10 +451,51 @@ class account_analytic_account(osv.osv): 'real_margin_rate': fields.function(_real_margin_rate_calc, type='float', string='Real Margin Rate (%)', help="Computes using the formula: (Real Margin / Total Costs) * 100.", digits_compute=dp.get_precision('Account')), + 'fix_price_invoices' : fields.boolean('Fix Price Invoices'), + 'invoice_on_timesheets' : fields.boolean("Invoice On Timesheets"), 'month_ids': fields.function(_analysis_all, multi='analytic_analysis', type='many2many', relation='account_analytic_analysis.summary.month', string='Month'), 'user_ids': fields.function(_analysis_all, multi='analytic_analysis', type="many2many", relation='account_analytic_analysis.summary.user', string='User'), + 'template_id': fields.many2one('account.analytic.account', 'Template of Contract'), + 'hours_qtt_est': fields.float('Estimation of Hours to Invoice'), + 'est_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total Estimation"), + 'invoiced_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total Invoiced"), + 'remaining_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total Remaining", help="Expectation of remaining income for this contract. Computed as the sum of remaining subtotals which, in turn, are computed as the maximum between '(Estimation - Invoiced)' and 'To Invoice' amounts"), + 'toinvoice_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total to Invoice", help=" Sum of everything that could be invoiced for this contract."), } + def open_sale_order_lines(self,cr,uid,ids,context=None): + if context is None: + context = {} + sale_ids = self.pool.get('sale.order').search(cr,uid,[('project_id','=',context.get('search_default_project_id',False)),('partner_id','=',context.get('search_default_partner_id',False))]) + names = [record.name for record in self.browse(cr, uid, ids, context=context)] + name = _('Sale Order Lines of %s') % ','.join(names) + return { + 'type': 'ir.actions.act_window', + 'name': name, + 'view_type': 'form', + 'view_mode': 'tree,form', + 'context': context, + 'domain' : [('order_id','in',sale_ids)], + 'res_model': 'sale.order.line', + 'nodestroy': True, + } + + def on_change_template(self, cr, uid, ids, template_id, context=None): + if not template_id: + return {} + res = {'value':{}} + template = self.browse(cr, uid, template_id, context=context) + res['value']['date_start'] = template.date_start + res['value']['date'] = template.date + res['value']['fix_price_invoices'] = template.fix_price_invoices + res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets + res['value']['quantity_max'] = template.quantity_max + res['value']['hours_qtt_est'] = template.hours_qtt_est + res['value']['amount_max'] = template.amount_max + res['value']['to_invoice'] = template.to_invoice.id + res['value']['pricelist_id'] = template.pricelist_id.id + res['value']['description'] = template.description + return res account_analytic_account() class account_analytic_account_summary_user(osv.osv): diff --git a/addons/account_analytic_analysis/account_analytic_analysis_menu.xml b/addons/account_analytic_analysis/account_analytic_analysis_menu.xml index cf939c2ccfa..8f86e9eeedc 100644 --- a/addons/account_analytic_analysis/account_analytic_analysis_menu.xml +++ b/addons/account_analytic_analysis/account_analytic_analysis_menu.xml @@ -58,8 +58,8 @@ <field name="res_model">account.analytic.account</field> <field name="view_type">form</field> <field name="view_mode">tree,form,graph</field> - <field name="context">{'search_default_has_partner':1, 'search_default_user_id':uid, 'search_default_draft':1, 'search_default_pending':1, 'search_default_open':1, 'search_default_renew':1}</field> - <field name="domain">[('type','=','normal')]</field> + <field name="context">{'search_default_user_id':uid, 'search_default_draft':1, 'search_default_pending':1, 'search_default_open':1, 'search_default_renew':1}</field> + <field name="domain">[('type','=','contract')]</field> <field name="search_view_id" ref="view_account_analytic_account_overdue_search"/> <field name="help">You will find here the contracts to be renewed because the deadline is passed or the working hours are higher than the allocated hours. OpenERP automatically sets these analytic accounts to the pending state, in order to raise a warning during the timesheets recording. Salesmen should review all pending accounts and reopen or close the according to the negotiation with the customer.</field> </record> @@ -70,14 +70,14 @@ <field name="res_model">account.analytic.account</field> <field name="view_type">form</field> <field name="view_mode">tree,form,graph</field> - <field name="context">{'search_default_has_partner':1, 'search_default_user_id':uid, 'search_default_draft':1, 'search_default_pending':1, 'search_default_open':1}</field> - <field name="domain">[('type','=','normal')]</field> + <field name="context">{'default_type':'contract'}</field> + <field name="domain">[('type','=','contract')]</field> <field name="search_view_id" ref="view_account_analytic_account_overdue_search"/> </record> <menuitem id="base.menu_sales" name="Sales" parent="base.menu_base_partner" sequence="1"/> - <menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="6" parent="base.menu_sales"/> + <menuitem action="action_account_analytic_overdue_all" id="menu_action_account_analytic_overdue_all" sequence="7" parent="base.menu_sales"/> </data> diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml index cd99299665b..ead87c176e3 100644 --- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml +++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml @@ -4,97 +4,99 @@ <!-- Analytic Account form - - Remove information on Account data => because they move on analysis sheet - create a page with invoicing informations --> - <record id="account_analytic_account_invoice_stat_form" model="ir.ui.view"> - <field name="name">account.analytic.account.invoice.stat.form.inherit</field> - <field name="model">account.analytic.account</field> - <field name="type">form</field> - <field name="inherit_id" ref="hr_timesheet_invoice.account_analytic_account_form_form"/> - <field eval="18" name="priority"/> - <field name="arch" type="xml"> - <group name="invoice_stats" position="inside"> - <field name="hours_qtt_non_invoiced" attrs="{'invisible': [('to_invoice','=',0)]}"/> - <field name="ca_to_invoice" attrs="{'invisible': [('to_invoice','=',0)]}"/> - <label string="" colspan="1"/> - <button - name="%(hr_timesheet_invoice.action_hr_timesheet_invoice_create_final)d" - string="Create Invoice" - type="action" - attrs="{'readonly':[('ca_to_invoice','=',0.0)], 'invisible': [('to_invoice','=',0)]}" - icon="gtk-go-forward"/> - </group> - </field> - </record> + + <act_window + id="action_sales_order" + name="Sales Orders" + res_model="sale.order" + src_model="account.analytic.account" + /> <record id="account_analytic_account_form_form" model="ir.ui.view"> <field name="name">account.analytic.account.invoice.form.inherit</field> <field name="model">account.analytic.account</field> <field name="type">form</field> - <field name="inherit_id" ref="account.view_account_analytic_account_form"/> - <field eval="18" name="priority"/> + <field name="inherit_id" ref="analytic.view_account_analytic_account_form"/> + <field eval="40" name="priority"/> <field name="arch" type="xml"> - <notebook position="inside"> - <page string="Invoice Analysis"> - <separator colspan="4" string="Work Done Stats"/> - - <field name="total_cost"/> - <field name="remaining_ca"/> - <field name="ca_invoiced"/> - <field name="ca_theorical"/> - <newline/> - <field name="hours_quantity"/> - <field name="hours_qtt_invoiced"/> - <field name="remaining_hours"/> - <newline/> - <separator colspan="4" string="Analysis Stats"/> - - <field name="revenue_per_hour"/> - <field name="real_margin"/> - <field name="real_margin_rate"/> - <field name="theorical_margin"/> - <separator colspan="4" string="Key Dates"/> - - <field name="last_invoice_date"/> - <field name="last_worked_invoiced_date"/> - <field name="last_worked_date"/> - </page> - <page string="Stats by month"> - <field colspan="4" name="month_ids" nolabel="1"> - <tree string="Month"> - <field name="month"/> - <field name="unit_amount" widget="float_time"/> - </tree> - </field> - </page> - <page string="Stats by user"> - <field colspan="4" name="user_ids" nolabel="1"> - <tree string="Users"> - <field name="user"/> - <field name="unit_amount" widget="float_time"/> - </tree> - </field> - </page> - </notebook> - - </field> - </record> - - <!-- Add information on Account analytic list for the project management --> - <record id="view_account_analytic_account_tree_c2c_2" model="ir.ui.view"> - <field name="name">account.analytic.account.tree</field> - <field name="model">account.analytic.account</field> - <field name="inherit_id" ref="account.view_account_analytic_account_list"/> - <field name="type">tree</field> - <field name="arch" type="xml"> - <field name="quantity" position="replace"> - <field name="hours_quantity"/> - <field name="hours_qtt_non_invoiced"/> - <field name="remaining_hours"/> - <field name="quantity_max"/> - </field> + <xpath expr='//field[@name="type"]' position='after'> + <field name="template_id" on_change="on_change_template(template_id,context)" domain="[('type','=','template')]" attrs="{'invisible': [('type','in',['view', 'normal','template'])]}" context="{'default_type' : 'template'}"/> + </xpath> + <xpath expr='//div[@name="duration"]' position="after" version="7.0"> + <label for="quantity_max"/> + <div> + <field name="quantity_max" class="oe_inline"/> / Remaining: <field name="remaining_hours" class="oe_inline"/> + </div> + </xpath> + <xpath expr='//group[@name="invoice_on_timesheets"]' position="replace"> + <group name='invoice_on_timesheets' string="Invoice on Timesheets Options" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}" col="4"> + <field name="pricelist_id" attrs="{'required': [('invoice_on_timesheets', '=', True)]}"/> + <field name="to_invoice" widget="selection" attrs="{'required': [('invoice_on_timesheets', '=', True)]}"/> + </group> + </xpath> + <xpath expr='//group[@name="master"]' position='after'> + <separator name="toinvoice" string="Invoicing"/> + <table width="100%%"> + <tr> + <th></th> + <th></th> + <th><label string="Est.Tot"/></th> + <th><label string="Invoiced"/></th> + <th><label string="Remaining"/></th> + <th><label string="To Invoice"/></th> + <th></th> + </tr><tr> + <td> + <label for="fix_price_invoices"/> + </td><td> + <field name="fix_price_invoices" class="oe_inline"/> + </td><td> + <field class="oe_inline" name="amount_max" attrs="{'invisible': [('fix_price_invoices','=',False)]}"/> + </td><td> + <field class="oe_inline" name="ca_invoiced" attrs="{'invisible': [('fix_price_invoices','=',False)]}"/> + </td><td> + <field class="oe_inline" name="remaining_ca" attrs="{'invisible': [('fix_price_invoices','=',False)]}"/> + </td><td> + <field class="oe_inline" name="fix_price_to_invoice" attrs="{'invisible': [('fix_price_invoices','=',False)]}"/> + </td><td> + <button name="%(action_sales_order)d" string="All Sales" type="action" context="{'default_partner_id': [partner_id], 'search_default_partner_id': [partner_id],'search_default_project_id': [active_id],'default_project_id': [active_id]}" attrs="{'invisible': [('fix_price_invoices','=',False)]}"/> + <button name="open_sale_order_lines" string="Lines To Invoice" type="object" context="{'default_partner_id': [partner_id],'default_project_id': active_id,'search_default_uninvoiced': 1,'search_default_project_id': active_id,'search_default_partner_id': [partner_id]}" attrs="{'invisible': [('fix_price_invoices','=',False)]}"/> + </td> + </tr><tr attrs="{'invisible':[('use_timesheets','=',False)]}"> + <td> + <label for="invoice_on_timesheets"/> + </td><td> + <field name="invoice_on_timesheets"/> + </td><td> + <field class="oe_inline" name="hours_qtt_est" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}"/> + </td><td> + <field class="oe_inline" name="timesheet_ca_invoiced" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}"/> + </td><td> + <field class="oe_inline" name="remaining_hours_to_invoice" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}"/> + </td><td> + <field class="oe_inline" name="ca_to_invoice" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}"/> + </td><td> + <button name="%(hr_timesheet.act_hr_timesheet_line_evry1_all_form)d" string="All Timesheets" type="action" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}" context="{'default_account_id': active_id,'search_default_account_id': active_id}"/> + <button name="%(hr_timesheet_invoice.act_acc_analytic_acc_2_report_acc_analytic_line_to_invoice)d" string="Timesheets to Invoice" type="action" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}"/> + </td> + </tr><tr name='total'> + <th> + <label string="Total"/> + </th><td> + </td><td> + <field name="est_total" class="oe_inline" attrs="{'invisible': [('invoice_on_timesheets','=',False)]}"/> + </td><td> + <field name="invoiced_total" class="oe_inline"/> + </td><td> + <field name="remaining_total" class="oe_inline"/> + </td><td> + <field name="toinvoice_total" class="oe_inline"/> + </td><td> + </td> + </tr> + </table> + </xpath> </field> </record> @@ -106,10 +108,20 @@ <field name="arch" type="xml"> <field name="date" position="before"> <field name="last_invoice_date"/> - <field name="ca_to_invoice"/> + <field name="toinvoice_total"/> </field> </field> </record> + <record id="template_of_contract_action" model="ir.actions.act_window"> + <field name="name">Template of Contract</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">account.analytic.account</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + <field name="domain">[('type','=','template')]</field> + <field name="context">{'search_default_type':'template','default_type' : 'template'}</field> + </record> + <menuitem action="template_of_contract_action" id="menu_template_of_contract_action" parent="base.menu_base_config"/> </data> </openerp> |
