ACCOUNT,ACCOUNT_TAX_INCLUDE: improve invoice encoding (supplier invoice, default...
authorced <>
Fri, 11 May 2007 11:52:16 +0000 (11:52 +0000)
committerced <>
Fri, 11 May 2007 11:52:16 +0000 (11:52 +0000)
bzr revid: ced-15fcc3c1b60f5ded8d0fd8a501061cb05a8fa249

addons/account/account.py
addons/account/account_invoice_view.xml
addons/account/invoice.py
addons/account_tax_include/__init__.py
addons/account_tax_include/account.py [deleted file]
addons/account_tax_include/invoice_tax_incl.py
addons/account_tax_include/invoice_tax_incl.xml

index cf0b0cc..656f5e4 100644 (file)
@@ -845,6 +845,7 @@ class account_tax(osv.osv):
                'child_ids':fields.one2many('account.tax', 'parent_id', 'Childs Tax Account'),
                'child_depend':fields.boolean('Tax on Childs', help="Indicate if the tax computation is based on the value computed for the computation of child taxes or based on the total amount."),
                'python_compute':fields.text('Python Code'),
+               'python_compute_inv':fields.text('Python Code (reverse)'),
                'python_applicable':fields.text('Python Code'),
                'tax_group': fields.selection([('vat','VAT'),('other','Other')], 'Tax Group', help="If a default tax if given in the partner it only override taxes from account (or product) of the same group."),
 
@@ -873,9 +874,10 @@ class account_tax(osv.osv):
                return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0]
        _defaults = {
                'python_compute': lambda *a: '''# price_unit\n# address : res.partner.address object or False\n# product : product.product object or None\n# partner : res.partner object or None\n\nresult = price_unit * 0.10''',
+               'python_compute_inv': lambda *a: '''# price_unit\n# address : res.partner.address object or False\n# product : product.product object or False\n\nresult = price_unit * 0.10''',
                'applicable_type': lambda *a: 'true',
                'type': lambda *a: 'percent',
-               'amount': lambda *a: 0.196,
+               'amount': lambda *a: 0,
                'active': lambda *a: 1,
                'sequence': lambda *a: 1,
                'tax_group': lambda *a: 'vat',
@@ -948,7 +950,6 @@ class account_tax(osv.osv):
                                cur_price_unit+=amount2
                return res
 
-
        def compute(self, cr, uid, taxes, price_unit, quantity, address_id=None, product=None, partner=None):
 
                """
@@ -963,6 +964,71 @@ class account_tax(osv.osv):
                for r in res:
                        r['amount'] *= quantity
                return res
+
+       def _unit_compute_inv(self, cr, uid, taxes, price_unit, address_id=None, product=None, partner=None):
+               taxes = self._applicable(cr, uid, taxes, price_unit, address_id, product, partner)
+
+               res = []
+               taxes.reverse()
+               cur_price_unit=price_unit
+               for tax in taxes:
+                       # we compute the amount for the current tax object and append it to the result
+                       if tax.type=='percent':
+                               amount = cur_price_unit - (cur_price_unit / (1 + tax.amount))
+                               res.append({'id':tax.id, 'name':tax.name, 'amount':amount, 'account_collected_id':tax.account_collected_id.id, 'account_paid_id':tax.account_paid_id.id, 'base_code_id': tax.base_code_id.id, 'ref_base_code_id': tax.ref_base_code_id.id, 'sequence': tax.sequence, 'base_sign': tax.base_sign, 'tax_sign': tax.tax_sign, 'ref_base_sign': tax.ref_base_sign, 'ref_tax_sign': tax.ref_tax_sign, 'price_unit': cur_price_unit - amount, 'tax_code_id': tax.tax_code_id.id, 'ref_tax_code_id': tax.ref_tax_code_id.id,})
+                       elif tax.type=='fixed':
+                               res.append({'id':tax.id, 'name':tax.name, 'amount':tax.amount, 'account_collected_id':tax.account_collected_id.id, 'account_paid_id':tax.account_paid_id.id, 'base_code_id': tax.base_code_id.id, 'ref_base_code_id': tax.ref_base_code_id.id, 'sequence': tax.sequence, 'base_sign': tax.base_sign, 'tax_sign': tax.tax_sign, 'ref_base_sign': tax.ref_base_sign, 'ref_tax_sign': tax.ref_tax_sign, 'price_unit': 1, 'tax_code_id': tax.tax_code_id.id, 'ref_tax_code_id': tax.ref_tax_code_id.id,})
+                       elif tax.type=='code':
+                               address = address_id and self.pool.get('res.partner.address').browse(cr, uid, address_id) or None
+                               localdict = {'price_unit':cur_price_unit, 'address':address, 'product':product, 'partner':partner}
+                               exec tax.python_compute_inv in localdict
+                               amount = localdict['result']
+                               res.append({
+                                       'id': tax.id,
+                                       'name': tax.name,
+                                       'amount': amount,
+                                       'account_collected_id': tax.account_collected_id.id,
+                                       'account_paid_id': tax.account_paid_id.id,
+                                       'base_code_id': tax.base_code_id.id,
+                                       'ref_base_code_id': tax.ref_base_code_id.id,
+                                       'sequence': tax.sequence,
+                                       'base_sign': tax.base_sign,
+                                       'tax_sign': tax.tax_sign,
+                                       'ref_base_sign': tax.ref_base_sign,
+                                       'ref_tax_sign': tax.ref_tax_sign,
+                                       'price_unit': cur_price_unit - amount,
+                                       'tax_code_id': tax.tax_code_id.id,
+                                       'ref_tax_code_id': tax.ref_tax_code_id.id,
+                               })
+                       amount2 = res[-1]['amount']
+                       if len(tax.child_ids):
+                               if tax.child_depend:
+                                       del res[-1]
+                                       amount = amount2
+                               else:
+                                       amount = amount2
+                       for t in tax.child_ids:
+                               parent_tax = self._unit_compute_inv(cr, uid, [t], amount, address_id)
+                               res.extend(parent_tax)
+                       if tax.include_base_amount:
+                               cur_price_unit-=amount
+               taxes.reverse()
+               return res
+
+       def compute_inv(self, cr, uid, taxes, price_unit, quantity, address_id=None, product=None, partner=None):
+               """
+               Compute tax values for given PRICE_UNIT, QUANTITY and a buyer/seller ADDRESS_ID.
+               Price Unit is a VAT included price
+
+               RETURN:
+                       [ tax ]
+                       tax = {'name':'', 'amount':0.0, 'account_collected_id':1, 'account_paid_id':2}
+                       one tax for each tax id in IDS and their childs
+               """
+               res = self._unit_compute_inv(cr, uid, taxes, price_unit, address_id, product, partner=None)
+               for r in res:
+                       r['amount'] *= quantity
+               return res
 account_tax()
 
 # ---------------------------------------------------------
index 318e0bc..f5705fb 100644 (file)
@@ -88,7 +88,7 @@
                                <field name="account_id" select="1"/>
                                <field name="manual" select="1"/>
                                <field name="amount" select="1"/>
-                               <field name="base"/>
+                               <field name="base" readonly="0"/>
                                <separator string="Tax codes" colspan="4"/>
                                <field name="base_code_id"/>
                                <field name="base_amount"/>
 
        <record model="ir.ui.view" id="invoice_supplier_form">
                <field name="name">account.invoice.supplier.form</field>
-               <field name="model">account.invoice.supplier</field>
+               <field name="model">account.invoice</field>
                <field name="type">form</field>
+               <field name="priority">2</field>
                <field name="arch" type="xml">
                        <form string="Supplier invoice">
                        <notebook>
                                <page string="Invoice">
-                                       <field name="journal_id" select="1"/>
-                                       <field name="type" select="1"/>
+                                       <field name="journal_id" domain="[('type', '=', 'purchase')]" select="1"/>
+                                       <field name="type" select="1" readonly="1"/>
                                        <field name="partner_id" on_change="onchange_partner_id(type,partner_id)" select="1"/>
                                        <field name="address_invoice_id" domain="[('partner_id','=',partner_id)]"/>
                                        <field name="account_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id),('journal_id','=',journal_id)]" />
                                        <field name="date_due" select="1"/>
 
 
-                                       <field name="check_total"/>
-                                       <field name="currency_id" on_change="onchange_currency_id(currency_id)" select="1"/>
 
                                        <field name="name" select="1"/>
-                                       <field name="number" select="1"/>
+                                       <field name="reference" select="1"/>
 
-                                       <field name="invoice_line" nolabel="1" colspan="4">
+                                       <field name="check_total" required="1"/>
+                                       <field name="currency_id" on_change="onchange_currency_id(currency_id)" select="1"/>
+                                       <field name="invoice_line" nolabel="1" colspan="4" default_get="{'check_total': check_total, 'invoice_line': invoice_line, 'address_invoice_id': address_invoice_id, 'partner_id': partner_id, 'price_type': 'price_type' in dir() and price_type or False}">
                                                <tree string="Invoice lines" editable="bottom">
-                                                       <field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id)"/>
+                                                       <field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, price_unit, parent.address_invoice_id)"/>
                                                        <field name="account_id" on_change="onchange_account_id(parent.partner_id,account_id)" domain="[('company_id', '=', parent.company_id),('journal_id','=',parent.journal_id)]"/>
                                                        <field name="invoice_line_tax_id" view_mode="2"/>
                                                        <field name="account_analytic_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id)]" />
                                                        <field name="uos_id" invisible="True"/>
                                                </tree>
                                        </field>
-                                       <group col="2" colspan="2">
-                                               <field name="tax_line" nolabel="1" colspan="2">
+                                       <group col="1" colspan="2">
+                                               <field name="tax_line" nolabel="1">
                                                        <tree string="Taxes" editable="bottom">
                                                                <field name="name"/>
-                                                               <field name="base" on_change="base_change(base)"/>
+                                                               <field name="base" on_change="base_change(base)" readonly="1"/>
                                                                <field name="amount" on_change="amount_change(amount)"/>
 
                                                                <field name="base_amount" invisible="True"/>
                                                        </tree>
                                                </field>
                                        </group>
-                                       <group col="4" colspan="2">
+                                       <group col="3" colspan="2">
+                                               <label/>
                                                <field name="amount_untaxed"/>
+                                               <button name="button_reset_taxes" string="Reset taxes" states="draft" type="object"/>
                                                <field name="amount_tax"/>
+                                               <button name="button_compute" string="Compute" states="draft" type="object"/>
                                                <field name="amount_total"/>
-                                               <button name="button_compute" string="Compute taxes" states="draft" type="object" colspan="2"/>
-                                               <field name="state" select="1" colspan="4"/>
-                                               <newline/>
-                                               <group col="3" colspan="4">
+                                               <label/>
+                                               <field name="state" select="1"/>
+                                               <group col="3" colspan="3">
                                                        <button name="invoice_open" states="draft,proforma" string="Create"/>
                                                        <button name="invoice_cancel" states="draft,proforma,sale,open" string="Cancel"/>
                                                        <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object"/>
                                        <newline/>
                                        <field name="partner_bank_id" domain="[('partner_id','=',partner_id)]"/>
                                        <field name="payment_term" on_change="onchange_payment_term_date_invoice(payment_term, date_invoice)" />
-                                       <field name="reference" select="1"/>
+                                       <field name="number" select="1"/>
                                        <field name="origin"/>
                                        <field name="address_contact_id" domain="[('partner_id','=',partner_id)]" colspan="4"/>
-                                       <field name="partner_ref"/>
-                                       <field name="partner_contact"/>
                                        <field name="move_id"/>
                                        <field name="date_invoice" on_change="onchange_payment_term_date_invoice(payment_term, date_invoice)" select="1"/>
                                        <field name="period_id"/><label string="(keep empty to use the current period)" align="0.0" colspan="2"/>
 
 
        <record model="ir.ui.view" id="invoice_form">
-               <field name="name">account.invoice.form1</field>
+               <field name="name">account.invoice.form</field>
                <field name="model">account.invoice</field>
                <field name="type">form</field>
                <field name="arch" type="xml">
                        <form string="Invoice">
                        <notebook>
                                <page string="Invoice">
-                                       <field name="name" select="1"/>
-                                       <field name="currency_id" on_change="onchange_currency_id(currency_id)" select="1"/>
-                                       <newline/>
-                                       <field name="type" select="1"/>
-                                       <field name="number" select="1"/>
-                                       <newline/>
-
+                                       <field name="journal_id" select="1"/>
+                                       <field name="type" select="1" readonly="1"/>
                                        <field name="partner_id" on_change="onchange_partner_id(type,partner_id)" select="1"/>
                                        <field name="address_invoice_id" domain="[('partner_id','=',partner_id)]"/>
-                                       <field name="partner_bank_id" domain="[('partner_id','=',partner_id)]"/>
-
                                        <field name="account_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', company_id),('journal_id','=',journal_id)]" />
-
                                        <field name="payment_term" on_change="onchange_payment_term_date_invoice(payment_term, date_invoice)" />
-                                       <field name="date_due" select="1"/>
-
-                                       <field name="journal_id" select="1"/>
+                                       <field name="name" select="1"/>
+                                       <field name="number" select="1"/>
+                                       <field name="currency_id" on_change="onchange_currency_id(currency_id)" select="1"/>
 
                                        <field name="invoice_line" nolabel="1" widget="one2many_list" colspan="4"/>
-                                       <group colspan="4" col="7">
+
+                                       <group col="1" colspan="2">
+                                               <field name="tax_line" nolabel="1">
+                                                       <tree string="Taxes" editable="bottom">
+                                                               <field name="name"/>
+                                                               <field name="base" on_change="base_change(base)" readonly="1"/>
+                                                               <field name="amount" on_change="amount_change(amount)"/>
+
+                                                               <field name="base_amount" invisible="True"/>
+                                                               <field name="tax_amount" invisible="True"/>
+                                                       </tree>
+                                               </field>
+                                       </group>
+                                       <group col="3" colspan="2">
+                                               <label/>
                                                <field name="amount_untaxed"/>
+                                               <button name="button_reset_taxes" string="Reset taxes" states="draft" type="object"/>
                                                <field name="amount_tax"/>
-                                               <field name="amount_total"/>
                                                <button name="button_compute" string="Compute" states="draft" type="object"/>
-                                       </group>
-
-                                       <group col="6" colspan="4">
+                                               <field name="amount_total"/>
+                                               <label/>
                                                <field name="state" select="1"/>
-                                               <button name="invoice_proforma" states="draft" string="Create PRO-FORMA"/>
-                                               <button name="invoice_open" states="draft,proforma" string="Create Invoice"/>
-                                               <button name="invoice_cancel" states="draft,proforma,sale,open" string="Cancel Invoice"/>
-                                               <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object"/>
+                                               <group col="4" colspan="3" expand="1">
+                                                       <button name="invoice_proforma" states="draft" string="PRO-FORMA"/>
+                                                       <button name="invoice_open" states="draft,proforma" string="Create"/>
+                                                       <button name="invoice_cancel" states="draft,proforma,sale,open" string="Cancel"/>
+                                                       <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object"/>
+                                               </group>
                                        </group>
                                </page>
-                               <page string="Tax Lines">
-                                       <field name="tax_line" nolabel="1" widget="one2many_list" colspan="4"/>
-                               </page>
                                <page string="Other Information">
                                        <field name="company_id"/>
                                        <newline/>
+                                       <field name="partner_bank_id" domain="[('partner_id','=',partner_id)]"/>
+                                       <field name="date_due" select="1"/>
                                        <field name="reference" select="1"/>
                                        <field name="origin"/>
                                        <field name="address_contact_id" domain="[('partner_id','=',partner_id)]" colspan="4"/>
-                                       <field name="partner_ref"/>
-                                       <field name="partner_contact"/>
                                        <field name="move_id"/>
                                        <field name="date_invoice" on_change="onchange_payment_term_date_invoice(payment_term, date_invoice)" select="1"/>
                                        <field name="period_id"/><label string="(keep empty to use the current period)" align="0.0" colspan="2"/>
                <field name="view_type">form</field>
                <field name="view_id" ref="invoice_form"/>
        </record>
-       <menuitem name="Financial Management/Invoices" id="menu_action_invoice_form" action="action_invoice_form" sequence="6"/>
+       <menuitem name="Financial Management/Invoices" sequence="6"/>
 
        <record model="ir.actions.act_window" id="action_invoice_tree1">
                <field name="name">account.invoice</field>
                <field name="res_model">account.invoice</field>
                <field name="view_type">form</field>
-               <field name="view_mode">tree,form</field>
+               <field name="view_mode">form,tree</field>
+               <field name="view_id" eval="invoice_form"/>
                <field name="domain">[('type','=','out_invoice')]</field>
                <field name="context">{'type':'out_invoice'}</field>
        </record>
        
        <record model="ir.actions.act_window" id="action_invoice_tree2">
                <field name="name">account.invoice.supplier</field>
-               <field name="res_model">account.invoice.supplier</field>
+               <field name="res_model">account.invoice</field>
                <field name="view_type">form</field>
                <field name="view_mode">form,tree</field>
                <field name="view_id" eval="invoice_supplier_form"/>
                <field name="name">account.invoice</field>
                <field name="res_model">account.invoice</field>
                <field name="view_type">form</field>
-               <field name="view_mode">tree,form</field>
+               <field name="view_mode">form,tree</field>
+               <field name="view_id" eval="invoice_form"/>
                <field name="domain">[('type','=','out_refund')]</field>
                <field name="context">{'type':'out_refund'}</field>
        </record>
        <menuitem name="Financial Management/Invoices/Customers Refund" id="menu_action_invoice_tree3" action="action_invoice_tree3"/>
 
        <record model="ir.actions.act_window" id="action_invoice_tree4">
-               <field name="name">account.invoice</field>
+               <field name="name">account.invoice.supplier</field>
                <field name="res_model">account.invoice</field>
                <field name="view_type">form</field>
-               <field name="view_mode">tree,form</field>
+               <field name="view_mode">form,tree</field>
+               <field name="view_id" eval="invoice_supplier_form"/>
                <field name="domain">[('type','=','in_refund')]</field>
                <field name="context">{'type':'in_refund'}</field>
        </record>
                <field name="domain">[('state','=','draft'),('type','=','in_invoice')]</field>
                <field name="context">{'type':'in_invoice'}</field>
        </record>
-       <menuitem name="Financial Management/Invoices/Suppliers Invoices/Draft" id="menu_action_invoice_tree8" action="action_invoice_tree8"/>
+       <menuitem name="Financial Management/Invoices/Suppliers Invoices/Draft Invoices" id="menu_action_invoice_tree8" action="action_invoice_tree8"/>
 
        <record model="ir.actions.act_window" id="action_invoice_tree9">
                <field name="name">account.invoice</field>
                <field name="domain">[('state','=','open'),('type','=','in_invoice')]</field>
                <field name="context">{'type':'in_invoice'}</field>
        </record>
-       <menuitem name="Financial Management/Invoices/Suppliers Invoices/Opened" id="menu_action_invoice_tree9" action="action_invoice_tree9"/>
+       <menuitem name="Financial Management/Invoices/Suppliers Invoices/Opened Invoices" id="menu_action_invoice_tree9" action="action_invoice_tree9"/>
 
        <record model="ir.actions.act_window" id="action_invoice_tree10">
                <field name="name">account.invoice</field>
                <field name="domain">[('state','=','draft'),('type','=','out_refund')]</field>
                <field name="context">{'type':'out_refund'}</field>
        </record>
-       <menuitem name="Financial Management/Invoices/Customers Refund/Draft" id="menu_action_invoice_tree10" action="action_invoice_tree10"/>
+       <menuitem name="Financial Management/Invoices/Customers Refund/Draft Invoices" id="menu_action_invoice_tree10" action="action_invoice_tree10"/>
        
        <record model="ir.actions.act_window" id="action_invoice_tree11">
                <field name="name">account.invoice</field>
                <field name="domain">[('state','=','open'),('type','=','out_refund')]</field>
                <field name="context">{'type':'out_refund'}</field>
        </record>
-       <menuitem name="Financial Management/Invoices/Customers Refund/Opened" id="menu_action_invoice_tree11" action="action_invoice_tree11"/>
+       <menuitem name="Financial Management/Invoices/Customers Refund/Opened Invoices" id="menu_action_invoice_tree11" action="action_invoice_tree11"/>
 
        <record model="ir.actions.act_window" id="action_invoice_tree12">
                <field name="name">account.invoice</field>
                <field name="domain">[('state','=','draft'),('type','=','in_refund')]</field>
                <field name="context">{'type':'in_refund'}</field>
        </record>
-       <menuitem name="Financial Management/Invoices/Suppliers Refund/Draft" id="menu_action_invoice_tree12" action="action_invoice_tree12"/>
+       <menuitem name="Financial Management/Invoices/Suppliers Refund/Draft Invoices" id="menu_action_invoice_tree12" action="action_invoice_tree12"/>
        
        <record model="ir.actions.act_window" id="action_invoice_tree13">
                <field name="name">account.invoice</field>
                <field name="domain">[('state','=','open'),('type','=','in_refund')]</field>
                <field name="context">{'type':'in_refund'}</field>
        </record>
-       <menuitem name="Financial Management/Invoices/Suppliers Refund/Opened" id="menu_action_invoice_tree13" action="action_invoice_tree13"/>
+       <menuitem name="Financial Management/Invoices/Suppliers Refund/Opened Invoices" id="menu_action_invoice_tree13" action="action_invoice_tree13"/>
 
 </data>
 </terp>
index 523ca18..c64ba81 100644 (file)
@@ -36,22 +36,24 @@ import pooler
 import mx.DateTime
 from mx.DateTime import RelativeDateTime
 
+from tools import config
+
 class account_invoice(osv.osv):
-       def _amount_untaxed(self, cr, uid, ids, prop, unknow_none,unknow_dict):
+       def _amount_untaxed(self, cr, uid, ids, name, args, context={}):
                id_set=",".join(map(str,ids))
                cr.execute("SELECT s.id,COALESCE(SUM(l.price_unit*l.quantity*(100-l.discount))/100.0,0)::decimal(16,2) AS amount FROM account_invoice s LEFT OUTER JOIN account_invoice_line l ON (s.id=l.invoice_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
                res=dict(cr.fetchall())
                return res
 
-       def _amount_tax(self, cr, uid, ids, prop, unknow_none,unknow_dict):
+       def _amount_tax(self, cr, uid, ids, name, args, context={}):
                id_set=",".join(map(str,ids))
                cr.execute("SELECT s.id,COALESCE(SUM(l.amount),0)::decimal(16,2) AS amount FROM account_invoice s LEFT OUTER JOIN account_invoice_tax l ON (s.id=l.invoice_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
                res=dict(cr.fetchall())
                return res
 
-       def _amount_total(self, cr, uid, ids, prop, unknow_none,unknow_dict):
-               untax = self._amount_untaxed(cr, uid, ids, prop, unknow_none,unknow_dict)
-               tax = self._amount_tax(cr, uid, ids, prop, unknow_none,unknow_dict)
+       def _amount_total(self, cr, uid, ids, name, args, context={}):
+               untax = self._amount_untaxed(cr, uid, ids, name, args, context)
+               tax = self._amount_tax(cr, uid, ids, name, args, context)
                res = {}
                for id in ids:
                        res[id] = untax.get(id,0.0) + tax.get(id,0.0)
@@ -94,7 +96,7 @@ class account_invoice(osv.osv):
                        ('in_invoice','Supplier Invoice'),
                        ('out_refund','Customer Refund'),
                        ('in_refund','Supplier Refund'),
-               ],'Type', readonly=True, states={'draft':[('readonly',False)]}, select=True),
+                       ],'Type', readonly=True, states={'draft':[('readonly', False)]}, select=True),
 
                'number': fields.char('Invoice Number', size=32, readonly=True),
                'reference': fields.char('Invoice Reference', size=64),
@@ -116,9 +118,6 @@ class account_invoice(osv.osv):
                'address_contact_id': fields.many2one('res.partner.address', 'Contact Address', readonly=True, states={'draft':[('readonly',False)]}),
                'address_invoice_id': fields.many2one('res.partner.address', 'Invoice Address', readonly=True, required=True, states={'draft':[('readonly',False)]}),
 
-               'partner_contact': fields.char('Partner Contact', size=64),
-               'partner_ref': fields.char('Partner Reference', size=64),
-
                'payment_term': fields.many2one('account.payment.term', 'Payment Term',readonly=True, states={'draft':[('readonly',False)]} ),
 
                'period_id': fields.many2one('account.period', 'Force Period', help="Keep empty to use the period of the validation date."),
@@ -134,7 +133,7 @@ class account_invoice(osv.osv):
                'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
                'journal_id': fields.many2one('account.journal', 'Journal', required=True, relate=True,readonly=True, states={'draft':[('readonly',False)]}),
                'company_id': fields.many2one('res.company', 'Company', required=True),
-
+               'check_total': fields.float('Total', digits=(16,2)),
        }
        _defaults = {
                'type': lambda *a: 'out_invoice',
@@ -212,6 +211,9 @@ class account_invoice(osv.osv):
 
                return res
 
+       def onchange_invoice_line(self, cr, uid, ids, lines):
+               return {}
+
        # go from canceled state to draft state
        def action_cancel_draft(self, cr, uid, ids, *args):
                self.write(cr, uid, ids, {'state':'draft'})
@@ -251,18 +253,47 @@ class account_invoice(osv.osv):
                        ok = ok and  bool(cr.fetchone()[0])
                return ok
 
-       def button_compute(self, cr, uid, ids, context={}):
+       def button_reset_taxes(self, cr, uid, ids, context={}):
+               ait_obj = self.pool.get('account.invoice.tax')
                for id in ids:
-                       self.pool.get('account.invoice.line').move_line_get(cr, uid, id)
+                       cr.execute("DELETE FROM account_invoice_tax WHERE invoice_id=%d", (id,))
+                       for taxe in ait_obj.compute(cr, uid, id).values():
+                               ait_obj.create(cr, uid, taxe)
+               return True
+
+       def button_compute(self, cr, uid, ids, context={}):
+               ait_obj = self.pool.get('account.invoice.tax')
+               for inv in self.browse(cr, uid, ids):
+                       compute_taxes = ait_obj.compute(cr, uid, inv.id)
+                       if not inv.tax_line:
+                               for tax in compute_taxes.values():
+                                       ait_obj.create(cr, uid, tax)
+                       else:
+                               tax_key = []
+                               for tax in inv.tax_line:
+                                       if tax.manual:
+                                               continue
+                                       key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id)
+                                       tax_key.append(key)
+                                       if not key in compute_taxes:
+                                               ait_obj.unlink(cr, uid, [tax.id])
+                                               continue
+                                       if compute_taxes[key]['base'] != tax.base:
+                                               ait_obj.write(cr, uid, [tax.id], compute_taxes[key])
+                               for key in compute_taxes:
+                                       if not key in tax_key:
+                                               ait_obj.create(cr, uid, compute_taxes[key])
                return True
 
        def action_move_create(self, cr, uid, ids, *args):
+               ait_obj = self.pool.get('account.invoice.tax')
                cur_obj = self.pool.get('res.currency')
                for inv in self.browse(cr, uid, ids):
                        if inv.move_id:
                                continue
-
-                       company_currency = inv.account_id.company_id.currency_id.id
+                       if inv.type in ('in_invoice', 'in_refund') and not inv.check_total == inv.amount_total:
+                               raise osv.except_osv('Bad total !', 'Please verify the price of the invoice !\nThe real total does not match the computed total.')
+                       company_currency = inv.company_id.currency_id.id
                        # create the analytical lines
                        line_ids = self.read(cr, uid, [inv.id], ['invoice_line'])[0]['invoice_line']
                        ils = self.pool.get('account.invoice.line').read(cr, uid, line_ids)
@@ -283,11 +314,33 @@ class account_invoice(osv.osv):
                                                'product_id': il['product_id'],
                                                'product_uom_id': il['uos_id'],
                                                'general_account_id': il['account_id'],
-                                               'journal_id': self._get_journal_analytic(cr, uid, inv.type)
+                                               'journal_id': self._get_journal_analytic(cr, uid, inv.type),
+                                               'ref': inv['number'],
                                        })]
 
+                       # check if taxes are all computed
+                       compute_taxes = ait_obj.compute(cr, uid, inv.id)
+                       if not inv.tax_line:
+                               for tax in compute_taxes.values():
+                                       ait_obj.create(cr, uid, tax)
+                       else:
+                               tax_key = []
+                               for tax in inv.tax_line:
+                                       if tax.manual:
+                                               continue
+                                       key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id)
+                                       tax_key.append(key)
+                                       if not key in compute_taxes:
+                                               raise osv.except_osv('Warning !', 'Too much taxes !')
+                                       base = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, compute_taxes[key]['base'], context={'date': inv.date_invoice})
+                                       if abs(base - tax.base) > inv.company_id.currency_id.rounding:
+                                               raise osv.except_osv('Warning !', 'Base different !')
+                               for key in compute_taxes:
+                                       if not key in tax_key:
+                                               raise osv.except_osv('Warning !', 'Taxes missing !')
+
                        # one move line per tax line
-                       iml += self.pool.get('account.invoice.tax').move_line_get(cr, uid, inv.id)
+                       iml += ait_obj.move_line_get(cr, uid, inv.id)
 
                        
                        # create one move line for the total and possibly adjust the other lines amount
@@ -519,30 +572,29 @@ class account_invoice(osv.osv):
                return True
 account_invoice()
 
-class account_invoice_supplier(osv.osv):
-       _name = "account.invoice.supplier"
-       _description = "Supplier invoice"
-       _inherits = {'account.invoice': 'account_invoice_id'}
-       _columns = {
-               'account_invoice_id': fields.many2one('account.invoice', 'Account invoice', required=True),
-               'check_total': fields.float('Total', digits=(16,2)),
-       }
-
-       def action_move_create(self, cr, uid, ids, context={}):
-               for inv in self.browse(cr, uid, ids):
-                       if inv.move_id:
-                               continue
-                       if inv.check_total <> inv.amount_total:
-                               raise osv.except_osv('Bad total !', 'Please verify the price of the invoice !\nThe real total does not match the computed total.')
-               return super(account_invoice_supplier, self).action_move_create(cr, uid, ids, context=context)
-account_invoice_supplier()
-
 class account_invoice_line(osv.osv):
        def _amount_line(self, cr, uid, ids, prop, unknow_none,unknow_dict):
                res = {}
                for line in self.browse(cr, uid, ids):
                        res[line.id] = round(line.price_unit * line.quantity * (1-(line.discount or 0.0)/100.0),2)
                return res
+
+       def _price_unit_default(self, cr, uid, context={}):
+               if 'check_total' in context:
+                       t = context['check_total']
+                       for l in context.get('invoice_line', {}):
+                               if len(l) >= 3 and l[2]:
+                                       tax_obj = self.pool.get('account.tax')
+                                       p = l[2].get('price_unit', 0) * (1-l[2].get('discount', 0)/100.0)
+                                       t = t - (p * l[2].get('quantity'))
+                                       taxes = l[2].get('invoice_line_tax_id')
+                                       if len(taxes[0]) >= 3 and taxes[0][2]:
+                                               taxes=tax_obj.browse(cr, uid, taxes[0][2])
+                                               for tax in tax_obj.compute(cr, uid, taxes, p,l[2].get('quantity'), context.get('address_invoice_id', False), l[2].get('product_id', False), context.get('partner_id', False)):
+                                                       t = t - tax['amount']
+                       return t
+               return 0
+
        _name = "account.invoice.line"
        _description = "Invoice line"
        _columns = {
@@ -551,7 +603,7 @@ class account_invoice_line(osv.osv):
                'uos_id': fields.many2one('product.uom', 'Unit', ondelete='set null'),
                'product_id': fields.many2one('product.product', 'Product', ondelete='set null'),
                'account_id': fields.many2one('account.account', 'Source Account', required=True, domain=[('type','<>','view')]),
-               'price_unit': fields.float('Unit Price', required=True),
+               'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))),
                'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal'),
                'quantity': fields.float('Quantity', required=True),
                'discount': fields.float('Discount (%)', digits=(16,2)),
@@ -561,24 +613,38 @@ class account_invoice_line(osv.osv):
        }
        _defaults = {
                'quantity': lambda *a: 1,
-               'discount': lambda *a: 0.0
+               'discount': lambda *a: 0.0,
+               'price_unit': _price_unit_default,
        }
-       def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False):
+
+       def product_id_change_unit_price_inv(self, cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context={}):
+               tax_obj = self.pool.get('account.tax')
+               if price_unit:
+                       taxes = tax_obj.browse(cr, uid, tax_id)
+                       for tax in tax_obj.compute_inv(cr, uid, taxes, price_unit, qty, address_invoice_id, product, partner_id):
+                               price_unit = price_unit - tax['amount']
+               return {'price_unit': price_unit,'invoice_line_tax_id': tax_id}
+
+       def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, price_unit=False, address_invoice_id=False, context={}):
                if not product:
-                       return {'value': {'price_unit': 0.0}, 'domain':{'product_uom':[]}}
+                       if type in ('in_invoice', 'in_refund'):
+                               return {'domain':{'product_uom':[]}}
+                       else:
+                               return {'value': {'price_unit': 0.0}, 'domain':{'product_uom':[]}}
                lang=False
-               context={'lang': lang}
+               context.update({'lang': lang})
                res = self.pool.get('product.product').browse(cr, uid, product, context=context)
                taxep=None
                if partner_id:
                        lang=self.pool.get('res.partner').read(cr, uid, [partner_id])[0]['lang']
                        taxep = self.pool.get('res.partner').browse(cr, uid, partner_id).property_account_tax
+               tax_obj = self.pool.get('account.tax')
                if type in ('out_invoice', 'out_refund'):
                        if not taxep or not taxep[0]:
                                tax_id = map(lambda x: x.id, res.taxes_id)
                        else:
                                tax_id = [taxep[0]]
-                               tp = self.pool.get('account.tax').browse(cr, uid, taxep[0])
+                               tp = tax_obj.browse(cr, uid, taxep[0])
                                for t in res.taxes_id:
                                        if not t.tax_group==tp.tax_group:
                                                tax_id.append(t.id)
@@ -587,11 +653,14 @@ class account_invoice_line(osv.osv):
                                tax_id = map(lambda x: x.id, res.supplier_taxes_id)
                        else:
                                tax_id = [taxep[0]]
-                               tp = self.pool.get('account.tax').browse(cr, uid, taxep[0])
+                               tp = tax_obj.browse(cr, uid, taxep[0])
                                for t in res.supplier_taxes_id:
                                        if not t.tax_group==tp.tax_group:
                                                tax_id.append(t.id)
-               result = {'price_unit': res.list_price, 'invoice_line_tax_id': tax_id}
+               if type in ('in_invoice', 'in_refund'):
+                       result = self.product_id_change_unit_price_inv(cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context=context)
+               else:
+                       result = {'price_unit': res.list_price, 'invoice_line_tax_id': tax_id}
 
                if not name:
                        result['name'] = res.name
@@ -600,11 +669,11 @@ class account_invoice_line(osv.osv):
                        a =  res.product_tmpl_id.property_account_income
                        if not a:
                                a = res.categ_id.property_account_income_categ
-                       result['account_id'] = a[0]
                else:
                        a =  res.product_tmpl_id.property_account_expense
                        if not a:
                                a = res.categ_id.property_account_expense_categ
+               if a:
                        result['account_id'] = a[0]
 
                domain = {}
@@ -626,56 +695,23 @@ class account_invoice_line(osv.osv):
 
                for line in inv.invoice_line:
                        res.append( {
-                               'type':'src', 
-                               'name':line.name, 
-                               'price_unit':line.price_unit, 
-                               'quantity':line.quantity, 
-                               'price':cur_obj.round(cr, uid, cur, line.quantity*line.price_unit * (1.0- (line.discount or 0.0)/100.0)),
+                               'type':'src',
+                               'name':line.name,
+                               'price_unit':line.price_unit,
+                               'quantity':line.quantity,
+                               'price':line.price_subtotal,
                                'account_id':line.account_id.id,
                                'product_id':line.product_id.id,
                                'uos_id':line.uos_id.id,
                                'account_analytic_id':line.account_analytic_id.id,
                        })
                        for tax in tax_obj.compute(cr, uid, line.invoice_line_tax_id, (line.price_unit *(1.0-(line['discount'] or 0.0)/100.0)), line.quantity, inv.address_invoice_id.id, line.product_id, inv.partner_id):
-                               val={}
-                               val['invoice_id'] = inv.id
-                               val['name'] = tax['name']
-                               val['amount'] = cur_obj.round(cr, uid, cur, tax['amount'])
-                               val['manual'] = False
-                               val['sequence'] = tax['sequence']
-                               val['base'] = tax['price_unit'] * line['quantity']
-
-                               #
-                               # Setting the tax account and amount for the line
-                               #
-                               if inv.type in ('out_invoice','in_invoice'):
-                                       val['base_code_id'] = tax['base_code_id']
-                                       val['tax_code_id'] = tax['tax_code_id']
-                                       val['base_amount'] = val['base'] * tax['base_sign']
-                                       val['tax_amount'] = val['amount'] * tax['tax_sign']
-                                       val['account_id'] = tax['account_collected_id'] or line.account_id.id
-                               else:
-                                       val['base_code_id'] = tax['ref_base_code_id']
-                                       val['tax_code_id'] = tax['ref_tax_code_id']
-                                       val['base_amount'] = val['base'] * tax['ref_base_sign']
-                                       val['tax_amount'] = val['amount'] * tax['ref_tax_sign']
-                                       val['account_id'] = tax['account_paid_id'] or line.account_id.id
-
-                               res[-1]['tax_code_id'] = val['base_code_id']
-                               res[-1]['tax_amount'] = val['base_amount']
-
-                               key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
-                               if not key in tax_grouped:
-                                       tax_grouped[key] = val
+                               if inv.type in ('out_invoice', 'in_invoice'):
+                                       res[-1]['tax_code_id'] = tax['base_code_id']
+                                       res[-1]['tax_amount'] = tax['price_unit'] * line['quantity'] * tax['base_sign']
                                else:
-                                       tax_grouped[key]['amount'] += val['amount']
-                                       tax_grouped[key]['base'] += val['base']
-                                       tax_grouped[key]['base_amount'] += val['base_amount']
-                                       tax_grouped[key]['tax_amount'] += val['tax_amount']
-               # delete automatic tax lines for this invoice
-               cr.execute("DELETE FROM account_invoice_tax WHERE NOT manual AND invoice_id=%d", (invoice_id,))
-               for t in tax_grouped.values():
-                       ait_obj.create(cr, uid, t)
+                                       res[-1]['tax_code_id'] = tax['ref_base_code_id']
+                                       res[-1]['tax_amount'] = tax['price_unit'] * line['quantity'] * tax['ref_base_sign']
                return res
 
        #
@@ -724,6 +760,47 @@ class account_invoice_tax(osv.osv):
                'base_amount': lambda *a: 0.0,
                'tax_amount': lambda *a: 0.0,
        }
+       def compute(self, cr, uid, invoice_id):
+               tax_grouped = {}
+               tax_obj = self.pool.get('account.tax')
+               cur_obj = self.pool.get('res.currency')
+               inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id)
+               cur = inv.currency_id
+
+               for line in inv.invoice_line:
+                       for tax in tax_obj.compute(cr, uid, line.invoice_line_tax_id, line.price_subtotal, line.quantity, inv.address_invoice_id.id, line.product_id, inv.partner_id):
+                               val={}
+                               val['invoice_id'] = inv.id
+                               val['name'] = tax['name']
+                               val['amount'] = cur_obj.round(cr, uid, cur, tax['amount'])
+                               val['manual'] = False
+                               val['sequence'] = tax['sequence']
+                               val['base'] = tax['price_unit'] * line['quantity']
+
+                               if inv.type in ('out_invoice','in_invoice'):
+                                       val['base_code_id'] = tax['base_code_id']
+                                       val['tax_code_id'] = tax['tax_code_id']
+                                       val['base_amount'] = val['base'] * tax['base_sign']
+                                       val['tax_amount'] = val['amount'] * tax['tax_sign']
+                                       val['account_id'] = tax['account_collected_id'] or line.account_id.id
+                               else:
+                                       val['base_code_id'] = tax['ref_base_code_id']
+                                       val['tax_code_id'] = tax['ref_tax_code_id']
+                                       val['base_amount'] = val['base'] * tax['ref_base_sign']
+                                       val['tax_amount'] = val['amount'] * tax['ref_tax_sign']
+                                       val['account_id'] = tax['account_paid_id'] or line.account_id.id
+
+                               key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
+                               if not key in tax_grouped:
+                                       tax_grouped[key] = val
+                               else:
+                                       tax_grouped[key]['amount'] += val['amount']
+                                       tax_grouped[key]['base'] += val['base']
+                                       tax_grouped[key]['base_amount'] += val['base_amount']
+                                       tax_grouped[key]['tax_amount'] += val['tax_amount']
+
+               return tax_grouped
+
        def move_line_get(self, cr, uid, invoice_id):
                res = []
                cr.execute('SELECT * FROM account_invoice_tax WHERE invoice_id=%d', (invoice_id,))
index f40f9bb..49b7b14 100644 (file)
@@ -27,4 +27,3 @@
 ##############################################################################
 
 import invoice_tax_incl
-import account
diff --git a/addons/account_tax_include/account.py b/addons/account_tax_include/account.py
deleted file mode 100644 (file)
index a0a1559..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
-#
-# $Id: account.py 1005 2005-07-25 08:41:42Z nicoe $
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#
-##############################################################################
-
-import netsvc
-from osv import fields, osv
-
-class account_tax(osv.osv):
-       _inherit = 'account.tax'
-       _description = 'Tax'
-       _columns = {
-               'python_compute_inv':fields.text('Python Code (VAT Incl)'),
-       }
-       _defaults = {
-               'python_compute_inv': lambda *a: '''# price_unit\n# address : res.partner.address object or False\n# product : product.product object or False\n\nresult = price_unit * 0.10''',
-       }
-       def _unit_compute_inv(self, cr, uid, taxes, price_unit, address_id=None, product=None, partner=None):
-               taxes = self._applicable(cr, uid, taxes, price_unit, address_id, product, partner)
-
-               res = []
-               taxes.reverse()
-               cur_price_unit=price_unit
-               for tax in taxes:
-                       # we compute the amount for the current tax object and append it to the result
-                       if tax.type=='percent':
-                               amount = cur_price_unit - (cur_price_unit / (1 + tax.amount))
-                               res.append({'id':tax.id, 'name':tax.name, 'amount':amount, 'account_collected_id':tax.account_collected_id.id, 'account_paid_id':tax.account_paid_id.id, 'base_code_id': tax.base_code_id.id, 'ref_base_code_id': tax.ref_base_code_id.id, 'sequence': tax.sequence, 'base_sign': tax.base_sign, 'tax_sign': tax.tax_sign, 'ref_base_sign': tax.ref_base_sign, 'ref_tax_sign': tax.ref_tax_sign, 'price_unit': cur_price_unit - amount, 'tax_code_id': tax.tax_code_id.id, 'ref_tax_code_id': tax.ref_tax_code_id.id,})
-                       elif tax.type=='fixed':
-                               res.append({'id':tax.id, 'name':tax.name, 'amount':tax.amount, 'account_collected_id':tax.account_collected_id.id, 'account_paid_id':tax.account_paid_id.id, 'base_code_id': tax.base_code_id.id, 'ref_base_code_id': tax.ref_base_code_id.id, 'sequence': tax.sequence, 'base_sign': tax.base_sign, 'tax_sign': tax.tax_sign, 'ref_base_sign': tax.ref_base_sign, 'ref_tax_sign': tax.ref_tax_sign, 'price_unit': 1, 'tax_code_id': tax.tax_code_id.id, 'ref_tax_code_id': tax.ref_tax_code_id.id,})
-                       elif tax.type=='code':
-                               address = address_id and self.pool.get('res.partner.address').browse(cr, uid, address_id) or None
-                               localdict = {'price_unit':cur_price_unit, 'address':address, 'product':product, 'partner':partner}
-                               exec tax.python_compute_inv in localdict
-                               amount = localdict['result']
-                               res.append({
-                                       'id': tax.id,
-                                       'name': tax.name,
-                                       'amount': amount,
-                                       'account_collected_id': tax.account_collected_id.id,
-                                       'account_paid_id': tax.account_paid_id.id,
-                                       'base_code_id': tax.base_code_id.id,
-                                       'ref_base_code_id': tax.ref_base_code_id.id,
-                                       'sequence': tax.sequence,
-                                       'base_sign': tax.base_sign,
-                                       'tax_sign': tax.tax_sign,
-                                       'ref_base_sign': tax.ref_base_sign,
-                                       'ref_tax_sign': tax.ref_tax_sign,
-                                       'price_unit': cur_price_unit - amount,
-                                       'tax_code_id': tax.tax_code_id.id,
-                                       'ref_tax_code_id': tax.ref_tax_code_id.id,
-                               })
-                       amount2 = res[-1]['amount']
-                       if len(tax.child_ids):
-                               if tax.child_depend:
-                                       del res[-1]
-                                       amount = amount2
-                               else:
-                                       amount = amount2
-                       for t in tax.child_ids:
-                               parent_tax = self._unit_compute_inv(cr, uid, [t], amount, address_id)
-                               res.extend(parent_tax)
-                       if tax.include_base_amount:
-                               cur_price_unit-=amount
-               taxes.reverse()
-               return res
-
-       def compute_inv(self, cr, uid, taxes, price_unit, quantity, address_id=None, product=None, partner=None):
-               """
-               Compute tax values for given PRICE_UNIT, QUANTITY and a buyer/seller ADDRESS_ID.
-               Price Unit is a VAT included price
-
-               RETURN:
-                       [ tax ]
-                       tax = {'name':'', 'amount':0.0, 'account_collected_id':1, 'account_paid_id':2}
-                       one tax for each tax id in IDS and their childs
-               """
-               res = self._unit_compute_inv(cr, uid, taxes, price_unit, address_id, product, partner=None)
-               for r in res:
-                       r['amount'] *= quantity
-               return res
-account_tax()
-
index e9eb8dd..7b9648a 100644 (file)
@@ -34,33 +34,39 @@ from osv import fields, osv
 import ir
 
 class account_invoice(osv.osv):
-       def _amount_untaxed(self, cr, uid, ids, prop, unknow_none,unknow_dict):
+       def _amount_untaxed(self, cr, uid, ids, name, args, context={}):
                res = {}
                for invoice in self.browse(cr,uid,ids):
-                       res[invoice.id]= reduce( lambda x, y: x+y.price_subtotal,
-                                                                       invoice.invoice_line,0)
+                       if invoice.price_type == 'tax_included':
+                               res[invoice.id]= invoice.amount_total - invoice.amount_tax
+                       else:
+                               res[invoice.id] = super(account_invoice, self)._amount_untaxed(cr, uid, [invoice.id], name, args, context)[invoice.id]
                return res
 
-       def _amount_total(self, cr, uid, ids, prop, unknow_none,unknow_dict):
+       def _amount_tax(self, cr, uid, ids, name, args, context={}):
                res = {}
                for invoice in self.browse(cr,uid,ids):
-                       res[invoice.id]= reduce( lambda x, y: x+y.price_subtotal_incl,
-                                                                       invoice.invoice_line,0)
+                       if invoice.price_type == 'tax_included':
+                               res[invoice.id] = reduce( lambda x, y: x+y.amount, invoice.tax_line,0)
+                       else:
+                               res[invoice.id] = super(account_invoice, self)._amount_tax(cr, uid, [invoice.id], name, args, context)[invoice.id]
                return res
 
-       def _amount_tax(self, cr, uid, ids, prop, unknow_none,unknow_dict):
+       def _amount_total(self, cr, uid, ids, name, args, context={}):
                res = {}
                for invoice in self.browse(cr,uid,ids):
-                       res[invoice.id]= reduce( lambda x, y: x+y.amount,
-                                                                       invoice.tax_line,0)
+                       if invoice.price_type == 'tax_included':
+                               res[invoice.id]= reduce( lambda x, y: x+y.price_subtotal_incl, invoice.invoice_line,0)
+                       else:
+                               res[invoice.id] = super(account_invoice, self)._amount_total(cr, uid, [invoice.id], name, args, context)[invoice.id]
                return res
 
        _inherit = "account.invoice"
        _columns = {
                'price_type': fields.selection([('tax_included','Tax included'),
                                                                                ('tax_excluded','Tax excluded')],
-                                                                          'Price method', required=True, readonly=True,
-                                                                          states={'draft':[('readonly',False)]}),
+                                                                               'Price method', required=True, readonly=True,
+                                                                               states={'draft':[('readonly',False)]}),
                'amount_untaxed': fields.function(_amount_untaxed, digits=(16,2), method=True,string='Untaxed Amount'),
                'amount_tax': fields.function(_amount_tax, method=True, string='Tax'),
                'amount_total': fields.function(_amount_total, method=True, string='Total'),
@@ -72,66 +78,55 @@ account_invoice()
 
 class account_invoice_line(osv.osv):
        _inherit = "account.invoice.line"
-       def _amount_line(self, cr, uid, ids, prop, unknow_none,unknow_dict):
+       def _amount_line(self, cr, uid, ids, name, args, context={}):
                """
                Return the subtotal excluding taxes with respect to price_type.
                """
-               #cur_obj = self.pool.get('res.currency')
-               cur = False
-               res = {}
-               tax_obj = self.pool.get('account.tax')
-               for line in self.browse(cr, uid, ids):
-                       res[line.id] = line.price_unit * line.quantity * (1-(line.discount or 0.0)/100.0)
-               
-                       if line.product_id and line.invoice_id.price_type == 'tax_included':
-                               taxes = tax_obj.compute_inv(cr, uid,line.product_id.taxes_id,
-                                                                                       res[line.id],
-                                                                                       line.quantity)
-                               amount = 0
-                               for t in taxes : amount = amount + t['amount']
-                               cur = cur or line.invoice_id.currency_id
-                               res[line.id]= cur.round(cr, uid, cur, res[line.id] - amount) 
-               return res
-
-       def _amount_line_incl(self, cr, uid, ids, prop, unknow_none,unknow_dict):
-               """
-               Return the subtotal including taxes with respect to price_type.
-               """
                res = {}
-               cur = False
                tax_obj = self.pool.get('account.tax')
+               res = super(account_invoice_line, self)._amount_line(cr, uid, ids, name, args, context)
+               res2 = res.copy()
                for line in self.browse(cr, uid, ids):
-                       res[line.id] = line.price_unit * line.quantity * (1-(line.discount or 0.0)/100.0)
-                       if line.product_id:
-                               prod_taxe_ids = line.product_id and [t.id for t in line.product_id.taxes_id ] or []
-                               prod_taxe_ids.sort()
-                               line_taxe_ids = [ t.id for t in line.invoice_line_tax_id if t]
-                               line_taxe_ids.sort()
-                               if prod_taxe_ids == line_taxe_ids :
-                                       continue
-                       else : continue
-                       
-                       res[line.id] = line.price_unit * line.quantity * (1-(line.discount or 0.0)/100.0)
-                       if line.invoice_id.price_type == 'tax_included':                        
-                               # remove product taxes
-                               taxes = tax_obj.compute_inv(cr, uid,line.product_id.taxes_id,
-                                                                                       res[line.id],
-                                                                                       line.quantity)
-                               amount = 0
-                               for t in taxes : amount = amount + t['amount']
-                               res[line.id]= res[line.id] - amount
-                       ## Add line taxes
-                       taxes = tax_obj.compute(cr, uid,line.invoice_line_tax_id, res[line.id], line.quantity)
-                       amount = 0
-                       for t in taxes : amount = amount + t['amount']
-                       cur = cur or line.invoice_id.currency_id                                        
-                       res[line.id]= cur.round(cr, uid, cur, res[line.id] + amount) 
+                       if line.invoice_id.price_type == 'tax_included':
+                               if line.product_id:
+                                       for tax in tax_obj.compute_inv(cr, uid,line.product_id.taxes_id, res[line.id], line.quantity):
+                                               res[line.id] = res[line.id] - tax['amount']
+                               else:
+                                       for tax in tax_obj.compute_inv(cr, uid,line.invoice_line_tax_id, res[line.id], line.quantity):
+                                               res[line.id] = res[line.id] - tax['amount']
+                       if name == 'price_subtotal_incl':
+                               if line.product_id and line.invoice_id.price_type == 'tax_included':
+                                       prod_taxe_ids = [ t.id for t in line.product_id.taxes_id ]
+                                       prod_taxe_ids.sort()
+                                       line_taxe_ids = [ t.id for t in line.invoice_line_tax_id ]
+                                       line_taxe_ids.sort()
+                               if line.product_id and line.invoice_id.price_type == 'tax_included' and prod_taxe_ids == line_taxe_ids:
+                                       res[line.id] = res2[line.id]
+                               else:
+                                       for tax in tax_obj.compute(cr, uid, line.invoice_line_tax_id, res[line.id], line.quantity):
+                                               res[line.id] = res[line.id] + tax['amount']
+                       res[line.id]= round(res[line.id], 2)
                return res
 
+       def _price_unit_default(self, cr, uid, context={}):
+               if 'check_total' in context:
+                       t = context['check_total']
+                       if context.get('price_type', False) == 'tax_included':
+                               for l in context.get('invoice_line', {}):
+                                       if len(l) >= 3 and l[2]:
+                                               p = l[2].get('price_unit', 0) * (1-l[2].get('discount', 0)/100.0)
+                                               t = t - (p * l[2].get('quantity'))
+                               return t
+                       return super(account_invoice_line, self)._price_unit_default(cr, uid, context)
+               return 0
 
        _columns = {
-               'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal w/o vat'),
-               'price_subtotal_incl': fields.function(_amount_line_incl, method=True, string='Subtotal'),
+               'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal w/o tax'),
+               'price_subtotal_incl': fields.function(_amount_line, method=True, string='Subtotal'),
+       }
+
+       _defaults = {
+               'price_unit': _price_unit_default,
        }
 
        #
@@ -148,79 +143,35 @@ class account_invoice_line(osv.osv):
                cur_obj = self.pool.get('res.currency')
                ait_obj = self.pool.get('account.invoice.tax')
                cur = inv.currency_id
-               for line in inv.invoice_line:
-                       price_unit = line.price_unit
-                       if line.product_id:
-                               prod_taxe_ids = [ t.id for t in line.product_id.taxes_id ]
-                               prod_taxe_ids.sort()
-                               line_taxe_ids = [ t.id for t in line.invoice_line_tax_id]
-                               line_taxe_ids.sort()
-                       if line.product_id and prod_taxe_ids != line_taxe_ids :
-                               price_unit= reduce( lambda x, y: x-y['amount'],
-                                                                       tax_obj.compute_inv(cr, uid,line.product_id.taxes_id,
-                                                                                                               line.price_unit * (1-(line.discount or 0.0)/100.0), line.quantity),
-                                                                       price_unit)
-                               taxes =tax_obj.compute(cr, uid, line.invoice_line_tax_id,
-                                                                          (price_unit *(1.0-(line['discount'] or 0.0)/100.0)),
-                                                                          line.quantity, inv.address_invoice_id.id)
-                       else:
-                               taxes= tax_obj.compute_inv(cr, uid, line.invoice_line_tax_id,
-                                                                                  (line.price_unit *(1.0-(line['discount'] or 0.0)/100.0)),
-                                                                                  line.quantity, inv.address_invoice_id.id)
 
+               for line in inv.invoice_line:
                        res.append( {
-                               'type':'src', 
-                               'name':line.name, 
-                               'price_unit':price_unit, 
-                               'quantity':line.quantity, 
-                               'price':line.quantity*price_unit * (1.0- (line.discount or 0.0)/100.0),
+                               'type':'src',
+                               'name':line.name,
+                               'price_unit':line.price_unit,
+                               'quantity':line.quantity,
+                               'price':line.price_subtotal,
                                'account_id':line.account_id.id,
                                'product_id': line.product_id.id,
                                'uos_id':line.uos_id.id,
                                'account_analytic_id':line.account_analytic_id.id,
                        })
-                       for tax in taxes:
-                               val={}
-                               val['invoice_id'] = inv.id
-                               val['name'] = tax['name']
-                               val['amount'] = cur_obj.round(cr, uid, cur, tax['amount'])
-                               val['manual'] = False
-                               val['sequence'] = tax['sequence']
-                               val['base'] = tax['price_unit'] * line['quantity']
-
-                               res[-1]['price']-=tax['amount']
-
-                               #
-                               # Setting the tax account and amount for the line
-                               #
-                               if inv.type in ('out_invoice','in_invoice'):
-                                       val['base_code_id'] = tax['base_code_id']
-                                       val['tax_code_id'] = tax['tax_code_id']
-                                       val['base_amount'] = val['base'] * tax['base_sign']
-                                       val['tax_amount'] = val['amount'] * tax['tax_sign']
-                                       val['account_id'] = tax['account_collected_id'] or line.account_id.id
+                       for tax in tax_obj.compute(cr, uid, line.invoice_line_tax_id, (line.price_unit *(1.0-(line['discount'] or 0.0)/100.0)), line.quantity, inv.address_invoice_id.id, line.product_id, inv.partner_id):
+                               if inv.type in ('out_invoice', 'in_invoice'):
+                                       res[-1]['tax_code_id'] = tax['base_code_id']
+                                       res[-1]['tax_amount'] = tax['price_unit'] * line['quantity'] * tax['base_sign']
                                else:
-                                       val['base_code_id'] = tax['ref_base_code_id']
-                                       val['tax_code_id'] = tax['ref_tax_code_id']
-                                       val['base_amount'] = val['base'] * tax['ref_base_sign']
-                                       val['tax_amount'] = val['amount'] * tax['ref_tax_sign']
-                                       val['account_id'] = tax['account_paid_id'] or line.account_id.id
+                                       res[-1]['ta_code_id'] = tax['ref_base_code_id']
+                                       res[-1]['tax_amount'] = tax['price_unit'] * line['quantity'] * tax['ref_base_sign']
+               return res
 
-                               res[-1]['tax_code_id'] = val['base_code_id']
-                               res[-1]['tax_amount'] = val['base_amount']
+       def product_id_change_unit_price_inv(self, cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context={}):
+               if context.get('price_type', False) == 'tax_included':
+                       return {'price_unit': price_unit,'invoice_line_tax_id': tax_id}
+               else:
+                       return super(account_invoice_line, self).product_id_change_unit_price_inv(cr, uid, tax_id, price_unit, qty, address_invoice_id, product, partner_id, context=context)
 
-                               key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
-                               if not key in tax_grouped:
-                                       tax_grouped[key] = val
-                               else:
-                                       tax_grouped[key]['amount'] += val['amount']
-                                       tax_grouped[key]['base'] += val['base']
-                                       tax_grouped[key]['base_amount'] += val['base_amount']
-                                       tax_grouped[key]['tax_amount'] += val['tax_amount']
-                       res[-1]['price']=cur_obj.round(cr, uid, cur, res[-1]['price'])
-               # delete automatic tax lines for this invoice
-               cr.execute("DELETE FROM account_invoice_tax WHERE NOT manual AND invoice_id=%d", (invoice_id,))
-               for t in tax_grouped.values():
-                       ait_obj.create(cr, uid, t)
-               return res
+       def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, price_unit=False, address_invoice_id=False, price_type='tax_excluded', context={}):
+               context.update({'price_type': price_type})
+               return super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, price_unit, address_invoice_id, context=context)
 account_invoice_line()
index fefed46..43792dc 100644 (file)
                <field name="model">account.invoice</field>
                <field name="inherit_id" ref="account.invoice_form" />
                <field name="arch" type="xml">
-                       <field name="journal_id" position="after">
+                       <field name="invoice_line" position="before">
                                <field name="price_type"/>
                        </field>
                </field>
        </record>
 
+       <record model="ir.ui.view" id="invoice_supplier_form_tax_include">
+               <field name="name">account.invoice.supplier.tax_include</field>
+               <field name="type">form</field>
+               <field name="model">account.invoice</field>
+               <field name="inherit_id" ref="account.invoice_supplier_form" />
+               <field name="arch" type="xml">
+                       <field name="invoice_line" position="before">
+                               <field name="price_type"/>
+                       </field>
+               </field>
+       </record>
+
+       <record model="ir.ui.view" id="invoice_supplier_form_tax_include2">
+               <field name="name">account.invoice.supplier.tax_include2</field>
+               <field name="type">form</field>
+               <field name="model">account.invoice</field>
+               <field name="inherit_id" ref="account.invoice_supplier_form" />
+               <field name="arch" type="xml">
+                       <field name="price_subtotal" position="after">
+                               <field name="price_subtotal_incl"/>
+                       </field>
+               </field>
+       </record>
+
+       <record model="ir.ui.view" id="invoice_supplier_form_tax_include3">
+               <field name="name">account.invoice.supplier.tax_include3</field>
+               <field name="type">form</field>
+               <field name="model">account.invoice</field>
+               <field name="inherit_id" ref="account.invoice_supplier_form" />
+               <field name="arch" type="xml">
+                       <field name="product_id" position="replace">
+                               <field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, price_unit, parent.address_invoice_id, parent.price_type)"/>
+                       </field>
+               </field>
+       </record>
+
        <record model="ir.ui.view" id="view_invoice_line_tree">
                <field name="name">account.invoice.line.tree</field>
                <field name="model">account.invoice.line</field>