2017-09-24 115 views
0

我目前在我的模块中实现了一项功能,该功能从订单行中总计税额。我的模块有一个订单行部分(非常类似于销售模块),它允许添加多个产品并将其价格显示在旁边。看看我如何添加此功能here。在底部,我有一个小计页脚,其中显示三个字段:amount_axaxed,amount_taxamount_total。计税工作正常(存储在amount_tax),但我无法在该页脚中显示税额。下面是相关代码:Odoo 10 - Singleton错误 - 无法获得订单行中特定字段的总和

models.py

# -*- coding: utf-8 -*- 

from odoo import models, fields, api 
from odoo.addons import decimal_precision as dp 

class mymodule(models.Model): 
    _name = 'mymodule.mymodule' 
    _description = 'My Module' 

    currency_id = fields.Many2one('res.currency', string='Currency') 

    operations = fields.One2many('mymodule.line', 'mymodule_id', 'Order Lines') 

    amount_untaxed = fields.Monetary(string='Untaxed Amount', 
           default=0, 
           compute='_compute_untaxed', 
           currency_field='currency_id') 

    amount_tax = fields.Monetary(string='Taxes', 
          default=0, 
          compute='_compute_taxes', 
          currency_field='currency_id') 

    amount_total = fields.Monetary(string='Total', 
           default=0, 
           compute='_compute_total', 
           currency_field='currency_id') 


    # Sum all prices into untaxed total 
    @api.depends('operations.price') 
    def _compute_untaxed(self): 
     for record in self: 
      record.amount_untaxed = sum(line.price for line in record.operations) 

    # Sum all prices into taxed total 
    @api.depends('operations.total') 
    def _compute_total(self): 
     for record in self: 
      record.amount_total = sum(line.total for line in record.operations) 

    # Sum all taxes 
    @api.depends('operations.taxes') 
    def _compute_taxes(self): 
     for record in self: 
      record.amount_tax = sum(line.taxes for line in record.operations) 

class mymodule_line(models.Model): 
    _name = 'mymodule.line' 
    _description = 'Order Line' 

    mymodule_id = fields.Many2one('mymodule.mymodule') 

    product_id = fields.Many2one('product.template', 
           string='Product', 
           required=False) # Product name 

    tax_id = fields.Many2many('account.tax', 
          string='Taxes', 
          store=False) # Product default taxes 

    taxes = fields.Float(string='Taxes', readonly=False) 

    price = fields.Float(string='Price') 

    total = fields.Float(string='Total', readonly=False) 

    # Display default values based on product selected 
    @api.onchange('product_id') 
    def _onchange_product_id(self): 
     self.price = self.product_id.lst_price 
     self.tax_id = self.product_id.taxes_id 

    # Compute total and tax amount for selected product 
    @api.onchange('price', 'tax_id') 
    @api.depends('total', 'tax_id.amount', 'price', 'taxes') 
    def _compute_total(self): 
      self.taxes = (0.01 * self.tax_id.amount * self.price)  
      self.total = self.taxes + self.price 

views.xml

<record id="mymodule.form" model="ir.ui.view"> 
     <field name="name">My Module Form</field> 
     <field name="model">mymodule.mymodule</field> 
     <field name="arch" type="xml"> 
      <form> 
       <sheet> 
        <notebook> 
         <!-- Order Lines --> 
         <page string="Operations"> 
          <group class="oe_subtotal_footer oe_right" colspan="2" name="sale_total"> 
           <field name="amount_untaxed"/> 
           <field name="amount_tax"/> 
           <div class="oe_subtotal_footer_separator oe_inline o_td_label"> 
           </div> 
           <field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator"/> 
          </group> 
         </page> 
        </notebook> 
       </sheet> 
      </form> 
     </field> 
    </record> 

有趣的是,如果我更改以下行正因为如此,添加计算论点,税额将正确显示。

taxes = fields.Float(string='Taxes', readonly=False, compute='_compute_total') 

但是,如果我在订单行中添加多个产品,然后尝试保存该记录,则会出现单例错误。

ValueError: Expected singleton: mymodule.line(346, 347) 

添加@ api.one装饰上面我_compute_total功能则可以让我保存记录,但一旦它被保存计税消失。

这里是我的小计页脚应该是什么样子的参考图像:Subtotal Footer

我感谢您的帮助!

+0

下面的链接将有助于你在未来。 https://odedrabhavesh.blogspot.in/2017/02/valueerror-expected-singleton-in-odoo.html –

回答

2

让我们来看看这是如何Odoo核心在sale module完成,例如:

_name = "sale.order" 

@api.depends('order_line.price_total') 
def _amount_all(self): 
    """ 
    Compute the total amounts of the SO. 
    """ 
    for order in self: 
     amount_untaxed = amount_tax = 0.0 
     for line in order.order_line: 
      amount_untaxed += line.price_subtotal 
      # FORWARDPORT UP TO 10.0 
      if order.company_id.tax_calculation_rounding_method == 'round_globally': 
       price = line.price_unit * (1 - (line.discount or 0.0)/100.0) 
       taxes = line.tax_id.compute_all(price, line.order_id.currency_id, line.product_uom_qty, product=line.product_id, partner=line.order_id.partner_id) 
       amount_tax += sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])) 
      else: 
       amount_tax += line.price_tax 
     order.update({ 
      'amount_untaxed': order.pricelist_id.currency_id.round(amount_untaxed), 
      'amount_tax': order.pricelist_id.currency_id.round(amount_tax), 
      'amount_total': amount_untaxed + amount_tax, 
     }) 

amount_untaxed = fields.Monetary(string='Untaxed Amount', store=True, readonly=True, compute='_amount_all', track_visibility='always') 
amount_tax = fields.Monetary(string='Taxes', store=True, readonly=True, compute='_amount_all', track_visibility='always') 
amount_total = fields.Monetary(string='Total', store=True, readonly=True, compute='_amount_all', track_visibility='always') 

首先,请注意,所有的字段都可以在一个单一的方法来计算,它可以是一个比多次循环相同的记录效率稍高一点。

其次,请注意,字段definitios全部为readonly=True。计算字段默认为readonly,不应手动制作readonly=False这可能是您的字段未按预期显示的原因。

如果您想让计算字段可编辑,您需要为字段设置inverse method。看起来你不希望这个字段是可编辑的,因为它应该在你的每个record.operations上进行管理。


这只是您设置中可能存在缺陷的一个方面。再次,看看销售模块,但这次怎么看待order lines are set up

_name = 'sale.order.line' 

@api.depends('product_uom_qty', 'discount', 'price_unit', 'tax_id') 
def _compute_amount(self): 
    """ 
    Compute the amounts of the SO line. 
    """ 
    for line in self: 
     price = line.price_unit * (1 - (line.discount or 0.0)/100.0) 
     taxes = line.tax_id.compute_all(price, line.order_id.currency_id, line.product_uom_qty, product=line.product_id, partner=line.order_id.partner_id) 
     line.update({ 
      'price_tax': taxes['total_included'] - taxes['total_excluded'], 
      'price_total': taxes['total_included'], 
      'price_subtotal': taxes['total_excluded'], 
     }) 

price_subtotal = fields.Monetary(compute='_compute_amount', string='Subtotal', readonly=True, store=True) 
price_tax = fields.Monetary(compute='_compute_amount', string='Taxes', readonly=True, store=True) 
price_total = fields.Monetary(compute='_compute_amount', string='Total', readonly=True, store=True) 

注意,每个领域都还计算的,而你是通过onchange方法驱动。此外,这些字段为readonly=True(因为默认情况下所有computed字段都是这样的),防止它们被手动更改。


ValueError: Expected singleton: mymodule.line(346, 347)

添加上面我_compute_total功能@ api.one装饰则让我保存记录,但一旦它被保存计税消失。因为它是用来指定你的方法应该只用于计算单个记录(而不是记录)

@api.depends('operations.total') 
def _compute_total(self): 
    for record in self: 

添加@api.one装饰你以上的方法是不合逻辑的。你的方法已经被设置为处理多个记录(for record in self意味着可能会有多个记录),所以如果有的话,你应该使用@api.multi装饰器。


之所以这么说,我会强烈建议重新审视你的模型设计,因为它们是设计时考虑到效率和数据安全性,以反映那些sale模块中使用。

0

我想添加一些travisw的答案没有描述的东西:您将api.changeapi.depends装饰器组合使用。这将解释奇怪的行为,如单身错误,并且不保存附加api.one的记录。

api.onchange只能用于单身人士,我想这就是为什么你用自己写自己的方法,而不是循环自我。 api.depends也可以与单身人士一起工作,但在许多情况下不限制Odoo,它将与一组记录一起使用。

我建议你将你的方法,如:

@api.onchange('price', 'tax_id') 
def onchange_total(self): 
    self._compute_total() 

@api.depends('total', 'tax_id.amount', 'price', 'taxes') 
def compute_total(self): 
    self._compute_total() 

@api.multi 
def _compute_total(self): 
    for line in self: 
     line.taxes = (0.01 * line.tax_id.amount * line.price) 
     line.total = line.taxes + line.price