odoo-addon-l10n-it-riba-oca 18.0.1.0.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. odoo/addons/l10n_it_riba_oca/README.rst +175 -0
  2. odoo/addons/l10n_it_riba_oca/__init__.py +9 -0
  3. odoo/addons/l10n_it_riba_oca/__manifest__.py +59 -0
  4. odoo/addons/l10n_it_riba_oca/data/riba_sequence.xml +14 -0
  5. odoo/addons/l10n_it_riba_oca/demo/riba_demo.xml +39 -0
  6. odoo/addons/l10n_it_riba_oca/hooks.py +17 -0
  7. odoo/addons/l10n_it_riba_oca/i18n/it.po +1686 -0
  8. odoo/addons/l10n_it_riba_oca/i18n/l10n_it_riba.pot +1573 -0
  9. odoo/addons/l10n_it_riba_oca/i18n/l10n_it_riba_oca.pot +1554 -0
  10. odoo/addons/l10n_it_riba_oca/migrations/18.0.1.0.0/pre-migrate.py +16 -0
  11. odoo/addons/l10n_it_riba_oca/models/__init__.py +14 -0
  12. odoo/addons/l10n_it_riba_oca/models/account.py +563 -0
  13. odoo/addons/l10n_it_riba_oca/models/account_config.py +35 -0
  14. odoo/addons/l10n_it_riba_oca/models/ir_ui_menu.py +27 -0
  15. odoo/addons/l10n_it_riba_oca/models/partner.py +35 -0
  16. odoo/addons/l10n_it_riba_oca/models/riba.py +560 -0
  17. odoo/addons/l10n_it_riba_oca/models/riba_config.py +120 -0
  18. odoo/addons/l10n_it_riba_oca/readme/CONFIGURE.md +33 -0
  19. odoo/addons/l10n_it_riba_oca/readme/CONTRIBUTORS.md +17 -0
  20. odoo/addons/l10n_it_riba_oca/readme/DESCRIPTION.md +3 -0
  21. odoo/addons/l10n_it_riba_oca/readme/USAGE.md +35 -0
  22. odoo/addons/l10n_it_riba_oca/report/__init__.py +4 -0
  23. odoo/addons/l10n_it_riba_oca/report/report.xml +16 -0
  24. odoo/addons/l10n_it_riba_oca/report/slip_qweb.py +18 -0
  25. odoo/addons/l10n_it_riba_oca/security/ir.model.access.csv +23 -0
  26. odoo/addons/l10n_it_riba_oca/security/riba_security.xml +34 -0
  27. odoo/addons/l10n_it_riba_oca/static/description/icon.png +0 -0
  28. odoo/addons/l10n_it_riba_oca/static/description/index.html +512 -0
  29. odoo/addons/l10n_it_riba_oca/tests/__init__.py +10 -0
  30. odoo/addons/l10n_it_riba_oca/tests/riba_common.py +339 -0
  31. odoo/addons/l10n_it_riba_oca/tests/test_account_move.py +54 -0
  32. odoo/addons/l10n_it_riba_oca/tests/test_menu.py +51 -0
  33. odoo/addons/l10n_it_riba_oca/tests/test_riba.py +905 -0
  34. odoo/addons/l10n_it_riba_oca/views/account_config_view.xml +46 -0
  35. odoo/addons/l10n_it_riba_oca/views/account_view.xml +205 -0
  36. odoo/addons/l10n_it_riba_oca/views/configuration_view.xml +94 -0
  37. odoo/addons/l10n_it_riba_oca/views/partner_view.xml +29 -0
  38. odoo/addons/l10n_it_riba_oca/views/riba_detail_view.xml +97 -0
  39. odoo/addons/l10n_it_riba_oca/views/riba_view.xml +296 -0
  40. odoo/addons/l10n_it_riba_oca/views/slip_report.xml +149 -0
  41. odoo/addons/l10n_it_riba_oca/views/wizard_credit.xml +46 -0
  42. odoo/addons/l10n_it_riba_oca/views/wizard_due_date_settlement.xml +37 -0
  43. odoo/addons/l10n_it_riba_oca/views/wizard_past_due.xml +67 -0
  44. odoo/addons/l10n_it_riba_oca/views/wizard_presentation.xml +48 -0
  45. odoo/addons/l10n_it_riba_oca/views/wizard_riba_file_export.xml +33 -0
  46. odoo/addons/l10n_it_riba_oca/views/wizard_riba_issue.xml +46 -0
  47. odoo/addons/l10n_it_riba_oca/views/wizard_riba_payment_date.xml +45 -0
  48. odoo/addons/l10n_it_riba_oca/wizard/__init__.py +16 -0
  49. odoo/addons/l10n_it_riba_oca/wizard/wizard_credit.py +280 -0
  50. odoo/addons/l10n_it_riba_oca/wizard/wizard_due_date_settlement.py +24 -0
  51. odoo/addons/l10n_it_riba_oca/wizard/wizard_past_due.py +319 -0
  52. odoo/addons/l10n_it_riba_oca/wizard/wizard_presentation_riba.py +47 -0
  53. odoo/addons/l10n_it_riba_oca/wizard/wizard_riba_file_export.py +429 -0
  54. odoo/addons/l10n_it_riba_oca/wizard/wizard_riba_issue.py +143 -0
  55. odoo/addons/l10n_it_riba_oca/wizard/wizard_riba_multiple_payment.py +107 -0
  56. odoo/addons/l10n_it_riba_oca/wizard/wizard_riba_multiple_payment_views.xml +46 -0
  57. odoo/addons/l10n_it_riba_oca/wizard/wizard_riba_payment_date.py +31 -0
  58. odoo_addon_l10n_it_riba_oca-18.0.1.0.0.8.dist-info/METADATA +197 -0
  59. odoo_addon_l10n_it_riba_oca-18.0.1.0.0.8.dist-info/RECORD +61 -0
  60. odoo_addon_l10n_it_riba_oca-18.0.1.0.0.8.dist-info/WHEEL +5 -0
  61. odoo_addon_l10n_it_riba_oca-18.0.1.0.0.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,905 @@
1
+ # Author: Andrea Gallina
2
+ # © 2015 Apulia Software srl
3
+ # Copyright (C) 2017 Lorenzo Battistini - Agile Business Group
4
+ # Copyright 2023 Simone Rubino - Aion Tech
5
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
6
+
7
+ import base64
8
+ import datetime
9
+ import os
10
+
11
+ from odoo import Command
12
+ from odoo.exceptions import UserError
13
+ from odoo.fields import first
14
+ from odoo.tests import Form
15
+ from odoo.tools import config, safe_eval
16
+
17
+ from . import riba_common
18
+
19
+
20
+ class TestInvoiceDueCost(riba_common.TestRibaCommon):
21
+ def test_add_due_cost(self):
22
+ # ---- Set Service in Company Config
23
+ self.invoice.company_id.due_cost_service_id = self.service_due_cost.id
24
+ # ---- Validate Invoice
25
+ self.invoice.action_post()
26
+ # ---- Test Invoice has 2 line
27
+ self.assertEqual(len(self.invoice.invoice_line_ids), 3)
28
+ # ---- Test Invoice Line for service cost
29
+ self.assertEqual(
30
+ self.invoice.invoice_line_ids[1].product_id.id, self.service_due_cost.id
31
+ )
32
+ # ---- Test Invoice Line for service cost
33
+ self.assertEqual(
34
+ self.invoice.invoice_line_ids[2].product_id.id, self.service_due_cost.id
35
+ )
36
+ # ---- Test Cost line is equal to 10.00
37
+ self.assertEqual(
38
+ (
39
+ self.invoice.invoice_line_ids[1].price_unit
40
+ + self.invoice.invoice_line_ids[2].price_unit
41
+ ),
42
+ 10.00,
43
+ )
44
+ new_inv = self.invoice.copy()
45
+ self.assertEqual(len(new_inv.invoice_line_ids), 1)
46
+
47
+ def test_not_add_due_cost(self):
48
+ # create 2 invoice for partner in same month on the second one no
49
+ # collection fees line expected
50
+ # ---- Set Service in Company Config
51
+ self.invoice.company_id.due_cost_service_id = self.service_due_cost.id
52
+ # ---- Validate Invoice
53
+ self.invoice.action_post()
54
+
55
+ self.invoice2.invoice_payment_term_id = self.payment_term2
56
+ self.invoice2.action_post()
57
+ # ---- Test Invoice has 1 line, no collection fees added because it's added on
58
+ # ---- first due date for partner
59
+ self.assertEqual(len(self.invoice2.invoice_line_ids), 1)
60
+
61
+ def test_delete_due_cost_line(self):
62
+ # ---- Set Service in Company Config
63
+ self.invoice.company_id.due_cost_service_id = self.service_due_cost.id
64
+ # ---- Validate Invoice
65
+ self.invoice.action_post()
66
+ # ---- Cancel Invoice
67
+ self.invoice.button_cancel()
68
+ self.invoice.button_draft()
69
+ # ---- Set to Draft
70
+ # Collection fees line has been unlink
71
+ self.assertEqual(len(self.invoice.invoice_line_ids), 1)
72
+
73
+ def riba_sbf_common(self):
74
+ invoice = self._create_sbf_invoice()
75
+ invoice._onchange_riba_partner_bank_id()
76
+ invoice.action_post()
77
+ riba_move_line_id = False
78
+ for move_line in invoice.line_ids:
79
+ if move_line.account_id.id == self.account_rec1_id.id:
80
+ riba_move_line_id = move_line.id
81
+ line_ids = self.move_line_model.search(
82
+ [
83
+ "&",
84
+ "|",
85
+ ("riba", "=", "True"),
86
+ ("past_due_invoice_ids", "!=", False),
87
+ ("account_type", "=", "asset_receivable"),
88
+ ("reconciled", "=", False),
89
+ ("slip_line_ids", "=", False),
90
+ ("move_id", "=", invoice.id),
91
+ ]
92
+ )
93
+ self.assertEqual(len(line_ids), 1)
94
+ self.assertEqual(line_ids[0].id, move_line.id)
95
+ self.assertTrue(riba_move_line_id)
96
+
97
+ # issue wizard
98
+ wizard_riba_issue = self.env["riba.issue"].create(
99
+ {"configuration_id": self.riba_config_sbf.id}
100
+ )
101
+ action = wizard_riba_issue.with_context(
102
+ active_ids=[riba_move_line_id]
103
+ ).create_list()
104
+ riba_list_id = action and action["res_id"] or False
105
+ riba_list = self.slip_model.browse(riba_list_id)
106
+ riba_list.confirm()
107
+ self.assertEqual(riba_list.state, "accepted")
108
+ self.assertEqual(invoice.state, "posted")
109
+
110
+ # Se la compute non viene invocata il test fallisce
111
+ riba_list._compute_acceptance_move_ids()
112
+ self.assertEqual(len(riba_list.acceptance_move_ids), 1)
113
+ # Check that no payments exist yet
114
+ self.assertEqual(len(riba_list.payment_ids), 0)
115
+
116
+ # I print the RiBa slip report
117
+ docargs = {
118
+ "doc_ids": riba_list.ids,
119
+ "doc_model": "riba.slip",
120
+ "docs": self.env["riba.slip"].browse(riba_list.ids),
121
+ }
122
+ data = self.env["ir.qweb"]._render("l10n_it_riba_oca.slip_qweb", docargs)
123
+ if config.get("test_report_directory"):
124
+ open(
125
+ os.path.join(config["test_report_directory"], "riba-list." + format),
126
+ "wb+",
127
+ ).write(data)
128
+
129
+ # credit wizard
130
+ credit_wizard = (
131
+ self.env["riba.credit"]
132
+ .with_context(
133
+ active_model="riba.slip",
134
+ active_ids=[riba_list_id],
135
+ active_id=riba_list_id,
136
+ )
137
+ .create(
138
+ {
139
+ "credit_amount": 450,
140
+ "expense_amount": 5,
141
+ }
142
+ )
143
+ )
144
+ res = credit_wizard.create_move()
145
+ credit_move_id = self.env["account.move"].browse(res["res_id"])
146
+ credit_move_id.action_post()
147
+ self.assertEqual(riba_list.state, "credited")
148
+
149
+ # Test that credit_move_id is properly set on riba lines
150
+ for line in riba_list.line_ids:
151
+ self.assertEqual(line.credit_move_id, riba_list.credit_move_id)
152
+ self.assertTrue(
153
+ line.credit_move_id, "RiBa line should have credit_move_id set"
154
+ )
155
+
156
+ return invoice, riba_list
157
+
158
+ def test_riba_sbf_flow(self):
159
+ invoice, riba_list = self.riba_sbf_common()
160
+
161
+ # past due wizard
162
+ past_due_wizard = (
163
+ self.env["riba.past_due"]
164
+ .with_context(
165
+ active_model="riba.slip.line",
166
+ active_ids=[riba_list.line_ids[0].id],
167
+ active_id=riba_list.line_ids[0].id,
168
+ )
169
+ .create(
170
+ {
171
+ "past_due_fee_amount": 5,
172
+ }
173
+ )
174
+ )
175
+ past_due_wizard.create_move()
176
+ self.assertEqual(riba_list.state, "past_due")
177
+ self.assertEqual(len(riba_list.line_ids), 1)
178
+ self.assertEqual(riba_list.line_ids[0].state, "past_due")
179
+ self.assertTrue(invoice.past_due_move_line_ids)
180
+
181
+ # Se la compute non viene invocata il test fallisce
182
+ riba_list._compute_past_due_move_ids()
183
+ self.assertEqual(len(riba_list.past_due_move_ids), 1)
184
+ bank_past_due_line = False
185
+ for past_due_line in riba_list.past_due_move_ids[0].line_ids:
186
+ if past_due_line.account_id.id == self.past_due_account.id:
187
+ bank_past_due_line = past_due_line
188
+ break
189
+ self.assertTrue(bank_past_due_line)
190
+
191
+ def test_riba_incasso_all_paid(self):
192
+ """
193
+ RiBa of type 'After Collection' all paid flow
194
+ """
195
+ self.invoice.company_id.due_cost_service_id = self.service_due_cost
196
+ self.invoice.action_post()
197
+ self.assertEqual(self.invoice.state, "posted")
198
+
199
+ to_issue_action = self.env.ref("l10n_it_riba_oca.action_riba_to_issue")
200
+ to_issue_model = self.env[to_issue_action.res_model]
201
+ to_issue_domain = safe_eval.safe_eval(to_issue_action.domain)
202
+ to_issue_records = (
203
+ to_issue_model.search(to_issue_domain) & self.invoice.line_ids
204
+ )
205
+ self.assertTrue(to_issue_records)
206
+
207
+ issue_wizard_context = {
208
+ "active_model": to_issue_records._name,
209
+ "active_ids": to_issue_records.ids,
210
+ }
211
+ issue_wizard_model = self.env["riba.issue"].with_context(**issue_wizard_context)
212
+ issue_wizard_form = Form(issue_wizard_model)
213
+ issue_wizard_form.configuration_id = self.riba_config_incasso
214
+ issue_wizard = issue_wizard_form.save()
215
+ issue_result = issue_wizard.create_list()
216
+
217
+ riba_list_id = issue_result["res_id"]
218
+ riba_list_model = issue_result["res_model"]
219
+ riba_list = self.env[riba_list_model].browse(riba_list_id)
220
+ riba_list.confirm()
221
+
222
+ self.assertEqual(riba_list.state, "accepted")
223
+ self.assertEqual(self.invoice.state, "posted")
224
+
225
+ # invoice should be paid
226
+ self.assertEqual(self.invoice.payment_state, "paid")
227
+
228
+ # Action: Pay the RiBa
229
+ payment_wizard_action = riba_list.settle_all_line()
230
+ payment_wizard_form = Form(
231
+ self.env[payment_wizard_action["res_model"]].with_context(
232
+ **payment_wizard_action["context"]
233
+ )
234
+ )
235
+ # payment_wizard_form.payment_date = datetime.date.today()
236
+ payment_wizard = payment_wizard_form.save()
237
+ payment_wizard.pay()
238
+
239
+ # Assert
240
+ self.assertEqual(riba_list.state, "paid")
241
+ # invoice should be partial paid
242
+ self.assertEqual(self.invoice.payment_state, "paid")
243
+
244
+ def test_riba_incasso_past_due(self):
245
+ """
246
+ RiBa of type 'After Collection' past due flow
247
+ """
248
+ self.invoice.company_id.due_cost_service_id = self.service_due_cost
249
+ self.invoice.action_post()
250
+ self.assertEqual(self.invoice.state, "posted")
251
+
252
+ to_issue_action = self.env.ref("l10n_it_riba_oca.action_riba_to_issue")
253
+ to_issue_model = self.env[to_issue_action.res_model]
254
+ to_issue_domain = safe_eval.safe_eval(to_issue_action.domain)
255
+ to_issue_records = (
256
+ to_issue_model.search(to_issue_domain) & self.invoice.line_ids
257
+ )
258
+ self.assertTrue(to_issue_records)
259
+
260
+ issue_wizard_context = {
261
+ "active_model": to_issue_records._name,
262
+ "active_ids": to_issue_records.ids,
263
+ }
264
+ issue_wizard_model = self.env["riba.issue"].with_context(**issue_wizard_context)
265
+ issue_wizard_form = Form(issue_wizard_model)
266
+ issue_wizard_form.configuration_id = self.riba_config_incasso
267
+ issue_wizard = issue_wizard_form.save()
268
+ issue_result = issue_wizard.create_list()
269
+
270
+ riba_list_id = issue_result["res_id"]
271
+ riba_list_model = issue_result["res_model"]
272
+ riba_list = self.env[riba_list_model].browse(riba_list_id)
273
+ riba_list.confirm()
274
+
275
+ self.assertEqual(riba_list.state, "accepted")
276
+ self.assertEqual(self.invoice.state, "posted")
277
+
278
+ # invoice should be paid
279
+ self.assertEqual(self.invoice.payment_state, "paid")
280
+
281
+ # past due wizard
282
+ past_due_wizard = (
283
+ self.env["riba.past_due"]
284
+ .with_context(
285
+ active_model="riba.slip.line",
286
+ active_ids=[riba_list.line_ids[0].id],
287
+ active_id=riba_list.line_ids[0].id,
288
+ )
289
+ .create({})
290
+ )
291
+ past_due_wizard.create_move()
292
+ self.assertEqual(riba_list.state, "past_due")
293
+ self.assertEqual(len(riba_list.line_ids), 2)
294
+ self.assertEqual(riba_list.line_ids[0].state, "past_due")
295
+ self.assertTrue(self.invoice.past_due_move_line_ids)
296
+ # invoice should be partial paid
297
+ self.assertEqual(self.invoice.payment_state, "partial")
298
+
299
+ def test_past_due_riba(self):
300
+ """
301
+ RiBa of type 'sbf' past due flow
302
+ """
303
+ self.partner.property_account_receivable_id = self.account_rec1_id.id
304
+ recent_date = (
305
+ self.env["account.move"]
306
+ .search([("invoice_date", "!=", False)], order="invoice_date desc", limit=1)
307
+ .invoice_date
308
+ )
309
+ invoice = self.env["account.move"].create(
310
+ {
311
+ "invoice_date": recent_date,
312
+ "move_type": "out_invoice",
313
+ "journal_id": self.sale_journal.id,
314
+ "partner_id": self.partner.id,
315
+ "invoice_payment_term_id": self.account_payment_term_riba.id,
316
+ "invoice_line_ids": [
317
+ (
318
+ 0,
319
+ 0,
320
+ {
321
+ "name": "product1",
322
+ "product_id": self.product1.id,
323
+ "quantity": 1.0,
324
+ "price_unit": 100.00,
325
+ "account_id": self.sale_account.id,
326
+ "tax_ids": [[6, 0, []]],
327
+ },
328
+ )
329
+ ],
330
+ }
331
+ )
332
+ invoice._onchange_riba_partner_bank_id()
333
+ invoice.action_post()
334
+ for move_line in invoice.line_ids:
335
+ if move_line.account_id.id == self.account_rec1_id.id:
336
+ riba_move_line_id = move_line.id
337
+ # issue wizard
338
+ wizard_riba_issue = self.env["riba.issue"].create(
339
+ {"configuration_id": self.riba_config_sbf.id}
340
+ )
341
+ action = wizard_riba_issue.with_context(
342
+ active_ids=[riba_move_line_id]
343
+ ).create_list()
344
+ riba_list_id = action and action["res_id"] or False
345
+ riba_list = self.slip_model.browse(riba_list_id)
346
+ riba_list.confirm()
347
+ self.assertEqual(riba_list.state, "accepted")
348
+ self.assertEqual(invoice.state, "posted")
349
+ # credit wizard
350
+ credit_wizard = (
351
+ self.env["riba.credit"]
352
+ .with_context(
353
+ active_model="riba.slip",
354
+ active_ids=[riba_list_id],
355
+ active_id=riba_list_id,
356
+ )
357
+ .create(
358
+ {
359
+ "credit_amount": 100,
360
+ "expense_amount": 5,
361
+ }
362
+ )
363
+ )
364
+
365
+ res = credit_wizard.create_move()
366
+ credit_move_id = self.env["account.move"].browse(res["res_id"])
367
+ credit_move_id.action_post()
368
+ self.assertEqual(riba_list.state, "credited")
369
+
370
+ # pay wizard with skip
371
+ payment_wizard = (
372
+ self.env["riba.payment.multiple"]
373
+ .with_context(
374
+ active_model="riba.slip",
375
+ active_ids=[riba_list_id],
376
+ active_id=riba_list_id,
377
+ )
378
+ .create({})
379
+ )
380
+ payment_wizard.skip()
381
+ self.assertEqual(riba_list.state, "paid")
382
+ self.assertEqual(riba_list.line_ids[0].state, "paid")
383
+
384
+ # past due wizard
385
+ past_due_wizard = (
386
+ self.env["riba.past_due"]
387
+ .with_context(
388
+ active_model="riba.slip.line",
389
+ active_ids=[riba_list.line_ids[0].id],
390
+ active_id=riba_list.line_ids[0].id,
391
+ )
392
+ .create(
393
+ {
394
+ "overdue_credit_amount": 100,
395
+ "past_due_fee_amount": 2,
396
+ }
397
+ )
398
+ )
399
+ past_due_wizard.create_move()
400
+ self.assertEqual(riba_list.state, "past_due")
401
+ self.assertEqual(len(riba_list.line_ids), 1)
402
+ self.assertEqual(riba_list.line_ids[0].state, "past_due")
403
+ self.assertTrue(invoice.past_due_move_line_ids)
404
+
405
+ # Se la compute non viene invocata il test fallisce
406
+ riba_list._compute_past_due_move_ids()
407
+ self.assertEqual(len(riba_list.past_due_move_ids), 1)
408
+ bank_past_due_line = False
409
+ for past_due_line in riba_list.past_due_move_ids[0].line_ids:
410
+ if past_due_line.account_id.id == self.riba_account.id:
411
+ bank_past_due_line = past_due_line
412
+ break
413
+ self.assertTrue(bank_past_due_line)
414
+
415
+ # register the bank statement with the bank credit
416
+ # st = self.env['account.bank.statement'].create({
417
+ # 'journal_id': self.bank_journal.id,
418
+ # 'name': 'bank statement',
419
+ # 'line_ids': [(0, 0, {
420
+ # 'name': 'RiBa',
421
+ # 'amount': -102,
422
+ # })]
423
+ # })
424
+ # must be possible to close the bank statement line with the
425
+ # past due journal item generated by RiBa
426
+ # move_lines_for_rec=st.line_ids[0].get_move_lines_for_reconciliation()
427
+ # self.assertTrue(
428
+ # bank_past_due_line.id in [l.id for l in move_lines_for_rec])
429
+
430
+ def test_riba_fatturapa(self):
431
+ self.partner.property_account_receivable_id = self.account_rec1_id.id
432
+ recent_date = (
433
+ self.env["account.move"]
434
+ .search([("invoice_date", "!=", False)], order="invoice_date desc", limit=1)
435
+ .invoice_date
436
+ )
437
+ invoice = self.env["account.move"].create(
438
+ {
439
+ "invoice_date": recent_date,
440
+ "move_type": "out_invoice",
441
+ "journal_id": self.sale_journal.id,
442
+ "partner_id": self.partner.id,
443
+ "invoice_payment_term_id": self.account_payment_term_riba.id,
444
+ "invoice_line_ids": [
445
+ (
446
+ 0,
447
+ 0,
448
+ {
449
+ "name": "product1",
450
+ "product_id": self.product1.id,
451
+ "quantity": 1.0,
452
+ "price_unit": 450.00,
453
+ "account_id": self.sale_account.id,
454
+ "tax_ids": [[6, 0, self.tax_22.ids]],
455
+ },
456
+ )
457
+ ],
458
+ }
459
+ )
460
+ invoice._onchange_riba_partner_bank_id()
461
+ invoice.action_post()
462
+ # issue wizard
463
+ riba_move_line_id = invoice.line_ids.filtered(
464
+ lambda x: x.account_id == self.account_rec1_id
465
+ )
466
+ wizard_riba_issue = self.env["riba.issue"].create(
467
+ {"configuration_id": self.riba_config_sbf.id}
468
+ )
469
+ action = wizard_riba_issue.with_context(
470
+ active_ids=[riba_move_line_id.id]
471
+ ).create_list()
472
+ riba_list_id = action and action["res_id"] or False
473
+ riba_list = self.slip_model.browse(riba_list_id)
474
+ riba_list.confirm()
475
+ wizard_riba_export = self.env["riba.file.export"].create({})
476
+ wizard_riba_export.with_context(active_ids=[riba_list.id]).act_getfile()
477
+ # Assert
478
+ file_content = base64.decodebytes(wizard_riba_export.riba_txt).decode()
479
+ self.assertNotIn("INV/2025/00004", file_content)
480
+ self.assertIn("CABNP Paribas", file_content)
481
+
482
+ def test_riba_fatturapa_group(self):
483
+ self.partner.group_riba = True
484
+ self.partner.property_account_receivable_id = self.account_rec1_id.id
485
+ recent_date = (
486
+ self.env["account.move"]
487
+ .search([("invoice_date", "!=", False)], order="invoice_date desc", limit=1)
488
+ .invoice_date
489
+ )
490
+ invoice = self.env["account.move"].create(
491
+ {
492
+ "invoice_date": recent_date,
493
+ "move_type": "out_invoice",
494
+ "journal_id": self.sale_journal.id,
495
+ "partner_id": self.partner.id,
496
+ "invoice_payment_term_id": self.account_payment_term_riba.id,
497
+ "invoice_line_ids": [
498
+ (
499
+ 0,
500
+ 0,
501
+ {
502
+ "name": "product1",
503
+ "product_id": self.product1.id,
504
+ "quantity": 1.0,
505
+ "price_unit": 450.00,
506
+ "account_id": self.sale_account.id,
507
+ "tax_ids": [[6, 0, self.tax_22.ids]],
508
+ },
509
+ )
510
+ ],
511
+ }
512
+ )
513
+ invoice._onchange_riba_partner_bank_id()
514
+ invoice.action_post()
515
+ invoice1 = self.env["account.move"].create(
516
+ {
517
+ "invoice_date": recent_date,
518
+ "move_type": "out_invoice",
519
+ "journal_id": self.sale_journal.id,
520
+ "partner_id": self.partner.id,
521
+ "invoice_payment_term_id": self.account_payment_term_riba.id,
522
+ "invoice_line_ids": [
523
+ (
524
+ 0,
525
+ 0,
526
+ {
527
+ "name": "product1",
528
+ "product_id": self.product1.id,
529
+ "quantity": 1.0,
530
+ "price_unit": 450.00,
531
+ "account_id": self.sale_account.id,
532
+ "tax_ids": [[6, 0, self.tax_22.ids]],
533
+ },
534
+ )
535
+ ],
536
+ }
537
+ )
538
+ invoice1._onchange_riba_partner_bank_id()
539
+ invoice1.action_post()
540
+ # issue wizard
541
+ riba_move_line_id = invoice.line_ids.filtered(
542
+ lambda x: x.account_id == self.account_rec1_id
543
+ )
544
+ riba_move_line1_id = invoice1.line_ids.filtered(
545
+ lambda x: x.account_id == self.account_rec1_id
546
+ )
547
+ wizard_riba_issue = self.env["riba.issue"].create(
548
+ {"configuration_id": self.riba_config_sbf.id}
549
+ )
550
+ action = wizard_riba_issue.with_context(
551
+ active_ids=[riba_move_line_id.id, riba_move_line1_id.id]
552
+ ).create_list()
553
+ riba_list_id = action and action["res_id"] or False
554
+ riba_list = self.slip_model.browse(riba_list_id)
555
+ riba_list.confirm()
556
+ self.assertTrue(len(riba_list.line_ids), 2)
557
+ wizard_riba_export = self.env["riba.file.export"].create({})
558
+ wizard_riba_export.with_context(active_ids=[riba_list.id]).act_getfile()
559
+ # Assert
560
+ file_content = base64.decodebytes(wizard_riba_export.riba_txt).decode()
561
+ self.assertNotIn("INV/2025/00008", file_content)
562
+ self.assertIn("INV/2025/00005", file_content)
563
+ self.assertIn("INV/2025/00006", file_content)
564
+
565
+ def test_riba_presentation(self):
566
+ total_amount = 200000
567
+ wizard_riba_issue = self.env["presentation.riba.issue"].create(
568
+ {"presentation_amount": total_amount}
569
+ )
570
+ domain = wizard_riba_issue.action_presentation_riba()["domain"]
571
+ total_issue_amount = sum(
572
+ self.env["account.move.line"].search(domain).mapped("amount_residual")
573
+ )
574
+ self.assertTrue(total_amount - total_issue_amount >= 0)
575
+
576
+ def test_riba_bank_multicompany(self):
577
+ """Configuration parameters for RiBa
578
+ can only be created with data of current company."""
579
+ current_company = self.env.company
580
+ company_2 = self.company2
581
+ partner_bank = self.company2_bank
582
+ partner_bank.company_id = company_2
583
+ suspense_account = self.bank_journal.suspense_account_id.copy(
584
+ {"company_ids": [Command.link(company_2.id)]}
585
+ )
586
+ profit_account = self.bank_journal.profit_account_id.copy(
587
+ {"company_ids": [Command.link(company_2.id)]}
588
+ )
589
+ loss_account = self.bank_journal.loss_account_id.copy(
590
+ {"company_ids": [Command.link(company_2.id)]}
591
+ )
592
+ bank_journal = self.env["account.journal"].create(
593
+ {
594
+ "type": "bank",
595
+ "name": "Bank Journal",
596
+ "code": "BANK2",
597
+ "company_id": company_2.id,
598
+ "suspense_account_id": suspense_account.id,
599
+ "profit_account_id": profit_account.id,
600
+ "loss_account_id": loss_account.id,
601
+ }
602
+ )
603
+ acceptance_account = self.acceptance_account.copy(
604
+ {"company_ids": [Command.link(company_2.id)]}
605
+ )
606
+ # pre-condition
607
+ self.assertEqual(partner_bank.company_id, company_2)
608
+ self.assertNotEqual(current_company, company_2)
609
+
610
+ # Act
611
+ with self.assertRaises(UserError) as ue:
612
+ self.env["riba.configuration"].create(
613
+ {
614
+ "name": "Subject To Collection",
615
+ "type": "incasso",
616
+ "bank_id": partner_bank.id,
617
+ "acceptance_journal_id": bank_journal.id,
618
+ "acceptance_account_id": acceptance_account.id,
619
+ }
620
+ )
621
+
622
+ # Assert
623
+ exc_message = ue.exception.args[0]
624
+ self.assertIn(current_company.name, exc_message)
625
+ self.assertIn(partner_bank.display_name, exc_message)
626
+
627
+ def test_riba_line_date_no_move(self):
628
+ """
629
+ The RiBa line can compute the date when the linked move has been deleted.
630
+ """
631
+ # Arrange: Create RiBa for an invoice
632
+ self.invoice.company_id.due_cost_service_id = self.service_due_cost
633
+ self.invoice.action_post()
634
+ self.assertEqual(self.invoice.state, "posted")
635
+
636
+ to_issue_action = self.env.ref("l10n_it_riba_oca.action_riba_to_issue")
637
+ to_issue_model = self.env[to_issue_action.res_model]
638
+ to_issue_domain = safe_eval.safe_eval(to_issue_action.domain)
639
+ to_issue_records = (
640
+ to_issue_model.search(to_issue_domain) & self.invoice.line_ids
641
+ )
642
+ self.assertTrue(to_issue_records)
643
+
644
+ issue_wizard_context = {
645
+ "active_model": to_issue_records._name,
646
+ "active_ids": to_issue_records.ids,
647
+ }
648
+ issue_wizard_model = self.env["riba.issue"].with_context(**issue_wizard_context)
649
+ issue_wizard_form = Form(issue_wizard_model)
650
+ issue_wizard_form.configuration_id = self.riba_config_incasso
651
+ issue_wizard = issue_wizard_form.save()
652
+ issue_result = issue_wizard.create_list()
653
+
654
+ # Act: Delete the invoice
655
+ self.invoice.button_draft()
656
+ self.invoice.unlink()
657
+
658
+ # Assert: The dates on RiBa lines are empty
659
+ riba_list_id = issue_result["res_id"]
660
+ riba_list_model = issue_result["res_model"]
661
+ riba_list = self.env[riba_list_model].browse(riba_list_id)
662
+ self.assertEqual(
663
+ riba_list.line_ids.mapped("invoice_date"),
664
+ [False] * 2,
665
+ )
666
+
667
+ def test_file_substitute_forbidden_chars(self):
668
+ """Forbidden characters are substituted in generated file."""
669
+ # Arrange
670
+ company = self.env.company
671
+ company.vat = "IT00000000000"
672
+ payment_term = self.payment_term1
673
+ product = self.product1
674
+ partner = self.partner
675
+ partner.street = "Via di là"
676
+ company.due_cost_service_id = self.service_due_cost
677
+
678
+ invoice_form = Form(
679
+ self.env["account.move"].with_context(
680
+ default_move_type="out_invoice",
681
+ default_name="Test invoice",
682
+ )
683
+ )
684
+ invoice_form.partner_id = partner
685
+ invoice_form.invoice_payment_term_id = payment_term
686
+ invoice_form.riba_partner_bank_id = first(partner.bank_ids)
687
+ with invoice_form.invoice_line_ids.new() as line:
688
+ line.product_id = product
689
+ invoice = invoice_form.save()
690
+ invoice.action_post()
691
+
692
+ to_issue_action = self.env.ref("l10n_it_riba_oca.action_riba_to_issue")
693
+ to_issue_records = self.env[to_issue_action.res_model].search(
694
+ safe_eval.safe_eval(to_issue_action.domain)
695
+ )
696
+ invoice_to_issue_records = to_issue_records & invoice.line_ids
697
+ self.assertTrue(invoice_to_issue_records)
698
+
699
+ issue_wizard_model = self.env["riba.issue"].with_context(
700
+ active_model=invoice_to_issue_records._name,
701
+ active_ids=invoice_to_issue_records.ids,
702
+ )
703
+ issue_wizard_form = Form(issue_wizard_model)
704
+ issue_wizard_form.configuration_id = self.riba_config_incasso
705
+ issue_wizard = issue_wizard_form.save()
706
+ issue_result = issue_wizard.create_list()
707
+ slip = self.env[issue_result["res_model"]].browse(issue_result["res_id"])
708
+
709
+ # Act
710
+ export_wizard = (
711
+ self.env["riba.file.export"].with_context(active_ids=slip.ids).create({})
712
+ )
713
+ export_wizard.act_getfile()
714
+
715
+ # Assert
716
+ file_content = base64.decodebytes(export_wizard.riba_txt).decode()
717
+ self.assertNotIn("Via di là", file_content)
718
+ self.assertIn("Via di la", file_content)
719
+
720
+ def test_riba_inv_no_bank(self):
721
+ """
722
+ Test that a riba invoice without a bank defined
723
+ cannot be confirmed (e.g. via the list view)
724
+ """
725
+ self.invoice.company_id.due_cost_service_id = self.service_due_cost.id
726
+ self.invoice.riba_partner_bank_id = False
727
+ with self.assertRaises(UserError) as err:
728
+ self.invoice.action_post()
729
+ err_msg = err.exception.args[0]
730
+ self.assertIn("Cannot post invoices", err_msg)
731
+ self.assertIn(self.invoice.partner_id.display_name, err_msg)
732
+ # We have to add back a taxed collection fee for each payment term line
733
+ # because they have been added during `action_post`
734
+ # and recorded in the exception message,
735
+ # but `assertRaises` rolls them back
736
+ collection_fees = self.invoice.invoice_payment_term_id.riba_payment_cost
737
+ collection_fees_tax = self.invoice.fiscal_position_id.map_tax(
738
+ self.service_due_cost.taxes_id
739
+ )
740
+ taxed_collection_fees = collection_fees_tax.compute_all(collection_fees)[
741
+ "total_included"
742
+ ]
743
+ self.assertIn(
744
+ str(
745
+ self.invoice.amount_total
746
+ + len(self.invoice.invoice_payment_term_id.line_ids)
747
+ * taxed_collection_fees
748
+ ),
749
+ err_msg,
750
+ )
751
+
752
+ def test_riba_payment_date_multiple_lines(self):
753
+ """A specific date can be set to pay multiple RiBa lines."""
754
+ # Arrange
755
+ company = self.env.company
756
+ payment_date = datetime.date(2020, month=1, day=1)
757
+ payment_term = self.payment_term2
758
+ riba_configuration = self.riba_config_sbf
759
+ product = self.product1
760
+ partner = self.partner
761
+ company.due_cost_service_id = self.service_due_cost
762
+
763
+ invoice_form = Form(
764
+ self.env["account.move"].with_context(
765
+ default_move_type="out_invoice",
766
+ default_name="Test invoice",
767
+ )
768
+ )
769
+ invoice_form.partner_id = partner
770
+ invoice_form.invoice_payment_term_id = payment_term
771
+ invoice_form.riba_partner_bank_id = first(partner.bank_ids)
772
+ with invoice_form.invoice_line_ids.new() as line:
773
+ line.product_id = product
774
+ invoice = invoice_form.save()
775
+ invoice.action_post()
776
+
777
+ to_issue_action = self.env.ref("l10n_it_riba_oca.action_riba_to_issue")
778
+ to_issue_records = self.env[to_issue_action.res_model].search(
779
+ safe_eval.safe_eval(to_issue_action.domain)
780
+ )
781
+ invoice_to_issue_records = to_issue_records & invoice.line_ids
782
+ self.assertTrue(invoice_to_issue_records)
783
+
784
+ issue_wizard_model = self.env["riba.issue"].with_context(
785
+ active_model=invoice_to_issue_records._name,
786
+ active_ids=invoice_to_issue_records.ids,
787
+ )
788
+ issue_wizard_form = Form(issue_wizard_model)
789
+ issue_wizard_form.configuration_id = riba_configuration
790
+ issue_wizard = issue_wizard_form.save()
791
+ issue_result = issue_wizard.create_list()
792
+ slip = self.env[issue_result["res_model"]].browse(issue_result["res_id"])
793
+
794
+ slip.confirm()
795
+ self.assertEqual(slip.state, "accepted")
796
+
797
+ credit_wizard_action = self.env.ref("l10n_it_riba_oca.riba_credit_action")
798
+ credit_wizard = (
799
+ self.env[credit_wizard_action["res_model"]]
800
+ .with_context(active_id=slip.id)
801
+ .create(
802
+ {
803
+ "credit_amount": invoice.amount_total,
804
+ }
805
+ )
806
+ )
807
+ res = credit_wizard.create_move()
808
+ self.env["account.move"].browse([res["res_id"]]).action_post()
809
+ self.assertEqual(slip.state, "credited")
810
+ # Act
811
+ payment_wizard_action = slip.settle_all_line()
812
+ payment_wizard_form = Form(
813
+ self.env[payment_wizard_action["res_model"]].with_context(
814
+ **payment_wizard_action["context"]
815
+ )
816
+ )
817
+ payment_wizard_form.payment_date = payment_date
818
+ payment_wizard = payment_wizard_form.save()
819
+ payment_wizard.pay()
820
+
821
+ # Assert
822
+ self.assertEqual(slip.state, "paid")
823
+ payment_lines = self.env["account.move.line"].search(
824
+ [("slip_line_id", "in", slip.line_ids.ids)]
825
+ )
826
+ self.assertTrue(payment_lines)
827
+ payment_move = payment_lines[0].move_id
828
+ self.assertEqual(payment_move.date, payment_date)
829
+
830
+ def test_supplier_company_bank_account_domain(self):
831
+ """The domain for Company Bank Account for Supplier
832
+ only shows bank accounts of current company."""
833
+ # Arrange
834
+ current_company, other_company = self.env.company, self.company2
835
+ current_bank_account = self.company_bank
836
+ other_bank_account = self.company2_bank
837
+ # pre-condition: Bank accounts belong to different companies
838
+ self.assertNotEqual(current_company, other_company)
839
+ self.assertEqual(current_bank_account.partner_id, current_company.partner_id)
840
+ self.assertEqual(other_bank_account.partner_id, other_company.partner_id)
841
+
842
+ # Act: Search bank accounts
843
+ domain = self.env["res.partner"].fields_get(
844
+ allfields=["property_riba_supplier_company_bank_id"],
845
+ attributes=["domain"],
846
+ )["property_riba_supplier_company_bank_id"]["domain"]
847
+ bank_accounts = self.env["res.partner.bank"].search(domain)
848
+
849
+ # Assert: only the bank account of current company is found
850
+ self.assertIn(current_bank_account, bank_accounts)
851
+ self.assertNotIn(other_bank_account, bank_accounts)
852
+
853
+ def test_supplier_to_bill_company_bank_account(self):
854
+ """A supplier has a company bank account,
855
+ it is propagated to its vendor bill."""
856
+ # Arrange
857
+ bank_account = self.company_bank
858
+ payment_term = self.payment_term1
859
+ supplier = self.partner
860
+ supplier.property_supplier_payment_term_id = payment_term
861
+ supplier.property_riba_supplier_company_bank_id = bank_account
862
+ self.assertTrue(payment_term.riba)
863
+
864
+ # Act: Create the vendor bill
865
+ bill = self.env["account.move"].create(
866
+ {
867
+ "move_type": "in_invoice",
868
+ "partner_id": supplier.id,
869
+ "invoice_payment_term_id": payment_term.id,
870
+ }
871
+ )
872
+
873
+ # Assert
874
+ self.assertEqual(bill.riba_supplier_company_bank_id, bank_account)
875
+
876
+ def test_past_due_fee_amount_flow(self):
877
+ config = self.env["riba.configuration"].create(
878
+ {
879
+ "name": "Test Config",
880
+ "type": "sbf",
881
+ "bank_id": self.company_bank.id,
882
+ "acceptance_journal_id": self.bank_journal.id,
883
+ "acceptance_account_id": self.acceptance_account.id,
884
+ "past_due_fee_amount": 15.0,
885
+ }
886
+ )
887
+ self.assertEqual(config.past_due_fee_amount, 15.0)
888
+ distinta = self.env["riba.slip"].create(
889
+ {
890
+ "config_id": config.id,
891
+ "name": "Test slip",
892
+ }
893
+ )
894
+ distinta_line = self.env["riba.slip.line"].create(
895
+ {"slip_id": distinta.id, "amount": 100.0}
896
+ )
897
+ wizard = (
898
+ self.env["riba.past_due"]
899
+ .with_context(
900
+ active_model="riba.slip.line",
901
+ active_id=distinta_line.id,
902
+ )
903
+ .create({})
904
+ )
905
+ self.assertEqual(wizard.past_due_fee_amount, 15.0)