-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathtest_sale_invoice_plan.py
More file actions
369 lines (352 loc) · 14.4 KB
/
test_sale_invoice_plan.py
File metadata and controls
369 lines (352 loc) · 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import logging
from odoo import Command, _, fields
from odoo.exceptions import UserError, ValidationError
from odoo.tests import Form, tagged
from odoo.addons.sale.tests import common
_logger = logging.getLogger(__name__)
@tagged("post_install", "-at_install")
class TestSaleInvoicePlan(common.TestSaleCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
context_no_mail = {
"no_reset_password": True,
"mail_create_nosubscribe": True,
"mail_create_nolog": True,
}
# Create base account to simulate a chart of account for payable account
user_type_payable = cls.company_data["default_account_payable"]
cls.account_payable = cls.env["account.account"].create(
{
"code": "NC1110",
"name": "Test Payable Account",
"account_type": user_type_payable.account_type,
"reconcile": True,
}
)
# Create base account to simulate a chart of account for receivable account
cls.account_receivable = cls.env["account.account"].create(
{
"code": "NC1111",
"name": "Test Receivable Account",
"account_type": "asset_receivable",
"reconcile": True,
}
)
Partner = cls.env["res.partner"].with_context(**context_no_mail)
cls.partner_customer_usd = Partner.create(
{
"name": "Customer from the North",
"email": "customer.usd@north.com",
"property_account_payable_id": cls.account_payable.id,
"property_account_receivable_id": cls.account_receivable.id,
}
)
cls.sale_journal0 = cls.env["account.journal"].create(
{
"name": "Sale Journal",
"type": "sale",
"code": "SJT0",
}
)
cls.default_pricelist = cls.env["product.pricelist"].create(
{
"name": "Default Pricelist",
}
)
cls.setUpClassicProducts()
sale_obj = cls.env["sale.order"]
# Create an SO for Service
cls.so_service = sale_obj.with_user(
cls.company_data["default_user_salesman"]
).create(
{
"partner_id": cls.partner_customer_usd.id,
"partner_invoice_id": cls.partner_customer_usd.id,
"partner_shipping_id": cls.partner_customer_usd.id,
"use_invoice_plan": True,
"order_line": [
(
Command.create(
{
"name": cls.product_order.name,
"product_id": cls.product_order.id,
"product_uom_qty": 1,
"product_uom": cls.product_order.uom_id.id,
"price_unit": cls.product_order.list_price,
}
)
)
],
"pricelist_id": cls.default_pricelist.id,
}
)
@classmethod
def setUpClassicProducts(cls):
# Create an expense journal
cls.account_income_product = cls.env["account.account"].create(
{
"code": "4.0.0.0.0",
"name": "Income - Test Account",
"account_type": "income",
}
)
# Create category
cls.product_category = cls.env["product.category"].create(
{
"name": "Product Category with Income account",
"property_account_income_categ_id": cls.account_income_product.id,
}
)
# Products
uom_unit = cls.env.ref("uom.product_uom_unit")
cls.product_order = cls.env["product.product"].create(
{
"name": "Zed+ Antivirus",
"standard_price": 235.0,
"list_price": 280.0,
"type": "consu",
"uom_id": uom_unit.id,
"uom_po_id": uom_unit.id,
"invoice_policy": "order",
"expense_policy": "no",
"default_code": "PROD_ORDER",
"service_type": "manual",
"taxes_id": False,
"categ_id": cls.product_category.id,
}
)
# Advance Product
deposit_account = cls.env["account.account"].search(
[("internal_group", "=", "income"), ("deprecated", "=", False)], limit=1
)
cls.product_advance = cls.env["product.product"].create(
{
"name": _("Down payment"),
"type": "service",
"invoice_policy": "order",
"property_account_income_id": deposit_account.id,
"taxes_id": False,
}
)
cls.env["ir.config_parameter"].sudo().set_param(
"sale.default_deposit_product_id", cls.product_advance.id
)
def test_00_invoice_plan(self):
# To create next invoice from SO
ctx = {
"active_id": self.so_service.id,
"active_ids": [self.so_service.id],
"all_remain_invoices": False,
}
f = Form(self.env["sale.create.invoice.plan"])
try: # UserError if no installment
plan = f.save()
except ValidationError as e:
_logger.info(_("No installment raises following error : %s"), e.args[0])
# Create Invoice Plan 3 installment
num_installment = 5
f.num_installment = num_installment
# Test 3 types of interval
for interval_type in ["month", "year", "day"]:
f.interval_type = interval_type
plan = f.save()
# SO confirmed without invoice plan being created
if not self.so_service.invoice_plan_ids:
with self.assertRaises(UserError):
self.so_service.action_confirm()
# Create Invocie Plan Installment
plan.with_context(**ctx).sale_create_invoice_plan()
self.assertEqual(
len(self.so_service.invoice_plan_ids),
num_installment,
"Wrong number of installment created",
)
self.assertEqual(
self.so_service.invoice_plan_pending,
num_installment,
"Pending invoice plan count mismatch after creation",
)
# Change plan, so that the 1st installment is 1000 and 5th is 3000
self.assertEqual(len(self.so_service.invoice_plan_ids), 5)
self.so_service.invoice_plan_ids[0].amount = 280.0
self.so_service.invoice_plan_ids[4].amount = 840.0
# Confirm the SO
self.so_service.action_confirm()
# Create one invoice
make_wizard = self.env["sale.make.planned.invoice"].create({})
make_wizard.with_context(**ctx).create_invoices_by_plan()
self.assertEqual(
self.so_service.amount_total,
sum(self.so_service.invoice_ids.mapped("amount_total")),
)
self.assertEqual(
self.so_service.invoice_plan_pending,
num_installment - 1,
"Pending invoice plan count mismatch after 1st invoice",
)
invoices = self.so_service.invoice_ids
self.assertEqual(len(invoices), 1, "Only 1 invoice should be created")
def test_01_invoice_plan(self):
# To create all remaining invoice from SO
ctx = {
"active_id": self.so_service.id,
"active_ids": [self.so_service.id],
"advance_payment_method": "delivered",
"all_remain_invoices": True,
}
f = Form(self.env["sale.create.invoice.plan"])
# Create Invoice Plan 3 installment
num_installment = 3
# Test 3 types of interval
for interval_type in ["month", "year", "day"]:
f.interval_type = interval_type
f.num_installment = num_installment
plan = f.save()
plan.with_context(**ctx).sale_create_invoice_plan()
self.assertEqual(
self.so_service.invoice_plan_pending,
num_installment,
"Pending invoice plan count mismatch after creation",
)
# Confirm the SO
self.so_service.action_confirm()
# Create all invoices
make_wizard = self.env["sale.make.planned.invoice"].create({})
make_wizard.with_context(**ctx).create_invoices_by_plan()
# Valid number of invoices plan pending
self.assertEqual(
self.so_service.invoice_plan_pending,
0,
"Pending invoice plan should be 0 after invoicing all",
)
# Valid number of invoices
invoices = self.so_service.invoice_ids
self.assertEqual(
len(invoices), num_installment, "Wrong number of invoice created"
)
# Valid total quantity of invoices
quantity = sum(invoices.mapped("invoice_line_ids").mapped("quantity"))
self.assertEqual(quantity, 1, "Wrong number of total invoice quantity")
def test_02_invoice_plan_with_advance(self):
# To create all remaining invoice from SO
ctx = {
"active_id": self.so_service.id,
"active_ids": [self.so_service.id],
"all_remain_invoices": True,
}
# Create Invoice Plan 3 installment with Advance
num_installment = 3
f = Form(self.env["sale.create.invoice.plan"])
f.num_installment = num_installment
f.advance = True # Advance
plan = f.save()
plan.with_context(**ctx).sale_create_invoice_plan()
self.assertEqual(
len(self.so_service.invoice_plan_ids),
num_installment + 1,
"Wrong number of installment created",
)
self.assertEqual(
self.so_service.invoice_plan_pending,
num_installment + 1,
"Pending invoice plan count mismatch (with advance)",
)
# If advance percent is not filled, show error
with self.assertRaises(ValidationError):
self.so_service.action_confirm()
advance_line = self.so_service.invoice_plan_ids.filtered(
lambda plan: plan.invoice_type == "advance"
)
self.assertEqual(len(advance_line), 1, "No one advance line")
# Add 10% to advance
advance_line.percent = 10
# Can confirm the SO after advance is filled
self.so_service.action_confirm()
# Create all invoice plan
wizard = self.env["sale.make.planned.invoice"].create({})
wizard.with_context(**ctx).create_invoices_by_plan()
# Valid number of invoices plan pending
self.assertEqual(
self.so_service.invoice_plan_pending,
0,
"Pending invoice plan should be 0 after all invoiced (with advance)",
)
# Valid number of invoices, including advance
invoices = self.so_service.invoice_ids
self.assertEqual(
len(invoices), num_installment + 1, "Wrong number of invoice created"
)
# Valid total quantity of invoices (exclude Advance line)
quantity = sum(
invoices.mapped("invoice_line_ids")
.filtered(lambda line: line.product_id == self.product_order)
.mapped("quantity")
)
self.assertEqual(quantity, 1, "Wrong number of total invoice quantity")
def test_03_unlink_invoice_plan(self):
ctx = {"active_id": self.so_service.id}
f = Form(self.env["sale.create.invoice.plan"])
# Create Invoice Plan 3 installment
num_installment = 3
f.num_installment = num_installment
plan = f.save()
plan.with_context(**ctx).sale_create_invoice_plan()
# Remove it
self.so_service.remove_invoice_plan()
self.assertFalse(self.so_service.invoice_plan_ids)
def test_invoice_plan_so_edit(self):
"""Case when some installment already invoiced,
but then, the SO line added. Test to ensure that
the invoiced amount of the done installment is fixed"""
ctx = {
"active_id": self.so_service.id,
"active_ids": [self.so_service.id],
"all_remain_invoices": False,
}
first_order_line = fields.first(self.so_service.order_line)
first_order_line.product_uom_qty = 10
f = Form(self.env["sale.create.invoice.plan"])
# Create Invoice Plan 5 installment
num_installment = 5
f.num_installment = num_installment
plan = f.save()
plan.with_context(**ctx).sale_create_invoice_plan()
# Change plan, so that the 1st installment is 280 and 5th is 840
self.assertEqual(len(self.so_service.invoice_plan_ids), 5)
first_install = self.so_service.invoice_plan_ids[0]
first_install.amount = 280.0
self.so_service.invoice_plan_ids[4].amount = 840.0
self.so_service.action_confirm()
self.assertEqual(self.so_service.state, "sale")
sale_create = self.env["sale.make.planned.invoice"].create({})
# Create only the 1st invoice, amount should be 280, and percent is 10
sale_create.with_context(**ctx).create_invoices_by_plan()
self.assertEqual(first_install.amount, 280.0)
self.assertEqual(first_install.percent, 10)
# Add new SO line with amount = 280, check that only percent is changed
self.so_service.write(
{
"order_line": [
(
Command.create(
{
"name": "SO-Product-NEW",
"product_id": self.product_order.id,
"product_uom_qty": 1,
"product_uom": self.product_order.uom_id.id,
"price_unit": 280.0,
}
)
)
],
}
)
# Overall amount changed to 3080, install amount not
# changed, only percent changed.
self.assertEqual(self.so_service.amount_total, 3080.0)
self.so_service.invoice_plan_ids._compute_amount()
self.assertEqual(first_install.amount, 280.0)
self.assertEqual(first_install.percent, 9.090909)