272 lines
16 KiB
Python
272 lines
16 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
|
|
|
from flectra.addons.account.tests.account_test_classes import AccountingTestCase
|
|
|
|
|
|
class TestSaleOrderInvoicing(AccountingTestCase):
|
|
|
|
def test_sale_to_invoice_and_to_be_invoiced(self):
|
|
""" Testing amount to invoice and amount to be invoiced, with advances. """
|
|
|
|
partner = self.env.ref('base.res_partner_1')
|
|
partner.property_account_receivable_id = self.env['account.account'].search(
|
|
[('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1)
|
|
product_1 = self.env.ref('product.product_product_8')
|
|
product_2 = self.env.ref('product.product_product_11')
|
|
|
|
# In order to test I create sales order and confirmed it.
|
|
order = self.env['sale.order'].create({
|
|
'partner_id': partner.id,
|
|
'partner_invoice_id': partner.id,
|
|
'partner_shipping_id': partner.id,
|
|
'order_line': [
|
|
(0, 0, {
|
|
'name': product_1.name,
|
|
'product_id': product_1.id,
|
|
'product_uom_qty': 2,
|
|
'qty_delivered': 2,
|
|
'product_uom': product_1.uom_id.id,
|
|
'price_unit': 100
|
|
}),
|
|
(0, 0, {
|
|
'name': product_2.name,
|
|
'product_id': product_2.id,
|
|
'product_uom_qty': 2,
|
|
'qty_delivered': 2,
|
|
'product_uom': product_2.uom_id.id,
|
|
'price_unit': 300
|
|
})
|
|
],
|
|
'pricelist_id': self.env.ref('product.list0').id,
|
|
})
|
|
|
|
context = {"active_model": 'sale.order', "active_ids": [order.id], "active_id": order.id}
|
|
order.with_context(context).action_confirm()
|
|
|
|
# Now I create invoice.
|
|
advance_product = self.env.ref('sale.advance_product_0')
|
|
advance_product.property_account_income_id = self.env['account.account'].search(
|
|
[('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1)
|
|
|
|
payment = self.env['sale.advance.payment.inv'].create({
|
|
'advance_payment_method': 'fixed',
|
|
'amount': 500,
|
|
'product_id': advance_product.id,
|
|
})
|
|
payment.with_context(context).create_invoices()
|
|
invoice_1 = order.invoice_ids[0]
|
|
|
|
# Lets create one more invoice.
|
|
|
|
payment = self.env['sale.advance.payment.inv'].create({
|
|
'advance_payment_method': 'fixed',
|
|
'amount': 300,
|
|
'product_id': advance_product.id,
|
|
})
|
|
payment.with_context(context).create_invoices()
|
|
invoice_2 = order.invoice_ids[1]
|
|
|
|
self.assertEqual(sum(order.order_line.mapped('amt_to_invoice')), 800.0, 'Sale: the Amount To Invoice for the sale order should be 800.0.')
|
|
self.assertEqual(sum(order.order_line.mapped('amt_invoiced')), 0.0, 'Sale: the Amount Invoiced for the sale order should be 0.0.')
|
|
|
|
# Now I validate invoice_1.
|
|
invoice_1.invoice_validate()
|
|
|
|
self.assertEqual(sum(order.order_line.mapped('amt_to_invoice')), 300.0, 'Sale: the Amount To Invoice for the sale order should be 300.0.')
|
|
self.assertEqual(sum(order.order_line.mapped('amt_invoiced')), 500.0, 'Sale: the Amount Invoiced for the sale order should be 500.0.')
|
|
|
|
# Now I validate invoice_2.
|
|
invoice_2.invoice_validate()
|
|
|
|
self.assertEqual(sum(order.order_line.mapped('amt_to_invoice')), 0.0, 'Sale: the Amount To Invoice for the sale order should be 0.0.')
|
|
self.assertEqual(sum(order.order_line.mapped('amt_invoiced')), 800.0, 'Sale: the Amount Invoiced for the sale order should be 800.0.')
|
|
|
|
# Lets create a refund invoice for invoice_1.
|
|
# I refund the invoice Using Refund Button.
|
|
context = {"active_model": 'account.invoice', "active_ids": [invoice_1.id], "active_id": invoice_1.id}
|
|
account_invoice_refund_1 = self.env['account.invoice.refund'].with_context(context).create(dict(
|
|
description='Refund for Invoice 1',
|
|
filter_refund='refund'
|
|
))
|
|
|
|
# I clicked on refund button.
|
|
account_invoice_refund_1.with_context(context).invoice_refund()
|
|
invoice_1.refund_invoice_ids and invoice_1.refund_invoice_ids[0].invoice_validate()
|
|
|
|
self.assertEqual(sum(order.order_line.mapped('amt_to_invoice')), 0.0, 'Sale: the Amount To Invoice for the sale order should be 0.0.')
|
|
self.assertEqual(sum(order.order_line.mapped('amt_invoiced')), 300.0, 'Sale: the Amount Invoiced for the sale order should be 300.0.')
|
|
|
|
# Lets create a refund invoice for invoice_2.
|
|
# I refund the invoice Using Refund Button.
|
|
context = {"active_model": 'account.invoice', "active_ids": [invoice_2.id], "active_id": invoice_2.id}
|
|
account_invoice_refund_2 = self.env['account.invoice.refund'].with_context(context).create(dict(
|
|
description='Refund for Invoice 2',
|
|
filter_refund='refund'
|
|
))
|
|
|
|
# I clicked on refund button.
|
|
account_invoice_refund_2.with_context(context).invoice_refund()
|
|
invoice_2.refund_invoice_ids and invoice_2.refund_invoice_ids[0].invoice_validate()
|
|
|
|
self.assertEqual(sum(order.order_line.mapped('amt_to_invoice')), 0.0, 'Sale: the Amount To Invoice for the sale order should be 0.0.')
|
|
self.assertEqual(sum(order.order_line.mapped('amt_invoiced')), 0.0, 'Sale: the Amount Invoiced for the sale order should be 0.0.')
|
|
|
|
def test_amount_delivered_and_ordered_qty(self):
|
|
""" Testing amount to invoice and amount to be invoiced, with different invoice policy and cancelling SO """
|
|
# disable mail feature to speed test
|
|
context_no_mail = {
|
|
'tracking_disable': True,
|
|
'mail_notrack': True,
|
|
'mail_create_nolog': True,
|
|
}
|
|
|
|
# create products and partner
|
|
Product = self.env['product.product'].with_context(context_no_mail)
|
|
product_order = Product.create({
|
|
'name': "Service Ordered",
|
|
'standard_price': 10,
|
|
'list_price': 20,
|
|
'type': 'service',
|
|
'invoice_policy': 'order',
|
|
'default_code': 'SERV-ORDERED1',
|
|
'taxes_id': False, # force no tax
|
|
})
|
|
product_deli = Product.create({
|
|
'name': 'iMac',
|
|
'standard_price': 400,
|
|
'list_price': 500,
|
|
'type': 'consu',
|
|
'invoice_policy': 'delivery',
|
|
'default_code': 'E-COM09',
|
|
'taxes_id': False, # force no tax
|
|
})
|
|
|
|
partner = self.env.ref('base.res_partner_1')
|
|
partner.property_account_receivable_id = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1)
|
|
|
|
# create Sales order, with 2 lines: one delivered, one ordered
|
|
order = self.env['sale.order'].with_context(context_no_mail).create({
|
|
'partner_id': partner.id,
|
|
'partner_invoice_id': partner.id,
|
|
'partner_shipping_id': partner.id,
|
|
'pricelist_id': self.env.ref('product.list0').id,
|
|
})
|
|
sale_line_ord = self.env['sale.order.line'].with_context(context_no_mail).create({
|
|
'order_id': order.id,
|
|
'name': product_order.name,
|
|
'product_id': product_order.id,
|
|
'product_uom_qty': 2,
|
|
'qty_delivered': 0,
|
|
'product_uom': product_order.uom_id.id,
|
|
'price_unit': 20
|
|
})
|
|
sale_line_deli = self.env['sale.order.line'].with_context(context_no_mail).create({
|
|
'order_id': order.id,
|
|
'name': product_deli.name,
|
|
'product_id': product_deli.id,
|
|
'product_uom_qty': 2,
|
|
'qty_delivered': 0,
|
|
'product_uom': product_deli.uom_id.id,
|
|
'price_unit': 500
|
|
})
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered qty SO line should zero, since its state is draft')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 0.0, 'Amount invoiced for delivered qty SO line should zero, since its state is draft, and there is no invoice at this moment')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered qty SO line should zero, since its state is draft')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 0.0, 'Amount invoiced for ordered qty SO line should zero, since its state is draft, and there is no invoice at this moment')
|
|
|
|
# confirm SO
|
|
order.action_confirm()
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered SO line is still zero, since its delivered quantity is zero')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 0.0, 'Amount invoiced for delivered SO line is still zero, since its delivered quantity is zero, and there is no invoice at this moment')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 40.0, 'Amount to invoice for ordered SO line should be 40, even if there is no invoice')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 0.0, 'Amount invoiced for ordered SO line should zero, there is no invoice at this moment')
|
|
|
|
# create invoice for delivered product
|
|
invoice_context = {"active_model": 'sale.order', "active_ids": [order.id], "active_id": order.id}
|
|
payment = self.env['sale.advance.payment.inv'].with_context(context_no_mail).create({
|
|
'advance_payment_method': 'delivered',
|
|
})
|
|
payment.with_context(invoice_context).create_invoices()
|
|
invoice_1 = order.invoice_ids[0]
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered SO line is still zero, since its delivered quantity (on SO line) is zero')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 0.0, 'Amount invoiced for delivered SO line is still zero, since its delivered quantity (on SO line) is zero, and there is no invoice at this moment')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 40.0, 'Amount to invoice for ordered SO line should be 40, since there is a draft invoice')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 0.0, 'Amount invoiced for ordered SO line should zero, there is no validated invoice at this moment')
|
|
|
|
# validate invoice
|
|
invoice_1.invoice_validate()
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered SO line is still zero, since its delivered quantity (on SO line) is zero')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 0.0, 'Amount invoiced for delivered SO line is still zero, since its delivered quantity (on SO line) is zero, and there is no invoice at this moment')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|
|
|
|
# deliver 2 unit of product_deli
|
|
sale_line_deli.write({'qty_delivered': 2})
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 1000.0, 'Amount to invoice for delivered SO line is now 1000, since its delivered quantity (on SO line) is 2 (unit price = 500)')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 0.0, 'Amount invoiced for delivered SO line is still zero, since there is no invoice at this moment for this product')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|
|
|
|
# create second invoice and validate it
|
|
payment = self.env['sale.advance.payment.inv'].with_context(context_no_mail).create({
|
|
'advance_payment_method': 'delivered',
|
|
})
|
|
payment.with_context(invoice_context).create_invoices()
|
|
invoice_2 = order.invoice_ids.sorted(key='id')[1]
|
|
invoice_2.invoice_validate()
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered SO line is 0, since this is all invoiced')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 1000.0, 'Amount invoiced for delivered SO line is now 1000, since the invoice for this product is validated')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|
|
|
|
# deliver 1 more unit of product_deli
|
|
sale_line_deli.write({'qty_delivered': sale_line_deli.qty_delivered+1})
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 500.0, 'Amount to invoice for delivered SO line is now 500, since we got a uninvoiced unit')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 1000.0, 'Amount invoiced for delivered SO line is still 1000, even the delivered qty change')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|
|
|
|
# create third invoice
|
|
payment = self.env['sale.advance.payment.inv'].with_context(context_no_mail).create({
|
|
'advance_payment_method': 'delivered',
|
|
})
|
|
payment.with_context(invoice_context, open_invoices=True).create_invoices()
|
|
invoice_3 = order.invoice_ids.sorted(key='id')[2]
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 500.0, 'Amount to invoice for delivered SO line is now 500, since we got a uninvoiced unit')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 1000.0, 'Amount invoiced for delivered SO line is still 1000')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|
|
|
|
# cancel order
|
|
order.action_cancel()
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered SO line is now 0, since SO is cancel')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 1000.0, 'Amount invoiced for delivered SO line is still 1000, even if the SO is cancelled')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|
|
|
|
# change the unit price on 3rd invoice
|
|
invoice_3.invoice_line_ids.write({'price_unit': 300})
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered SO line is now 0: nothing should change as the invoice is in draft state')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 1000.0, 'Amount invoiced for delivered SO line is still 1000, even if we change price of unvalidated invoice')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|
|
|
|
# validate third invoice
|
|
invoice_3.invoice_validate()
|
|
|
|
self.assertEqual(sale_line_deli.amt_to_invoice, 0.0, 'Amount to invoice for delivered SO line is now 0, since SO is cancel')
|
|
self.assertEqual(sale_line_deli.amt_invoiced, 1300.0, 'Amount invoiced for delivered SO line is incremented, since the 3rd invoice for this product is validated')
|
|
self.assertEqual(sale_line_ord.amt_to_invoice, 0.0, 'Amount to invoice for ordered SO line is zero, since the invoice is validated')
|
|
self.assertEqual(sale_line_ord.amt_invoiced, 40.0, 'Amount invoiced for ordered SO line should 40, there is a validated invoice at this moment')
|