[FIX] misc contracts fixes, timesheets
authorFabien Pinckaers <fp@openerp.com>
Tue, 12 Mar 2013 12:12:18 +0000 (13:12 +0100)
committerFabien Pinckaers <fp@openerp.com>
Tue, 12 Mar 2013 12:12:18 +0000 (13:12 +0100)
bzr revid: fp@openerp.com-20130312121218-vsvmaj12px4vqpvz

1  2 
addons/account/account_view.xml
addons/account/project/project_view.xml
addons/account_analytic_analysis/account_analytic_analysis.py
addons/account_analytic_analysis/account_analytic_analysis_view.xml
addons/account_analytic_default/account_analytic_default_view.xml
addons/account_budget/account_budget_view.xml
addons/analytic_contract_hr_expense/analytic_contract_hr_expense.py
addons/hr_timesheet_invoice/hr_timesheet_invoice.py
addons/purchase/purchase_view.xml
addons/sale/sale.py
addons/sale/sale_view.xml

                              </group>
                              <group string="Invoices">
                                    <field name="account_collected_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
--                                  <field name="account_analytic_collected_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id), ('parent_id', '&lt;&gt;', False)]" groups="analytic.group_analytic_accounting"/>
++                                  <field name="account_analytic_collected_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id)]" groups="analytic.group_analytic_accounting"/>
  
                                    <field name="base_code_id"/>
                                    <field name="base_sign"/>
                              </group>
                              <group string="Refunds">
                                    <field name="account_paid_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
--                                  <field name="account_analytic_paid_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id), ('parent_id', '&lt;&gt;', False)]" groups="analytic.group_analytic_accounting"/>
++                                  <field name="account_analytic_paid_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id)]" groups="analytic.group_analytic_accounting"/>
  
                                    <field name="ref_base_code_id"/>
                                    <field name="ref_base_sign"/>
                                          <field name="blocked"/>
                                      </group>
                                      <group groups="analytic.group_analytic_accounting" string="Analytic">
--                                        <field name="analytic_account_id" domain="[('parent_id','!=',False)]"/>
++                                        <field name="analytic_account_id" domain="[('type','in',('normal','contract'))]"/>
                                      </group>
                                  </group>
                                  <field name="narration" colspan="4" nolabel="1" placeholder="Add an internal note..."/>
                                  <field name="blocked"/>
                                  <newline/>
                                  <field name="account_tax_id" domain="[('parent_id','=',False)]"/>
--                                <field name="analytic_account_id" domain="[('parent_id','!=',False)]" groups="analytic.group_analytic_accounting"/>
++                                <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
                                  <separator colspan="4" string="Status"/>
                                  <newline/>
                                  <field name="reconcile_id"/>
                                                  </group>
  
                                                  <group groups="analytic.group_analytic_accounting" string="Analytic">
--                                                    <field name="analytic_account_id" domain="[('parent_id','!=',False)]"/>
++                                                    <field name="analytic_account_id"/>
                                                  </group>
                                              </group>
                                              <separator string="Internal Note"/>
                                      <field name="date_maturity"/>
                                      <field name="debit" sum="Total Debit"/>
                                      <field name="credit" sum="Total Credit"/>
--                                    <field name="analytic_account_id" domain="[('parent_id','!=',False)]" groups="analytic.group_analytic_accounting"/>
++                                    <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
                                      <field name="amount_currency"/>
                                      <field name="currency_id" groups="base.group_multi_currency"/>
                                      <field name="tax_code_id"/>
@@@ -215,6 -215,6 +215,8 @@@ class account_analytic_account(osv.osv)
                      GROUP BY account_analytic_line.account_id", (child_ids,))
              for account_id, sum in cr.fetchall():
                  res[account_id] = round(sum,2)
++        for acc in self.browse(cr, uid, res.keys(), context=context):
++            res[acc.id] = res[acc.id] - (acc.timesheet_ca_invoiced or 0.0)
          res_final = res
          return res_final
  
          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)
 -            sale_ids = sale_obj.search(cr, uid, ['|', ('project_id','=', account.id), ('partner_id', '=', account.partner_id.id), ('state', '=', 'manual')], context=context)
++            sale_ids = sale_obj.search(cr, uid, [('project_id','=', account.id), ('state', '=', 'manual')], context=context)
              for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
                  if not sale.invoiced:
                      res[account.id] += sale.amount_untaxed
  
          return True
  
+     def onchange_invoice_on_timesheets(self, cr, uid, ids, invoice_on_timesheets, context=None):
 -        return {'value': {'use_timesheets': invoice_on_timesheets}}
++        if not invoice_on_timesheets:
++            return {}
++        result = {'value': {'use_timesheets': True}}
++        try:
++            to_invoice = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'hr_timesheet_invoice', 'timesheet_invoice_factor1')
++            result['value']['to_invoice'] = to_invoice[1]
++        except ValueError:
++            pass
++        return result
  class account_analytic_account_summary_user(osv.osv):
      _name = "account_analytic_analysis.summary.user"
      _description = "Hours Summary by User"
@@@ -5,6 -5,6 +5,15 @@@
              <field name="name">Sales Orders</field>
              <field name="res_model">sale.order</field>
              <field name="src_model">account.analytic.account</field>
++            <field name="help" type="html">
++              <p class="oe_view_nocontent_create">
++                Click to create a quotation that can be converted into a sales
++                order.
++              </p><p>
++                Use sale orders to track everything that should be invoiced
++                at a fix price on a contract.
++              </p>
++            </field>
          </record>
  
          <!-- Inherited Analytic Account form for contracts -->
@@@ -26,6 -26,9 +35,9 @@@
                          </div>
                      </div>
                  </xpath>
+                 <field name="partner_id" position="attributes">
 -                    <attribute name="attrs">{'required': [('invoice_on_timesheets', '=', True)]}</attribute>
++                    <attribute name="attrs">{'required': [('type','=','contract'),'|',('fix_price_invoices','=',True), ('invoice_on_timesheets', '=', True)]}</attribute>
+                 </field>
                  <xpath expr='//group[@name="invoice_on_timesheets"]' position="replace">
                  </xpath>
                  <xpath expr='//separator[@name="description"]' position='before'>
                                      or view
                                  </span>
  
--                                <span attrs="{'invisible': ['|',('fix_price_to_invoice','&lt;&gt;',0.0 ),('partner_id','=',False)]}" class="oe_grey">
++                                <span attrs="{'invisible': [('fix_price_to_invoice','&lt;&gt;',0.0 )]}" class="oe_grey">
                                      No order to invoice, create
                                  </span>
-                                 <button name="%(action_sales_order)d" string="Sale Orders"
+                                 <button name="%(action_sales_order)d" string="Sales Orders"
                                      type="action"
                                      class="oe_link"
-                                     context="{'default_partner_id': [partner_id], 'search_default_partner_id': [partner_id],'search_default_project_id': [active_id],'default_project_id': [active_id]}"
+                                     context="{'default_partner_id': [partner_id], 'search_default_project_id': [active_id],'default_project_id': [active_id]}"
                                      />
                              </td>
                          </tr><tr>
@@@ -7,7 -7,7 +7,7 @@@
              <field name="arch" type="xml">
                  <tree string="Analytic Defaults">
                      <field name="sequence"/>
--                    <field name="analytic_id" required="0" domain="[('parent_id','!=',False)]" groups="analytic.group_analytic_accounting"/>
++                    <field name="analytic_id" required="0" groups="analytic.group_analytic_accounting"/>
                      <field name="product_id"/>
                      <field name="partner_id"/>
                      <field name="user_id"/>
@@@ -24,7 -24,7 +24,7 @@@
              <field name="arch" type="xml">
                  <form string="Analytic Defaults" version="7.0">
                      <group col="4">
--                        <field name="analytic_id" required="1" domain="[('parent_id','!=',False)]" groups="analytic.group_analytic_accounting"/>
++                        <field name="analytic_id" required="1" groups="analytic.group_analytic_accounting"/>
                          <field name="sequence"/>
                          <separator string="Conditions" colspan="4"/>
                          <field name="product_id"/>
@@@ -60,7 -60,7 +60,7 @@@
                              <field name="crossovered_budget_line" widget="one2many_list" mode="tree">
                                  <tree string="Budget Lines"  editable="top">
                                      <field name="crossovered_budget_id"/>
--                                    <field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('parent_id','!=',False)]"/>
++                                    <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
                                      <field name="date_from"/>
                                      <field name="date_to"/>
                                      <field name="paid_date"/>
@@@ -72,7 -72,7 +72,7 @@@
                                  <form string="Budget Lines" version="7.0">
                                      <group col="4">
                                          <field name="crossovered_budget_id"/>
--                                        <field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('parent_id','!=',False)]" />
++                                        <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
                                          <field name="date_from"/>
                                          <field name="date_to"/>
                                          <field name="paid_date"/>
@@@ -22,6 -22,6 +22,8 @@@ from openerp.osv import fields, os
  from openerp.osv.orm import intersect
  from openerp.tools.translate import _
  
++from openerp.addons.decimal_precision import decimal_precision as dp
++
  class account_analytic_account(osv.osv):
      _name = "account.analytic.account"
      _inherit = "account.analytic.account"
                  res[account.id] += line.invoice_id.amount_untaxed
          return res
  
++    def _ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
++        result = super(account_analytic_account, self)._ca_invoiced_calc(cr, uid, ids, name, arg, context=context)
++        for acc in self.browse(cr, uid, result.keys(), context=context):
++            result[acc.id] = result[acc.id] - (acc.expense_invoiced or 0.0)
++        return result
  
      _columns = {
          'charge_expenses' : fields.boolean('Charge Expenses'),
          'expense_to_invoice' : fields.function(_expense_to_invoice_calc, type='float'),
          'remaining_expense' : fields.function(_remaining_expnse_calc, type="float"), 
          'est_expenses': fields.float('Estimation of Expenses to Invoice'),
++        'ca_invoiced': fields.function(_ca_invoiced_calc, type='float', string='Invoiced Amount',
++            help="Total customer invoiced amount for this account.",
++            digits_compute=dp.get_precision('Account')),
      }
  
      def on_change_template(self, cr, uid, id, template_id, context=None):
@@@ -74,9 -88,10 +74,6 @@@ class account_analytic_account(osv.osv)
          'to_invoice': fields.many2one('hr_timesheet_invoice.factor', 'Timesheet Invoicing Ratio',
              help="You usually invoice 100% of the timesheets. But if you mix fixed price and timesheet invoicing, you may use another ratio. For instance, if you do a 20% advance invoice (fixed price, based on a sales order), you should invoice the rest on timesheet with a 80% ratio."),
      }
--    _defaults = {
-         'pricelist_id': lambda self, cr, uid, ctx: ctx.get('pricelist_id', False),
-     }
 -        'pricelist_id': _get_default_pricelist_id,
 -        'to_invoice': _get_default_to_invoice,
 -    }
  
      def on_change_partner_id(self, cr, uid, ids, partner_id, name, context=None):
          res = super(account_analytic_account, self).on_change_partner_id(cr, uid, ids, partner_id, name, context=context)
                                      <field name="name"/>
                                      <field name="date_planned"/>
                                      <field name="company_id" groups="base.group_multi_company" widget="selection"/>
--                                    <field name="account_analytic_id" groups="purchase.group_analytic_accounting" domain="[('parent_id','!=',False)]"/>
++                                    <field name="account_analytic_id" groups="purchase.group_analytic_accounting" domain="[('type','in',('normal','contract'))]"/>
                                      <field name="product_qty" on_change="onchange_product_id(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id,parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)"/>
                                      <field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)"/>
                                      <field name="price_unit"/>
                              <group>
                                  <field name="taxes_id" widget="many2many_tags" domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
                                  <field name="date_planned" widget="date"/>
--                                <field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting" domain="[('parent_id','!=',False)]" />
++                                <field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting"/>
                                  <field name="company_id" groups="base.group_multi_company" widget="selection"/>
                              </group>
                          </group>
                                      domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
                                  <field name="date_planned" widget="date" readonly="1"/>
                                  <field name="company_id" groups="base.group_multi_company" widget="selection"/>
--                                <field name="account_analytic_id" colspan="4" groups="purchase.group_analytic_accounting" domain="[('parent_id','!=',False)]"/>
++                                <field name="account_analytic_id" colspan="4" groups="purchase.group_analytic_accounting"/>
                                  <field name="invoiced"/>
                              </group>
                          </group>
@@@ -704,7 -704,7 +704,9 @@@ class sale_order_line(osv.osv)
          'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True),
          'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True),
          'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean',
--            store={'account.invoice': (_order_lines_from_invoice, ['state'], 10)}),
++            store={
++                'account.invoice': (_order_lines_from_invoice, ['state'], 10),
++                'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)}),
          'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}),
          'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
           help="From stock: When needed, the product is taken from the stock or we wait for replenishment.\nOn order: When needed, the product is purchased or produced."),
              vals = self._prepare_order_line_invoice_line(cr, uid, line, False, context)
              if vals:
                  inv_id = self.pool.get('account.invoice.line').create(cr, uid, vals, context=context)
--                cr.execute('insert into sale_order_line_invoice_rel (order_line_id,invoice_id) values (%s,%s)', (line.id, inv_id))
++                self.write(cr, uid, [line.id], {'invoice_lines': [(4, inv_id)]}, context=context)
                  sales.add(line.order_id.id)
                  create_ids.append(inv_id)
          # Trigger workflow events
                              <field name="partner_id" on_change="onchange_partner_id(partner_id, context)" domain="[('customer','=',True)]" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
                              <field name="partner_invoice_id" groups="sale.group_delivery_invoice_address" context="{'default_type':'invoice'}"/>
                              <field name="partner_shipping_id" groups="sale.group_delivery_invoice_address" context="{'default_type':'delivery'}"/>
--                            <field name="project_id" context="{'partner_id':partner_id, 'pricelist_id':pricelist_id, 'default_name':name, 'default_type': 'contract'}" groups="sale.group_analytic_accounting" domain="[('type','in',['view','normal','contract'])]"/>
++                            <field name="project_id" context="{'partner_id':partner_id, 'default_pricelist_id':pricelist_id, 'default_name':name, 'default_type': 'contract'}" groups="sale.group_analytic_accounting" domain="[('type','in',['view','normal','contract'])]"/>
                          </group>
                          <group>
                              <field name="date_order"/>