第一章 销售订单
价格计算
odoo中价格计算有一整套逻辑,尤其是涉及到税的时候,并非我们想象中的单价*数量的结果。
这里需要用到的就是税对象的_compute_all方法:
def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None, is_refund=False, handle_price_include=True):
""" Returns all information required to apply taxes (in self + their children in case of a tax group).
We consider the sequence of the parent for group of taxes.
Eg. considering letters as taxes and alphabetic order as sequence :
[G, B([A, D, F]), E, C] will be computed as [A, D, F, C, E, G]
'handle_price_include' is used when we need to ignore all tax included in price. If False, it means the
amount passed to this method will be considered as the base of all computations.
RETURN: {
'total_excluded': 0.0, # Total without taxes
'total_included': 0.0, # Total with taxes
'total_void' : 0.0, # Total with those taxes, that don't have an account set
'taxes': [{ # One dict for each tax in self and their children
'id': int,
'name': str,
'amount': float,
'sequence': int,
'account_id': int,
'refund_account_id': int,
'analytic': boolean,
}],
} """
以上代码是基于odoo13.0的版本,后续版本可能会有更新。
我们可以看到税对象的compute_all方法不仅会返回税的金额,还会将含税总价、不含税总价等信息一并计算出来。因此我们在使用的时候,就可以直接使用compute_all方法。 该方法接受以下几个参数:
- price_unit: 单价
- currency: 币种,非多币种环境不用填。
- quantity: 数量,默认1
- partner: 业务伙伴
- is_refund: 是否退款
- handle_price_include: 默认False,是否忽略含税价进行计算。
发送邮件
16.0
点击发送邮件按钮会弹出邮件发送向导:
发送按钮的逻辑如下:
def action_quotation_send(self):
""" Opens a wizard to compose an email, with relevant mail template loaded by default """
self.ensure_one()
self.order_line._validate_analytic_distribution()
lang = self.env.context.get('lang')
mail_template = self._find_mail_template()
if mail_template and mail_template.lang:
lang = mail_template._render_lang(self.ids)[self.id]
ctx = {
'default_model': 'sale.order',
'default_res_id': self.id,
'default_use_template': bool(mail_template),
'default_template_id': mail_template.id if mail_template else None,
'default_composition_mode': 'comment',
'mark_so_as_sent': True,
'default_email_layout_xmlid': 'mail.mail_notification_layout_with_responsible_signature',
'proforma': self.env.context.get('proforma', False),
'force_email': True,
'model_description': self.with_context(lang=lang).type_name,
}
return {
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'mail.compose.message',
'views': [(False, 'form')],
'view_id': False,
'target': 'new',
'context': ctx,
}
其中,邮件模板通过_find_mail_template()获取:
def _find_mail_template(self):
self.ensure_one()
if self.env.context.get('proforma') or self.state not in ('sale', 'done'):
return self.env.ref('sale.email_template_edi_sale', raise_if_not_found=False)
else:
return self._get_confirmation_template()
如果上下文中有proforma参数则调用edi邮件模板,否则使用确认订单的邮件模板。
def _get_confirmation_template(self):
return self.env.ref('sale.mail_template_sale_confirmation', raise_if_not_found=False)
确认邮件模板则非常简单,直接使用邮件确认模板发送。
创建发票
从销售订单准备发票数据:
#17.0
def _prepare_invoice(self):
"""
Prepare the dict of values to create the new invoice for a sales order. This method may be
overridden to implement custom invoice generation (making sure to call super() to establish
a clean extension chain).
"""
self.ensure_one()
values = {
'ref': self.client_order_ref or '',
'move_type': 'out_invoice',
'narration': self.note,
'currency_id': self.currency_id.id,
'campaign_id': self.campaign_id.id,
'medium_id': self.medium_id.id,
'source_id': self.source_id.id,
'team_id': self.team_id.id,
'partner_id': self.partner_invoice_id.id,
'partner_shipping_id': self.partner_shipping_id.id,
'fiscal_position_id': (self.fiscal_position_id or self.fiscal_position_id._get_fiscal_position(self.partner_invoice_id)).id,
'invoice_origin': self.name,
'invoice_payment_term_id': self.payment_term_id.id,
'invoice_user_id': self.user_id.id,
'payment_reference': self.reference,
'transaction_ids': [Command.set(self.transaction_ids.ids)],
'company_id': self.company_id.id,
'invoice_line_ids': [],
'user_id': self.user_id.id,
}
if self.journal_id:
values['journal_id'] = self.journal_id.id
return values