test_account_move_in_invoice.py 95 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333
  1. # -*- coding: utf-8 -*-
  2. # pylint: disable=bad-whitespace
  3. from freezegun import freeze_time
  4. from odoo.addons.account.tests.common import AccountTestInvoicingCommon
  5. from odoo.tests.common import Form
  6. from odoo.tests import tagged
  7. from odoo import fields, Command
  8. from odoo.osv import expression
  9. from odoo.exceptions import ValidationError, RedirectWarning
  10. from datetime import date
  11. from collections import defaultdict
  12. @tagged('post_install', '-at_install')
  13. class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon):
  14. @classmethod
  15. def setUpClass(cls, chart_template_ref=None):
  16. super().setUpClass(chart_template_ref=chart_template_ref)
  17. cls.invoice = cls.init_invoice('in_invoice', products=cls.product_a+cls.product_b)
  18. cls.product_line_vals_1 = {
  19. 'name': cls.product_a.name,
  20. 'product_id': cls.product_a.id,
  21. 'account_id': cls.product_a.property_account_expense_id.id,
  22. 'partner_id': cls.partner_a.id,
  23. 'product_uom_id': cls.product_a.uom_id.id,
  24. 'quantity': 1.0,
  25. 'discount': 0.0,
  26. 'price_unit': 800.0,
  27. 'price_subtotal': 800.0,
  28. 'price_total': 920.0,
  29. 'tax_ids': cls.product_a.supplier_taxes_id.ids,
  30. 'tax_line_id': False,
  31. 'currency_id': cls.company_data['currency'].id,
  32. 'amount_currency': 800.0,
  33. 'debit': 800.0,
  34. 'credit': 0.0,
  35. 'date_maturity': False,
  36. }
  37. cls.product_line_vals_2 = {
  38. 'name': cls.product_b.name,
  39. 'product_id': cls.product_b.id,
  40. 'account_id': cls.product_b.property_account_expense_id.id,
  41. 'partner_id': cls.partner_a.id,
  42. 'product_uom_id': cls.product_b.uom_id.id,
  43. 'quantity': 1.0,
  44. 'discount': 0.0,
  45. 'price_unit': 160.0,
  46. 'price_subtotal': 160.0,
  47. 'price_total': 208.0,
  48. 'tax_ids': cls.product_b.supplier_taxes_id.ids,
  49. 'tax_line_id': False,
  50. 'currency_id': cls.company_data['currency'].id,
  51. 'amount_currency': 160.0,
  52. 'debit': 160.0,
  53. 'credit': 0.0,
  54. 'date_maturity': False,
  55. }
  56. cls.tax_line_vals_1 = {
  57. 'name': cls.tax_purchase_a.name,
  58. 'product_id': False,
  59. 'account_id': cls.company_data['default_account_tax_purchase'].id,
  60. 'partner_id': cls.partner_a.id,
  61. 'product_uom_id': False,
  62. 'quantity': False,
  63. 'discount': 0.0,
  64. 'price_unit': 0.0,
  65. 'price_subtotal': 0.0,
  66. 'price_total': 0.0,
  67. 'tax_ids': [],
  68. 'tax_line_id': cls.tax_purchase_a.id,
  69. 'currency_id': cls.company_data['currency'].id,
  70. 'amount_currency': 144.0,
  71. 'debit': 144.0,
  72. 'credit': 0.0,
  73. 'date_maturity': False,
  74. }
  75. cls.tax_line_vals_2 = {
  76. 'name': cls.tax_purchase_b.name,
  77. 'product_id': False,
  78. 'account_id': cls.company_data['default_account_tax_purchase'].id,
  79. 'partner_id': cls.partner_a.id,
  80. 'product_uom_id': False,
  81. 'quantity': False,
  82. 'discount': 0.0,
  83. 'price_unit': 0.0,
  84. 'price_subtotal': 0.0,
  85. 'price_total': 0.0,
  86. 'tax_ids': [],
  87. 'tax_line_id': cls.tax_purchase_b.id,
  88. 'currency_id': cls.company_data['currency'].id,
  89. 'amount_currency': 24.0,
  90. 'debit': 24.0,
  91. 'credit': 0.0,
  92. 'date_maturity': False,
  93. }
  94. cls.term_line_vals_1 = {
  95. 'name': '',
  96. 'product_id': False,
  97. 'account_id': cls.company_data['default_account_payable'].id,
  98. 'partner_id': cls.partner_a.id,
  99. 'product_uom_id': False,
  100. 'quantity': False,
  101. 'discount': 0.0,
  102. 'price_unit': 0.0,
  103. 'price_subtotal': 0.0,
  104. 'price_total': 0.0,
  105. 'tax_ids': [],
  106. 'tax_line_id': False,
  107. 'currency_id': cls.company_data['currency'].id,
  108. 'amount_currency': -1128.0,
  109. 'debit': 0.0,
  110. 'credit': 1128.0,
  111. 'date_maturity': fields.Date.from_string('2019-01-01'),
  112. }
  113. cls.move_vals = {
  114. 'partner_id': cls.partner_a.id,
  115. 'currency_id': cls.company_data['currency'].id,
  116. 'journal_id': cls.company_data['default_journal_purchase'].id,
  117. 'date': fields.Date.from_string('2019-01-01'),
  118. 'fiscal_position_id': False,
  119. 'payment_reference': '',
  120. 'invoice_payment_term_id': cls.pay_terms_a.id,
  121. 'amount_untaxed': 960.0,
  122. 'amount_tax': 168.0,
  123. 'amount_total': 1128.0,
  124. }
  125. cls.env.user.groups_id += cls.env.ref('uom.group_uom')
  126. def setUp(self):
  127. super(TestAccountMoveInInvoiceOnchanges, self).setUp()
  128. self.assertInvoiceValues(self.invoice, [
  129. self.product_line_vals_1,
  130. self.product_line_vals_2,
  131. self.tax_line_vals_1,
  132. self.tax_line_vals_2,
  133. self.term_line_vals_1,
  134. ], self.move_vals)
  135. def test_in_invoice_onchange_invoice_date(self):
  136. for tax_date, invoice_date, accounting_date in [
  137. ('2019-03-31', '2019-05-12', '2019-05-31'),
  138. ('2019-03-31', '2019-02-10', '2019-04-30'),
  139. ('2019-05-31', '2019-06-15', '2019-06-30'),
  140. ]:
  141. self.invoice.company_id.tax_lock_date = tax_date
  142. with Form(self.invoice) as move_form:
  143. move_form.invoice_date = invoice_date
  144. self.assertEqual(self.invoice.date, fields.Date.to_date(accounting_date))
  145. @freeze_time('2021-09-16')
  146. def test_in_invoice_onchange_invoice_date_2(self):
  147. invoice_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice', account_predictive_bills_disable_prediction=True))
  148. invoice_form.partner_id = self.partner_a
  149. invoice_form.invoice_payment_term_id = self.env.ref('account.account_payment_term_30days')
  150. with invoice_form.invoice_line_ids.new() as line_form:
  151. line_form.product_id = self.product_a
  152. invoice_form.invoice_date = fields.Date.from_string('2021-09-01')
  153. invoice = invoice_form.save()
  154. self.assertRecordValues(invoice, [{
  155. 'date': fields.Date.from_string('2021-09-16'),
  156. 'invoice_date': fields.Date.from_string('2021-09-01'),
  157. 'invoice_date_due': fields.Date.from_string('2021-10-01'),
  158. }])
  159. def test_in_invoice_line_onchange_product_1(self):
  160. move_form = Form(self.invoice)
  161. with move_form.invoice_line_ids.edit(0) as line_form:
  162. line_form.product_id = self.product_b
  163. move_form.save()
  164. self.assertInvoiceValues(self.invoice, [
  165. {
  166. **self.product_line_vals_1,
  167. 'name': self.product_b.name,
  168. 'product_id': self.product_b.id,
  169. 'product_uom_id': self.product_b.uom_id.id,
  170. 'account_id': self.product_b.property_account_expense_id.id,
  171. 'price_unit': 160.0,
  172. 'price_subtotal': 160.0,
  173. 'price_total': 208.0,
  174. 'tax_ids': self.product_b.supplier_taxes_id.ids,
  175. 'amount_currency': 160.0,
  176. 'debit': 160.0,
  177. },
  178. self.product_line_vals_2,
  179. {
  180. **self.tax_line_vals_1,
  181. 'amount_currency': 48.0,
  182. 'debit': 48.0,
  183. },
  184. {
  185. **self.tax_line_vals_2,
  186. 'amount_currency': 48.0,
  187. 'debit': 48.0,
  188. },
  189. {
  190. **self.term_line_vals_1,
  191. 'amount_currency': -416.0,
  192. 'credit': 416.0,
  193. },
  194. ], {
  195. **self.move_vals,
  196. 'amount_untaxed': 320.0,
  197. 'amount_tax': 96.0,
  198. 'amount_total': 416.0,
  199. })
  200. def test_in_invoice_line_onchange_product_2_with_fiscal_pos(self):
  201. ''' Test mapping a price-included tax (10%) with a price-excluded tax (20%) on a price_unit of 110.0.
  202. The price_unit should be 100.0 after applying the fiscal position.
  203. '''
  204. tax_price_include = self.env['account.tax'].create({
  205. 'name': '10% incl',
  206. 'type_tax_use': 'purchase',
  207. 'amount_type': 'percent',
  208. 'amount': 10,
  209. 'price_include': True,
  210. 'include_base_amount': True,
  211. })
  212. tax_price_exclude = self.env['account.tax'].create({
  213. 'name': '15% excl',
  214. 'type_tax_use': 'purchase',
  215. 'amount_type': 'percent',
  216. 'amount': 15,
  217. })
  218. fiscal_position = self.env['account.fiscal.position'].create({
  219. 'name': 'fiscal_pos_a',
  220. 'tax_ids': [
  221. (0, None, {
  222. 'tax_src_id': tax_price_include.id,
  223. 'tax_dest_id': tax_price_exclude.id,
  224. }),
  225. ],
  226. })
  227. product = self.env['product.product'].create({
  228. 'name': 'product',
  229. 'uom_id': self.env.ref('uom.product_uom_unit').id,
  230. 'standard_price': 110.0,
  231. 'supplier_taxes_id': [(6, 0, tax_price_include.ids)],
  232. })
  233. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  234. move_form.partner_id = self.partner_a
  235. move_form.invoice_date = fields.Date.from_string('2019-01-01')
  236. move_form.currency_id = self.currency_data['currency']
  237. move_form.fiscal_position_id = fiscal_position
  238. with move_form.invoice_line_ids.new() as line_form:
  239. line_form.product_id = product
  240. invoice = move_form.save()
  241. self.assertInvoiceValues(invoice, [
  242. {
  243. 'product_id': product.id,
  244. 'price_unit': 200.0,
  245. 'price_subtotal': 200.0,
  246. 'price_total': 230.0,
  247. 'tax_ids': tax_price_exclude.ids,
  248. 'tax_line_id': False,
  249. 'currency_id': self.currency_data['currency'].id,
  250. 'amount_currency': 200.0,
  251. 'debit': 100.0,
  252. 'credit': 0.0,
  253. },
  254. {
  255. 'product_id': False,
  256. 'price_unit': 0.0,
  257. 'price_subtotal': 0.0,
  258. 'price_total': 0.0,
  259. 'tax_ids': [],
  260. 'tax_line_id': tax_price_exclude.id,
  261. 'currency_id': self.currency_data['currency'].id,
  262. 'amount_currency': 30.0,
  263. 'debit': 15.0,
  264. 'credit': 0.0,
  265. },
  266. {
  267. 'product_id': False,
  268. 'price_unit': 0.0,
  269. 'price_subtotal': 0.0,
  270. 'price_total': 0.0,
  271. 'tax_ids': [],
  272. 'tax_line_id': False,
  273. 'currency_id': self.currency_data['currency'].id,
  274. 'amount_currency': -230.0,
  275. 'debit': 0.0,
  276. 'credit': 115.0,
  277. },
  278. ], {
  279. 'currency_id': self.currency_data['currency'].id,
  280. 'fiscal_position_id': fiscal_position.id,
  281. 'amount_untaxed': 200.0,
  282. 'amount_tax': 30.0,
  283. 'amount_total': 230.0,
  284. })
  285. uom_dozen = self.env.ref('uom.product_uom_dozen')
  286. with Form(invoice) as move_form:
  287. with move_form.invoice_line_ids.edit(0) as line_form:
  288. line_form.product_uom_id = uom_dozen
  289. self.assertInvoiceValues(invoice, [
  290. {
  291. 'product_id': product.id,
  292. 'product_uom_id': uom_dozen.id,
  293. 'price_unit': 2400.0,
  294. 'price_subtotal': 2400.0,
  295. 'price_total': 2760.0,
  296. 'tax_ids': tax_price_exclude.ids,
  297. 'tax_line_id': False,
  298. 'currency_id': self.currency_data['currency'].id,
  299. 'amount_currency': 2400.0,
  300. 'debit': 1200.0,
  301. 'credit': 0.0,
  302. },
  303. {
  304. 'product_id': False,
  305. 'product_uom_id': False,
  306. 'price_unit': 0.0,
  307. 'price_subtotal': 0.0,
  308. 'price_total': 0.0,
  309. 'tax_ids': [],
  310. 'tax_line_id': tax_price_exclude.id,
  311. 'currency_id': self.currency_data['currency'].id,
  312. 'amount_currency': 360.0,
  313. 'debit': 180.0,
  314. 'credit': 0.0,
  315. },
  316. {
  317. 'product_id': False,
  318. 'product_uom_id': False,
  319. 'price_unit': 0.0,
  320. 'price_subtotal': 0.0,
  321. 'price_total': 0.0,
  322. 'tax_ids': [],
  323. 'tax_line_id': False,
  324. 'currency_id': self.currency_data['currency'].id,
  325. 'amount_currency': -2760.0,
  326. 'debit': 0.0,
  327. 'credit': 1380.0,
  328. },
  329. ], {
  330. 'currency_id': self.currency_data['currency'].id,
  331. 'fiscal_position_id': fiscal_position.id,
  332. 'amount_untaxed': 2400.0,
  333. 'amount_tax': 360.0,
  334. 'amount_total': 2760.0,
  335. })
  336. def test_in_invoice_line_onchange_product_2_with_fiscal_pos_2(self):
  337. ''' Test mapping a price-included tax (10%) with another price-included tax (20%) on a price_unit of 110.0.
  338. The price_unit should be 120.0 after applying the fiscal position.
  339. '''
  340. tax_price_include_1 = self.env['account.tax'].create({
  341. 'name': '10% incl',
  342. 'type_tax_use': 'purchase',
  343. 'amount_type': 'percent',
  344. 'amount': 10,
  345. 'price_include': True,
  346. 'include_base_amount': True,
  347. })
  348. tax_price_include_2 = self.env['account.tax'].create({
  349. 'name': '20% incl',
  350. 'type_tax_use': 'purchase',
  351. 'amount_type': 'percent',
  352. 'amount': 20,
  353. 'price_include': True,
  354. 'include_base_amount': True,
  355. })
  356. fiscal_position = self.env['account.fiscal.position'].create({
  357. 'name': 'fiscal_pos_a',
  358. 'tax_ids': [
  359. (0, None, {
  360. 'tax_src_id': tax_price_include_1.id,
  361. 'tax_dest_id': tax_price_include_2.id,
  362. }),
  363. ],
  364. })
  365. product = self.env['product.product'].create({
  366. 'name': 'product',
  367. 'uom_id': self.env.ref('uom.product_uom_unit').id,
  368. 'standard_price': 110.0,
  369. 'supplier_taxes_id': [(6, 0, tax_price_include_1.ids)],
  370. })
  371. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  372. move_form.partner_id = self.partner_a
  373. move_form.invoice_date = fields.Date.from_string('2019-01-01')
  374. move_form.currency_id = self.currency_data['currency']
  375. move_form.fiscal_position_id = fiscal_position
  376. with move_form.invoice_line_ids.new() as line_form:
  377. line_form.product_id = product
  378. invoice = move_form.save()
  379. self.assertInvoiceValues(invoice, [
  380. {
  381. 'product_id': product.id,
  382. 'price_unit': 240.0,
  383. 'price_subtotal': 200.0,
  384. 'price_total': 240.0,
  385. 'tax_ids': tax_price_include_2.ids,
  386. 'tax_line_id': False,
  387. 'currency_id': self.currency_data['currency'].id,
  388. 'amount_currency': 200.0,
  389. 'debit': 100.0,
  390. 'credit': 0.0,
  391. },
  392. {
  393. 'product_id': False,
  394. 'price_unit': 0.0,
  395. 'price_subtotal': 0.0,
  396. 'price_total': 0.0,
  397. 'tax_ids': [],
  398. 'tax_line_id': tax_price_include_2.id,
  399. 'currency_id': self.currency_data['currency'].id,
  400. 'amount_currency': 40.0,
  401. 'debit': 20.0,
  402. 'credit': 0.0,
  403. },
  404. {
  405. 'product_id': False,
  406. 'price_unit': 0.0,
  407. 'price_subtotal': 0.0,
  408. 'price_total': 0.0,
  409. 'tax_ids': [],
  410. 'tax_line_id': False,
  411. 'currency_id': self.currency_data['currency'].id,
  412. 'amount_currency': -240.0,
  413. 'debit': 0.0,
  414. 'credit': 120.0,
  415. },
  416. ], {
  417. 'currency_id': self.currency_data['currency'].id,
  418. 'fiscal_position_id': fiscal_position.id,
  419. 'amount_untaxed': 200.0,
  420. 'amount_tax': 40.0,
  421. 'amount_total': 240.0,
  422. })
  423. uom_dozen = self.env.ref('uom.product_uom_dozen')
  424. with Form(invoice) as move_form:
  425. with move_form.invoice_line_ids.edit(0) as line_form:
  426. line_form.product_uom_id = uom_dozen
  427. self.assertInvoiceValues(invoice, [
  428. {
  429. 'product_id': product.id,
  430. 'product_uom_id': uom_dozen.id,
  431. 'price_unit': 2880.0,
  432. 'price_subtotal': 2400.0,
  433. 'price_total': 2880.0,
  434. 'tax_ids': tax_price_include_2.ids,
  435. 'tax_line_id': False,
  436. 'currency_id': self.currency_data['currency'].id,
  437. 'amount_currency': 2400.0,
  438. 'debit': 1200.0,
  439. 'credit': 0.0,
  440. },
  441. {
  442. 'product_id': False,
  443. 'product_uom_id': False,
  444. 'price_unit': 0.0,
  445. 'price_subtotal': 0.0,
  446. 'price_total': 0.0,
  447. 'tax_ids': [],
  448. 'tax_line_id': tax_price_include_2.id,
  449. 'currency_id': self.currency_data['currency'].id,
  450. 'amount_currency': 480.0,
  451. 'debit': 240.0,
  452. 'credit': 0.0,
  453. },
  454. {
  455. 'product_id': False,
  456. 'product_uom_id': False,
  457. 'price_unit': 0.0,
  458. 'price_subtotal': 0.0,
  459. 'price_total': 0.0,
  460. 'tax_ids': [],
  461. 'tax_line_id': False,
  462. 'currency_id': self.currency_data['currency'].id,
  463. 'amount_currency': -2880.0,
  464. 'debit': 0.0,
  465. 'credit': 1440.0,
  466. },
  467. ], {
  468. 'currency_id': self.currency_data['currency'].id,
  469. 'fiscal_position_id': fiscal_position.id,
  470. 'amount_untaxed': 2400.0,
  471. 'amount_tax': 480.0,
  472. 'amount_total': 2880.0,
  473. })
  474. def test_in_invoice_line_onchange_business_fields_1(self):
  475. move_form = Form(self.invoice)
  476. with move_form.invoice_line_ids.edit(0) as line_form:
  477. # Current price_unit is 800.
  478. # We set quantity = 4, discount = 50%, price_unit = 400. The debit/credit fields don't change because (4 * 400) * 0.5 = 800.
  479. line_form.quantity = 4
  480. line_form.discount = 50
  481. line_form.price_unit = 400
  482. move_form.save()
  483. self.assertInvoiceValues(self.invoice, [
  484. {
  485. **self.product_line_vals_1,
  486. 'quantity': 4,
  487. 'discount': 50.0,
  488. 'price_unit': 400.0,
  489. },
  490. self.product_line_vals_2,
  491. self.tax_line_vals_1,
  492. self.tax_line_vals_2,
  493. self.term_line_vals_1,
  494. ], self.move_vals)
  495. move_form = Form(self.invoice)
  496. with move_form.invoice_line_ids.edit(0) as line_form:
  497. # Reset field except the discount that becomes 100%.
  498. # /!\ The modification is made on the accounting tab.
  499. line_form.quantity = 1
  500. line_form.discount = 100
  501. line_form.price_unit = 800
  502. move_form.save()
  503. self.assertInvoiceValues(self.invoice, [
  504. {
  505. **self.product_line_vals_1,
  506. 'discount': 100.0,
  507. 'price_subtotal': 0.0,
  508. 'price_total': 0.0,
  509. 'amount_currency': 0.0,
  510. 'debit': 0.0,
  511. },
  512. self.product_line_vals_2,
  513. {
  514. **self.tax_line_vals_1,
  515. 'amount_currency': 24.0,
  516. 'debit': 24.0,
  517. },
  518. self.tax_line_vals_2,
  519. {
  520. **self.term_line_vals_1,
  521. 'amount_currency': -208.0,
  522. 'credit': 208.0,
  523. },
  524. ], {
  525. **self.move_vals,
  526. 'amount_untaxed': 160.0,
  527. 'amount_tax': 48.0,
  528. 'amount_total': 208.0,
  529. })
  530. def test_in_invoice_line_onchange_partner_1(self):
  531. move_form = Form(self.invoice)
  532. move_form.partner_id = self.partner_b
  533. move_form.payment_reference = 'turlututu'
  534. move_form.save()
  535. self.assertInvoiceValues(self.invoice, [
  536. {
  537. **self.product_line_vals_1,
  538. 'partner_id': self.partner_b.id,
  539. },
  540. {
  541. **self.product_line_vals_2,
  542. 'partner_id': self.partner_b.id,
  543. },
  544. {
  545. **self.tax_line_vals_1,
  546. 'partner_id': self.partner_b.id,
  547. },
  548. {
  549. **self.tax_line_vals_2,
  550. 'partner_id': self.partner_b.id,
  551. },
  552. {
  553. **self.term_line_vals_1,
  554. 'name': 'turlututu',
  555. 'partner_id': self.partner_b.id,
  556. 'account_id': self.partner_b.property_account_payable_id.id,
  557. 'amount_currency': -789.6,
  558. 'credit': 789.6,
  559. 'date_maturity': fields.Date.from_string('2019-02-28'),
  560. },
  561. {
  562. **self.term_line_vals_1,
  563. 'name': 'turlututu',
  564. 'partner_id': self.partner_b.id,
  565. 'account_id': self.partner_b.property_account_payable_id.id,
  566. 'amount_currency': -338.4,
  567. 'credit': 338.4,
  568. },
  569. ], {
  570. **self.move_vals,
  571. 'partner_id': self.partner_b.id,
  572. 'payment_reference': 'turlututu',
  573. 'fiscal_position_id': self.fiscal_pos_a.id,
  574. 'invoice_payment_term_id': self.pay_terms_b.id,
  575. 'amount_untaxed': 960.0,
  576. 'amount_tax': 168.0,
  577. 'amount_total': 1128.0,
  578. })
  579. # Remove lines and recreate them to apply the fiscal position.
  580. move_form = Form(self.invoice)
  581. move_form.invoice_line_ids.remove(0)
  582. move_form.invoice_line_ids.remove(0)
  583. with move_form.invoice_line_ids.new() as line_form:
  584. line_form.product_id = self.product_a
  585. with move_form.invoice_line_ids.new() as line_form:
  586. line_form.product_id = self.product_b
  587. move_form.save()
  588. self.assertInvoiceValues(self.invoice, [
  589. {
  590. **self.product_line_vals_1,
  591. 'account_id': self.product_b.property_account_expense_id.id,
  592. 'partner_id': self.partner_b.id,
  593. 'tax_ids': self.tax_purchase_b.ids,
  594. },
  595. {
  596. **self.product_line_vals_2,
  597. 'partner_id': self.partner_b.id,
  598. 'price_total': 184.0,
  599. 'tax_ids': self.tax_purchase_b.ids,
  600. },
  601. {
  602. **self.tax_line_vals_1,
  603. 'name': self.tax_purchase_b.name,
  604. 'partner_id': self.partner_b.id,
  605. 'tax_line_id': self.tax_purchase_b.id,
  606. },
  607. {
  608. **self.term_line_vals_1,
  609. 'name': 'turlututu',
  610. 'account_id': self.partner_b.property_account_payable_id.id,
  611. 'partner_id': self.partner_b.id,
  612. 'amount_currency': -772.8,
  613. 'credit': 772.8,
  614. 'date_maturity': fields.Date.from_string('2019-02-28'),
  615. },
  616. {
  617. **self.term_line_vals_1,
  618. 'name': 'turlututu',
  619. 'account_id': self.partner_b.property_account_payable_id.id,
  620. 'partner_id': self.partner_b.id,
  621. 'amount_currency': -331.2,
  622. 'credit': 331.2,
  623. },
  624. ], {
  625. **self.move_vals,
  626. 'partner_id': self.partner_b.id,
  627. 'payment_reference': 'turlututu',
  628. 'fiscal_position_id': self.fiscal_pos_a.id,
  629. 'invoice_payment_term_id': self.pay_terms_b.id,
  630. 'amount_untaxed': 960.0,
  631. 'amount_tax': 144.0,
  632. 'amount_total': 1104.0,
  633. })
  634. def test_in_invoice_line_onchange_taxes_1(self):
  635. move_form = Form(self.invoice)
  636. with move_form.invoice_line_ids.edit(0) as line_form:
  637. line_form.price_unit = 960
  638. line_form.tax_ids.add(self.tax_armageddon)
  639. move_form.save()
  640. child_tax_1 = self.tax_armageddon.children_tax_ids[0]
  641. child_tax_2 = self.tax_armageddon.children_tax_ids[1]
  642. self.assertInvoiceValues(self.invoice, [
  643. {
  644. **self.product_line_vals_1,
  645. 'price_unit': 960.0,
  646. 'price_subtotal': 800.0,
  647. 'price_total': 1176.0,
  648. 'tax_ids': (self.tax_purchase_a + self.tax_armageddon).ids,
  649. },
  650. self.product_line_vals_2,
  651. self.tax_line_vals_1,
  652. self.tax_line_vals_2,
  653. {
  654. 'name': child_tax_1.name,
  655. 'product_id': False,
  656. 'account_id': self.company_data['default_account_tax_sale'].id,
  657. 'partner_id': self.partner_a.id,
  658. 'product_uom_id': False,
  659. 'quantity': False,
  660. 'discount': 0.0,
  661. 'price_unit': 0.0,
  662. 'price_subtotal': 0.0,
  663. 'price_total': 0.0,
  664. 'tax_ids': child_tax_2.ids,
  665. 'tax_line_id': child_tax_1.id,
  666. 'currency_id': self.company_data['currency'].id,
  667. 'amount_currency': 64.0,
  668. 'debit': 64.0,
  669. 'credit': 0.0,
  670. 'date_maturity': False,
  671. },
  672. {
  673. 'name': child_tax_1.name,
  674. 'product_id': False,
  675. 'account_id': self.company_data['default_account_expense'].id,
  676. 'partner_id': self.partner_a.id,
  677. 'product_uom_id': False,
  678. 'quantity': False,
  679. 'discount': 0.0,
  680. 'price_unit': 0.0,
  681. 'price_subtotal': 0.0,
  682. 'price_total': 0.0,
  683. 'tax_ids': child_tax_2.ids,
  684. 'tax_line_id': child_tax_1.id,
  685. 'currency_id': self.company_data['currency'].id,
  686. 'amount_currency': 96.0,
  687. 'debit': 96.0,
  688. 'credit': 0.0,
  689. 'date_maturity': False,
  690. },
  691. {
  692. 'name': child_tax_2.name,
  693. 'product_id': False,
  694. 'account_id': child_tax_2.cash_basis_transition_account_id.id,
  695. 'partner_id': self.partner_a.id,
  696. 'product_uom_id': False,
  697. 'quantity': False,
  698. 'discount': 0.0,
  699. 'price_unit': 0.0,
  700. 'price_subtotal': 0.0,
  701. 'price_total': 0.0,
  702. 'tax_ids': [],
  703. 'tax_line_id': child_tax_2.id,
  704. 'currency_id': self.company_data['currency'].id,
  705. 'amount_currency': 96.0,
  706. 'debit': 96.0,
  707. 'credit': 0.0,
  708. 'date_maturity': False,
  709. },
  710. {
  711. **self.term_line_vals_1,
  712. 'price_unit': 0.0,
  713. 'price_subtotal': 0.0,
  714. 'price_total': 0.0,
  715. 'amount_currency': -1384.0,
  716. 'credit': 1384.0,
  717. },
  718. ], {
  719. **self.move_vals,
  720. 'amount_untaxed': 960.0,
  721. 'amount_tax': 424.0,
  722. 'amount_total': 1384.0,
  723. })
  724. def test_in_invoice_line_onchange_cash_rounding_1(self):
  725. # Required for `invoice_cash_rounding_id` to be visible in the view
  726. self.env.user.groups_id += self.env.ref('account.group_cash_rounding')
  727. # Test 'add_invoice_line' rounding
  728. move_form = Form(self.invoice)
  729. # Add a cash rounding having 'add_invoice_line'.
  730. move_form.invoice_cash_rounding_id = self.cash_rounding_a
  731. move_form.save()
  732. # The cash rounding does nothing as the total is already rounded.
  733. self.assertInvoiceValues(self.invoice, [
  734. self.product_line_vals_1,
  735. self.product_line_vals_2,
  736. self.tax_line_vals_1,
  737. self.tax_line_vals_2,
  738. self.term_line_vals_1,
  739. ], self.move_vals)
  740. move_form = Form(self.invoice)
  741. with move_form.invoice_line_ids.edit(0) as line_form:
  742. line_form.price_unit = 799.99
  743. move_form.save()
  744. self.assertInvoiceValues(self.invoice, [
  745. {
  746. **self.product_line_vals_1,
  747. 'price_unit': 799.99,
  748. 'price_subtotal': 799.99,
  749. 'price_total': 919.99,
  750. 'amount_currency': 799.99,
  751. 'debit': 799.99,
  752. },
  753. self.product_line_vals_2,
  754. self.tax_line_vals_1,
  755. self.tax_line_vals_2,
  756. {
  757. 'name': 'add_invoice_line',
  758. 'product_id': False,
  759. 'account_id': self.cash_rounding_a.loss_account_id.id,
  760. 'partner_id': self.partner_a.id,
  761. 'product_uom_id': False,
  762. 'quantity': False,
  763. 'discount': 0.0,
  764. 'price_unit': 0.0,
  765. 'price_subtotal': 0.0,
  766. 'price_total': 0.0,
  767. 'tax_ids': [],
  768. 'tax_line_id': False,
  769. 'currency_id': self.company_data['currency'].id,
  770. 'amount_currency': 0.01,
  771. 'debit': 0.01,
  772. 'credit': 0.0,
  773. 'date_maturity': False,
  774. },
  775. self.term_line_vals_1,
  776. ], self.move_vals)
  777. # Test 'biggest_tax' rounding
  778. self.company_data['company'].country_id = self.env.ref('base.us')
  779. # Add a tag to product_a's default tax
  780. tax_line_tag = self.env['account.account.tag'].create({
  781. 'name': "Tax tag",
  782. 'applicability': 'taxes',
  783. 'country_id': self.company_data['company'].country_id.id,
  784. })
  785. repartition_line = self.tax_purchase_a.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax')
  786. repartition_line.write({'tag_ids': [(4, tax_line_tag.id, 0)]})
  787. # Create the invoice
  788. biggest_tax_invoice = self.env['account.move'].create({
  789. 'move_type': 'in_invoice',
  790. 'date': '2019-01-01',
  791. 'invoice_date': '2019-01-01',
  792. 'partner_id': self.partner_a.id,
  793. 'invoice_cash_rounding_id': self.cash_rounding_b.id,
  794. 'invoice_payment_term_id': self.pay_terms_a.id,
  795. 'invoice_line_ids': [
  796. (0, 0, {
  797. 'product_id': self.product_a.id,
  798. 'price_unit': 799.99,
  799. 'tax_ids': [(6, 0, self.product_a.supplier_taxes_id.ids)],
  800. 'product_uom_id': self.product_a.uom_id.id,
  801. }),
  802. (0, 0, {
  803. 'product_id': self.product_b.id,
  804. 'price_unit': self.product_b.standard_price,
  805. 'tax_ids': [(6, 0, self.product_b.supplier_taxes_id.ids)],
  806. 'product_uom_id': self.product_b.uom_id.id,
  807. }),
  808. ],
  809. })
  810. self.assertInvoiceValues(biggest_tax_invoice, [
  811. {
  812. **self.product_line_vals_1,
  813. 'price_unit': 799.99,
  814. 'price_subtotal': 799.99,
  815. 'price_total': 919.99,
  816. 'amount_currency': 799.99,
  817. 'debit': 799.99,
  818. 'tax_repartition_line_id': None,
  819. 'tax_tag_ids': [],
  820. },
  821. {
  822. **self.product_line_vals_2,
  823. 'tax_repartition_line_id': None,
  824. 'tax_tag_ids': [],
  825. },
  826. {
  827. **self.tax_line_vals_1,
  828. 'tax_repartition_line_id': repartition_line.id,
  829. 'tax_tag_ids': tax_line_tag.ids,
  830. },
  831. {
  832. **self.tax_line_vals_2,
  833. 'tax_repartition_line_id': self.tax_purchase_b.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id,
  834. 'tax_tag_ids': [],
  835. },
  836. {
  837. 'name': '%s (rounding)' % self.tax_purchase_a.name,
  838. 'product_id': False,
  839. 'account_id': self.company_data['default_account_tax_purchase'].id,
  840. 'partner_id': self.partner_a.id,
  841. 'product_uom_id': False,
  842. 'quantity': False,
  843. 'discount': 0.0,
  844. 'price_unit': 0.0,
  845. 'price_subtotal': 0.0,
  846. 'price_total': 0.0,
  847. 'tax_ids': [],
  848. 'tax_line_id': self.tax_purchase_a.id,
  849. 'tax_repartition_line_id': repartition_line.id,
  850. 'tax_tag_ids': tax_line_tag.ids,
  851. 'currency_id': self.company_data['currency'].id,
  852. 'amount_currency': -0.04,
  853. 'debit': 0.0,
  854. 'credit': 0.04,
  855. 'date_maturity': False,
  856. },
  857. {
  858. **self.term_line_vals_1,
  859. 'amount_currency': -1127.95,
  860. 'credit': 1127.95,
  861. 'tax_repartition_line_id': None,
  862. 'tax_tag_ids': [],
  863. },
  864. ], {
  865. **self.move_vals,
  866. 'amount_untaxed': 959.99,
  867. 'amount_tax': 167.96,
  868. 'amount_total': 1127.95,
  869. })
  870. def test_in_invoice_line_onchange_currency_1(self):
  871. move_form = Form(self.invoice)
  872. move_form.currency_id = self.currency_data['currency']
  873. move_form.save()
  874. self.assertInvoiceValues(self.invoice, [
  875. {
  876. **self.product_line_vals_1,
  877. 'currency_id': self.currency_data['currency'].id,
  878. 'amount_currency': 800.0,
  879. 'debit': 400.0,
  880. },
  881. {
  882. **self.product_line_vals_2,
  883. 'currency_id': self.currency_data['currency'].id,
  884. 'amount_currency': 160.0,
  885. 'debit': 80.0,
  886. },
  887. {
  888. **self.tax_line_vals_1,
  889. 'currency_id': self.currency_data['currency'].id,
  890. 'amount_currency': 144.0,
  891. 'debit': 72.0,
  892. },
  893. {
  894. **self.tax_line_vals_2,
  895. 'currency_id': self.currency_data['currency'].id,
  896. 'amount_currency': 24.0,
  897. 'debit': 12.0,
  898. },
  899. {
  900. **self.term_line_vals_1,
  901. 'currency_id': self.currency_data['currency'].id,
  902. 'amount_currency': -1128.0,
  903. 'credit': 564.0,
  904. },
  905. ], {
  906. **self.move_vals,
  907. 'currency_id': self.currency_data['currency'].id,
  908. })
  909. # Change the date to get another rate: 1/3 instead of 1/2.
  910. with Form(self.invoice) as move_form:
  911. move_form.invoice_date = fields.Date.from_string('2016-01-01')
  912. move_form.date = fields.Date.from_string('2016-01-01')
  913. self.assertInvoiceValues(self.invoice, [
  914. {
  915. **self.product_line_vals_1,
  916. 'currency_id': self.currency_data['currency'].id,
  917. 'amount_currency': 800.0,
  918. 'debit': 266.67,
  919. },
  920. {
  921. **self.product_line_vals_2,
  922. 'currency_id': self.currency_data['currency'].id,
  923. 'amount_currency': 160.0,
  924. 'debit': 53.33,
  925. },
  926. {
  927. **self.tax_line_vals_1,
  928. 'currency_id': self.currency_data['currency'].id,
  929. 'amount_currency': 144.0,
  930. 'debit': 48.0,
  931. },
  932. {
  933. **self.tax_line_vals_2,
  934. 'currency_id': self.currency_data['currency'].id,
  935. 'amount_currency': 24.0,
  936. 'debit': 8.0,
  937. },
  938. {
  939. **self.term_line_vals_1,
  940. 'currency_id': self.currency_data['currency'].id,
  941. 'amount_currency': -1128.0,
  942. 'credit': 376.0,
  943. 'date_maturity': fields.Date.from_string('2016-01-01'),
  944. },
  945. ], {
  946. **self.move_vals,
  947. 'currency_id': self.currency_data['currency'].id,
  948. 'date': fields.Date.from_string('2016-01-01'),
  949. })
  950. move_form = Form(self.invoice)
  951. with move_form.invoice_line_ids.edit(0) as line_form:
  952. # 0.045 * 0.1 = 0.0045. As the foreign currency has a 0.001 rounding,
  953. # the result should be 0.005 after rounding.
  954. line_form.quantity = 0.1
  955. line_form.price_unit = 0.045
  956. move_form.save()
  957. self.assertInvoiceValues(self.invoice, [
  958. {
  959. **self.product_line_vals_1,
  960. 'quantity': 0.1,
  961. 'price_unit': 0.05,
  962. 'price_subtotal': 0.005,
  963. 'price_total': 0.006,
  964. 'currency_id': self.currency_data['currency'].id,
  965. 'amount_currency': 0.005,
  966. 'debit': 0.0,
  967. },
  968. {
  969. **self.product_line_vals_2,
  970. 'currency_id': self.currency_data['currency'].id,
  971. 'amount_currency': 160.0,
  972. 'debit': 53.33,
  973. },
  974. {
  975. **self.tax_line_vals_1,
  976. 'currency_id': self.currency_data['currency'].id,
  977. 'amount_currency': 24.001,
  978. 'debit': 8.0,
  979. },
  980. {
  981. **self.tax_line_vals_2,
  982. 'currency_id': self.currency_data['currency'].id,
  983. 'amount_currency': 24.0,
  984. 'debit': 8.0,
  985. },
  986. {
  987. **self.term_line_vals_1,
  988. 'currency_id': self.currency_data['currency'].id,
  989. 'amount_currency': -208.006,
  990. 'credit': 69.33,
  991. 'date_maturity': fields.Date.from_string('2016-01-01'),
  992. },
  993. ], {
  994. **self.move_vals,
  995. 'currency_id': self.currency_data['currency'].id,
  996. 'date': fields.Date.from_string('2016-01-01'),
  997. 'amount_untaxed': 160.005,
  998. 'amount_tax': 48.001,
  999. 'amount_total': 208.006,
  1000. })
  1001. # Exit the multi-currencies.
  1002. with Form(self.invoice) as move_form:
  1003. move_form.currency_id = self.company_data['currency']
  1004. self.assertInvoiceValues(self.invoice, [
  1005. {
  1006. **self.product_line_vals_1,
  1007. 'quantity': 0.1,
  1008. 'price_unit': 0.05,
  1009. 'price_subtotal': 0.01,
  1010. 'price_total': 0.01,
  1011. 'amount_currency': 0.01,
  1012. 'debit': 0.01,
  1013. },
  1014. self.product_line_vals_2,
  1015. {
  1016. **self.tax_line_vals_1,
  1017. 'amount_currency': 24.0,
  1018. 'debit': 24.0,
  1019. },
  1020. self.tax_line_vals_2,
  1021. {
  1022. **self.term_line_vals_1,
  1023. 'amount_currency': -208.01,
  1024. 'credit': 208.01,
  1025. 'date_maturity': fields.Date.from_string('2016-01-01'),
  1026. },
  1027. ], {
  1028. **self.move_vals,
  1029. 'currency_id': self.company_data['currency'].id,
  1030. 'date': fields.Date.from_string('2016-01-01'),
  1031. 'amount_untaxed': 160.01,
  1032. 'amount_tax': 48.0,
  1033. 'amount_total': 208.01,
  1034. })
  1035. def test_in_invoice_onchange_past_invoice_1(self):
  1036. if self.env.ref('purchase.group_purchase_manager', raise_if_not_found=False):
  1037. # `purchase` adds a view which makes `invoice_vendor_bill_id` invisible
  1038. # for purchase users
  1039. # https://github.com/odoo/odoo/blob/385884afd31f25d61e99d139ecd4c574d99a1863/addons/purchase/views/account_move_views.xml#L26
  1040. self.env.user.groups_id -= self.env.ref('purchase.group_purchase_manager')
  1041. self.env.user.groups_id -= self.env.ref('purchase.group_purchase_user')
  1042. copy_invoice = self.invoice.copy()
  1043. move_form = Form(self.invoice)
  1044. move_form.invoice_line_ids.remove(0)
  1045. move_form.invoice_line_ids.remove(0)
  1046. move_form.invoice_vendor_bill_id = copy_invoice
  1047. move_form.save()
  1048. self.assertInvoiceValues(self.invoice, [
  1049. self.product_line_vals_1,
  1050. self.product_line_vals_2,
  1051. self.tax_line_vals_1,
  1052. self.tax_line_vals_2,
  1053. self.term_line_vals_1,
  1054. ], self.move_vals)
  1055. def test_in_invoice_create_refund(self):
  1056. self.invoice.action_post()
  1057. move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
  1058. 'date': fields.Date.from_string('2019-02-01'),
  1059. 'reason': 'no reason',
  1060. 'refund_method': 'refund',
  1061. 'journal_id': self.invoice.journal_id.id,
  1062. })
  1063. reversal = move_reversal.reverse_moves()
  1064. reverse_move = self.env['account.move'].browse(reversal['res_id'])
  1065. self.assertEqual(self.invoice.payment_state, 'not_paid', "Refunding with a draft credit note should keep the invoice 'not_paid'.")
  1066. self.assertInvoiceValues(reverse_move, [
  1067. {
  1068. **self.product_line_vals_1,
  1069. 'amount_currency': -800.0,
  1070. 'debit': 0.0,
  1071. 'credit': 800.0,
  1072. 'tax_tag_invert': True,
  1073. 'tax_base_amount': 0.0,
  1074. },
  1075. {
  1076. **self.product_line_vals_2,
  1077. 'amount_currency': -160.0,
  1078. 'debit': 0.0,
  1079. 'credit': 160.0,
  1080. 'tax_tag_invert': True,
  1081. 'tax_base_amount': 0.0,
  1082. },
  1083. {
  1084. **self.tax_line_vals_1,
  1085. 'amount_currency': -144.0,
  1086. 'debit': 0.0,
  1087. 'credit': 144.0,
  1088. 'tax_tag_invert': True,
  1089. 'tax_base_amount': 960.0,
  1090. },
  1091. {
  1092. **self.tax_line_vals_2,
  1093. 'amount_currency': -24.0,
  1094. 'debit': 0.0,
  1095. 'credit': 24.0,
  1096. 'tax_tag_invert': True,
  1097. 'tax_base_amount': 160.0,
  1098. },
  1099. {
  1100. **self.term_line_vals_1,
  1101. 'name': '',
  1102. 'amount_currency': 1128.0,
  1103. 'debit': 1128.0,
  1104. 'credit': 0.0,
  1105. 'date_maturity': move_reversal.date,
  1106. 'tax_tag_invert': False,
  1107. 'tax_base_amount': 0.0,
  1108. },
  1109. ], {
  1110. **self.move_vals,
  1111. 'invoice_payment_term_id': None,
  1112. 'date': move_reversal.date,
  1113. 'state': 'draft',
  1114. 'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
  1115. 'payment_state': 'not_paid',
  1116. })
  1117. move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
  1118. 'date': fields.Date.from_string('2019-02-01'),
  1119. 'reason': 'no reason again',
  1120. 'refund_method': 'cancel',
  1121. 'journal_id': self.invoice.journal_id.id,
  1122. })
  1123. reversal = move_reversal.reverse_moves()
  1124. reverse_move = self.env['account.move'].browse(reversal['res_id'])
  1125. self.assertEqual(self.invoice.payment_state, 'reversed', "After cancelling it with a reverse invoice, an invoice should be in 'reversed' state.")
  1126. self.assertInvoiceValues(reverse_move, [
  1127. {
  1128. **self.product_line_vals_1,
  1129. 'amount_currency': -800.0,
  1130. 'debit': 0.0,
  1131. 'credit': 800.0,
  1132. 'tax_tag_invert': True,
  1133. 'tax_base_amount': 0,
  1134. },
  1135. {
  1136. **self.product_line_vals_2,
  1137. 'amount_currency': -160.0,
  1138. 'debit': 0.0,
  1139. 'credit': 160.0,
  1140. 'tax_tag_invert': True,
  1141. 'tax_base_amount': 0,
  1142. },
  1143. {
  1144. **self.tax_line_vals_1,
  1145. 'amount_currency': -144.0,
  1146. 'debit': 0.0,
  1147. 'credit': 144.0,
  1148. 'tax_tag_invert': True,
  1149. 'tax_base_amount': 960.0,
  1150. },
  1151. {
  1152. **self.tax_line_vals_2,
  1153. 'amount_currency': -24.0,
  1154. 'debit': 0.0,
  1155. 'credit': 24.0,
  1156. 'tax_tag_invert': True,
  1157. 'tax_base_amount': 160.0,
  1158. },
  1159. {
  1160. **self.term_line_vals_1,
  1161. 'name': '',
  1162. 'amount_currency': 1128.0,
  1163. 'debit': 1128.0,
  1164. 'credit': 0.0,
  1165. 'date_maturity': move_reversal.date,
  1166. 'tax_tag_invert': False,
  1167. 'tax_base_amount': 0,
  1168. },
  1169. ], {
  1170. **self.move_vals,
  1171. 'invoice_payment_term_id': None,
  1172. 'date': move_reversal.date,
  1173. 'state': 'posted',
  1174. 'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
  1175. 'payment_state': 'paid',
  1176. })
  1177. def test_in_invoice_create_refund_multi_currency(self):
  1178. ''' Test the account.move.reversal takes care about the currency rates when setting
  1179. a custom reversal date.
  1180. '''
  1181. with Form(self.invoice) as move_form:
  1182. move_form.date = '2016-01-01'
  1183. move_form.currency_id = self.currency_data['currency']
  1184. self.invoice.action_post()
  1185. # The currency rate changed from 1/3 to 1/2.
  1186. move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
  1187. 'date': fields.Date.from_string('2017-01-01'),
  1188. 'reason': 'no reason',
  1189. 'refund_method': 'refund',
  1190. 'journal_id': self.invoice.journal_id.id,
  1191. })
  1192. reversal = move_reversal.reverse_moves()
  1193. reverse_move = self.env['account.move'].browse(reversal['res_id'])
  1194. self.assertEqual(self.invoice.payment_state, 'not_paid', "Refunding with a draft credit note should keep the invoice 'not_paid'.")
  1195. self.assertInvoiceValues(reverse_move, [
  1196. {
  1197. **self.product_line_vals_1,
  1198. 'amount_currency': -800.0,
  1199. 'currency_id': self.currency_data['currency'].id,
  1200. 'debit': 0.0,
  1201. 'credit': 400.0,
  1202. },
  1203. {
  1204. **self.product_line_vals_2,
  1205. 'amount_currency': -160.0,
  1206. 'currency_id': self.currency_data['currency'].id,
  1207. 'debit': 0.0,
  1208. 'credit': 80.0,
  1209. },
  1210. {
  1211. **self.tax_line_vals_1,
  1212. 'amount_currency': -144.0,
  1213. 'currency_id': self.currency_data['currency'].id,
  1214. 'debit': 0.0,
  1215. 'credit': 72.0,
  1216. },
  1217. {
  1218. **self.tax_line_vals_2,
  1219. 'amount_currency': -24.0,
  1220. 'currency_id': self.currency_data['currency'].id,
  1221. 'debit': 0.0,
  1222. 'credit': 12.0,
  1223. },
  1224. {
  1225. **self.term_line_vals_1,
  1226. 'name': '',
  1227. 'amount_currency': 1128.0,
  1228. 'currency_id': self.currency_data['currency'].id,
  1229. 'debit': 564.0,
  1230. 'credit': 0.0,
  1231. 'date_maturity': move_reversal.date,
  1232. },
  1233. ], {
  1234. **self.move_vals,
  1235. 'invoice_payment_term_id': None,
  1236. 'currency_id': self.currency_data['currency'].id,
  1237. 'date': move_reversal.date,
  1238. 'state': 'draft',
  1239. 'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
  1240. 'payment_state': 'not_paid',
  1241. })
  1242. move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
  1243. 'date': fields.Date.from_string('2017-01-01'),
  1244. 'reason': 'no reason again',
  1245. 'refund_method': 'cancel',
  1246. 'journal_id': self.invoice.journal_id.id,
  1247. })
  1248. reversal = move_reversal.reverse_moves()
  1249. reverse_move = self.env['account.move'].browse(reversal['res_id'])
  1250. self.assertEqual(self.invoice.payment_state, 'reversed', "After cancelling it with a reverse invoice, an invoice should be in 'reversed' state.")
  1251. self.assertInvoiceValues(reverse_move, [
  1252. {
  1253. **self.product_line_vals_1,
  1254. 'amount_currency': -800.0,
  1255. 'currency_id': self.currency_data['currency'].id,
  1256. 'debit': 0.0,
  1257. 'credit': 400.0,
  1258. },
  1259. {
  1260. **self.product_line_vals_2,
  1261. 'amount_currency': -160.0,
  1262. 'currency_id': self.currency_data['currency'].id,
  1263. 'debit': 0.0,
  1264. 'credit': 80.0,
  1265. },
  1266. {
  1267. **self.tax_line_vals_1,
  1268. 'amount_currency': -144.0,
  1269. 'currency_id': self.currency_data['currency'].id,
  1270. 'debit': 0.0,
  1271. 'credit': 72.0,
  1272. },
  1273. {
  1274. **self.tax_line_vals_2,
  1275. 'amount_currency': -24.0,
  1276. 'currency_id': self.currency_data['currency'].id,
  1277. 'debit': 0.0,
  1278. 'credit': 12.0,
  1279. },
  1280. {
  1281. **self.term_line_vals_1,
  1282. 'name': '',
  1283. 'amount_currency': 1128.0,
  1284. 'currency_id': self.currency_data['currency'].id,
  1285. 'debit': 564.0,
  1286. 'credit': 0.0,
  1287. 'date_maturity': move_reversal.date,
  1288. },
  1289. ], {
  1290. **self.move_vals,
  1291. 'invoice_payment_term_id': None,
  1292. 'currency_id': self.currency_data['currency'].id,
  1293. 'date': move_reversal.date,
  1294. 'state': 'posted',
  1295. 'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
  1296. 'payment_state': 'paid',
  1297. })
  1298. def test_in_invoice_create_1(self):
  1299. # Test creating an account_move with the least information.
  1300. move = self.env['account.move'].create({
  1301. 'move_type': 'in_invoice',
  1302. 'partner_id': self.partner_a.id,
  1303. 'invoice_date': fields.Date.from_string('2019-01-01'),
  1304. 'currency_id': self.currency_data['currency'].id,
  1305. 'invoice_payment_term_id': self.pay_terms_a.id,
  1306. 'invoice_line_ids': [
  1307. Command.create({
  1308. 'product_id': self.product_line_vals_1['product_id'],
  1309. 'product_uom_id': self.product_line_vals_1['product_uom_id'],
  1310. 'price_unit': self.product_line_vals_1['price_unit'],
  1311. 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])],
  1312. }),
  1313. Command.create({
  1314. 'product_id': self.product_line_vals_2['product_id'],
  1315. 'product_uom_id': self.product_line_vals_2['product_uom_id'],
  1316. 'price_unit': self.product_line_vals_2['price_unit'],
  1317. 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])],
  1318. }),
  1319. ],
  1320. })
  1321. self.assertInvoiceValues(move, [
  1322. {
  1323. **self.product_line_vals_1,
  1324. 'currency_id': self.currency_data['currency'].id,
  1325. 'amount_currency': 800.0,
  1326. 'debit': 400.0,
  1327. },
  1328. {
  1329. **self.product_line_vals_2,
  1330. 'currency_id': self.currency_data['currency'].id,
  1331. 'amount_currency': 160.0,
  1332. 'debit': 80.0,
  1333. },
  1334. {
  1335. **self.tax_line_vals_1,
  1336. 'currency_id': self.currency_data['currency'].id,
  1337. 'amount_currency': 144.0,
  1338. 'debit': 72.0,
  1339. },
  1340. {
  1341. **self.tax_line_vals_2,
  1342. 'currency_id': self.currency_data['currency'].id,
  1343. 'amount_currency': 24.0,
  1344. 'debit': 12.0,
  1345. },
  1346. {
  1347. **self.term_line_vals_1,
  1348. 'currency_id': self.currency_data['currency'].id,
  1349. 'amount_currency': -1128.0,
  1350. 'credit': 564.0,
  1351. },
  1352. ], {
  1353. **self.move_vals,
  1354. 'currency_id': self.currency_data['currency'].id,
  1355. 'date': fields.Date.from_string('2019-01-31'),
  1356. })
  1357. def test_in_invoice_write_1(self):
  1358. # Test creating an account_move with the least information.
  1359. move = self.env['account.move'].create({
  1360. 'move_type': 'in_invoice',
  1361. 'partner_id': self.partner_a.id,
  1362. 'invoice_date': fields.Date.from_string('2019-01-01'),
  1363. 'currency_id': self.currency_data['currency'].id,
  1364. 'invoice_payment_term_id': self.pay_terms_a.id,
  1365. 'invoice_line_ids': [
  1366. Command.create({
  1367. 'product_id': self.product_line_vals_1['product_id'],
  1368. 'product_uom_id': self.product_line_vals_1['product_uom_id'],
  1369. 'price_unit': self.product_line_vals_1['price_unit'],
  1370. 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])],
  1371. }),
  1372. ],
  1373. })
  1374. move.write({
  1375. 'invoice_line_ids': [
  1376. Command.create({
  1377. 'product_id': self.product_line_vals_2['product_id'],
  1378. 'product_uom_id': self.product_line_vals_2['product_uom_id'],
  1379. 'price_unit': self.product_line_vals_2['price_unit'],
  1380. 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])],
  1381. }),
  1382. ],
  1383. })
  1384. self.assertInvoiceValues(move, [
  1385. {
  1386. **self.product_line_vals_1,
  1387. 'currency_id': self.currency_data['currency'].id,
  1388. 'amount_currency': 800.0,
  1389. 'debit': 400.0,
  1390. },
  1391. {
  1392. **self.product_line_vals_2,
  1393. 'currency_id': self.currency_data['currency'].id,
  1394. 'amount_currency': 160.0,
  1395. 'debit': 80.0,
  1396. },
  1397. {
  1398. **self.tax_line_vals_1,
  1399. 'currency_id': self.currency_data['currency'].id,
  1400. 'amount_currency': 144.0,
  1401. 'debit': 72.0,
  1402. },
  1403. {
  1404. **self.tax_line_vals_2,
  1405. 'currency_id': self.currency_data['currency'].id,
  1406. 'amount_currency': 24.0,
  1407. 'debit': 12.0,
  1408. },
  1409. {
  1410. **self.term_line_vals_1,
  1411. 'currency_id': self.currency_data['currency'].id,
  1412. 'amount_currency': -1128.0,
  1413. 'credit': 564.0,
  1414. },
  1415. ], {
  1416. **self.move_vals,
  1417. 'date': fields.Date.from_string('2019-01-31'),
  1418. 'currency_id': self.currency_data['currency'].id,
  1419. })
  1420. def test_in_invoice_single_duplicate_supplier_reference(self):
  1421. """ Ensure duplicated ref are computed correctly in this simple case """
  1422. invoice_1 = self.invoice
  1423. invoice_1.ref = 'a unique supplier reference that will be copied'
  1424. invoice_2 = invoice_1.copy(default={'invoice_date': invoice_1.invoice_date})
  1425. # ensure no Error is raised
  1426. invoice_2.ref = invoice_1.ref
  1427. self.assertRecordValues(invoice_2, [{'duplicated_ref_ids': invoice_1.ids}])
  1428. def test_in_invoice_single_duplicate_supplier_reference_with_form(self):
  1429. """ Ensure duplicated ref are computed correctly with UI's NEW_ID"""
  1430. invoice_1 = self.invoice
  1431. invoice_1.ref = 'a unique supplier reference that will be copied'
  1432. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1433. move_form.partner_id = self.partner_a
  1434. move_form.invoice_date = invoice_1.invoice_date
  1435. move_form.ref = invoice_1.ref
  1436. with move_form.invoice_line_ids.new() as line_form:
  1437. line_form.product_id = self.product_a
  1438. with move_form.invoice_line_ids.new() as line_form:
  1439. line_form.product_id = self.product_b
  1440. invoice_2 = move_form.save()
  1441. self.assertRecordValues(invoice_2, [{'duplicated_ref_ids': invoice_1.ids}])
  1442. def test_in_invoice_multiple_duplicate_supplier_reference_batch(self):
  1443. """ Ensure duplicated ref are computed correctly even when updated in batch"""
  1444. invoice_1 = self.invoice
  1445. invoice_1.ref = 'a unique supplier reference that will be copied'
  1446. invoice_2 = invoice_1.copy(default={'invoice_date': invoice_1.invoice_date})
  1447. invoice_3 = invoice_1.copy(default={'invoice_date': invoice_1.invoice_date})
  1448. # reassign to trigger the compute method
  1449. invoices = invoice_1 + invoice_2 + invoice_3
  1450. invoices.ref = invoice_1.ref
  1451. self.assertRecordValues(invoices, [
  1452. {'duplicated_ref_ids': (invoice_2 + invoice_3).ids},
  1453. {'duplicated_ref_ids': (invoice_1 + invoice_3).ids},
  1454. {'duplicated_ref_ids': (invoice_1 + invoice_2).ids},
  1455. ])
  1456. def test_in_invoice_multiple_duplicate_supplier_reference_constrains(self):
  1457. """ Ensure that an error is raised on post if some invoices with duplicated ref share the same invoice_date """
  1458. invoice_1 = self.invoice
  1459. invoice_1.ref = 'a unique supplier reference that will be copied'
  1460. invoice_2 = invoice_1.copy(default={'invoice_date': invoice_1.invoice_date})
  1461. invoice_3 = invoice_1.copy(default={'invoice_date': invoice_1.invoice_date})
  1462. # reassign to trigger the compute method
  1463. invoices = invoice_1 + invoice_2 + invoice_3
  1464. invoices.ref = invoice_1.ref
  1465. # test constrains: batch without any previous posted invoice
  1466. with self.assertRaises(RedirectWarning):
  1467. (invoice_1 + invoice_2 + invoice_3).action_post()
  1468. # test constrains: batch with one previous posted invoice
  1469. invoice_1.action_post()
  1470. with self.assertRaises(RedirectWarning):
  1471. (invoice_2 + invoice_3).action_post()
  1472. # test constrains: single with one previous posted invoice
  1473. with self.assertRaises(RedirectWarning):
  1474. invoice_2.action_post()
  1475. @freeze_time('2023-02-01')
  1476. def test_in_invoice_payment_register_wizard(self):
  1477. # Test creating an account_move with an in_invoice_type and check payment register wizard values
  1478. move = self.env['account.move'].create({
  1479. 'move_type': 'in_invoice',
  1480. 'partner_id': self.partner_a.id,
  1481. 'invoice_date': fields.Date.from_string('2023-01-30'),
  1482. 'currency_id': self.currency_data['currency'].id,
  1483. 'invoice_payment_term_id': self.pay_terms_b.id,
  1484. 'invoice_line_ids': [
  1485. Command.create({
  1486. 'product_id': self.product_line_vals_1['product_id'],
  1487. 'product_uom_id': self.product_line_vals_1['product_uom_id'],
  1488. 'price_unit': self.product_line_vals_1['price_unit'],
  1489. 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])],
  1490. }),
  1491. ],
  1492. })
  1493. move.action_post()
  1494. action_data = move.action_register_payment()
  1495. with Form(self.env[action_data['res_model']].with_context(action_data['context'])) as wiz_form:
  1496. self.assertEqual(wiz_form.payment_date.strftime('%Y-%m-%d'), '2023-02-01')
  1497. self.assertEqual(wiz_form.amount, 920)
  1498. self.assertTrue(wiz_form.group_payment)
  1499. self.assertFalse(wiz_form._get_modifier('group_payment', 'invisible'))
  1500. self.assertFalse(wiz_form._get_modifier('group_payment', 'readonly'))
  1501. def test_in_invoice_switch_in_refund_1(self):
  1502. # Test creating an account_move with an in_invoice_type and switch it in an in_refund.
  1503. move = self.env['account.move'].create({
  1504. 'move_type': 'in_invoice',
  1505. 'partner_id': self.partner_a.id,
  1506. 'invoice_date': fields.Date.from_string('2019-01-01'),
  1507. 'currency_id': self.currency_data['currency'].id,
  1508. 'invoice_payment_term_id': self.pay_terms_a.id,
  1509. 'invoice_line_ids': [
  1510. Command.create({
  1511. 'product_id': self.product_line_vals_1['product_id'],
  1512. 'product_uom_id': self.product_line_vals_1['product_uom_id'],
  1513. 'price_unit': self.product_line_vals_1['price_unit'],
  1514. 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])],
  1515. }),
  1516. Command.create({
  1517. 'product_id': self.product_line_vals_2['product_id'],
  1518. 'product_uom_id': self.product_line_vals_2['product_uom_id'],
  1519. 'price_unit': self.product_line_vals_2['price_unit'],
  1520. 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])],
  1521. }),
  1522. ],
  1523. })
  1524. move.action_switch_invoice_into_refund_credit_note()
  1525. self.assertRecordValues(move, [{'move_type': 'in_refund'}])
  1526. self.assertInvoiceValues(move, [
  1527. {
  1528. **self.product_line_vals_1,
  1529. 'currency_id': self.currency_data['currency'].id,
  1530. 'amount_currency': -800.0,
  1531. 'credit': 400.0,
  1532. 'debit': 0,
  1533. },
  1534. {
  1535. **self.product_line_vals_2,
  1536. 'currency_id': self.currency_data['currency'].id,
  1537. 'amount_currency': -160.0,
  1538. 'credit': 80.0,
  1539. 'debit': 0,
  1540. },
  1541. {
  1542. **self.tax_line_vals_1,
  1543. 'currency_id': self.currency_data['currency'].id,
  1544. 'amount_currency': -144.0,
  1545. 'credit': 72.0,
  1546. 'debit': 0,
  1547. },
  1548. {
  1549. **self.tax_line_vals_2,
  1550. 'currency_id': self.currency_data['currency'].id,
  1551. 'amount_currency': -24.0,
  1552. 'credit': 12.0,
  1553. 'debit': 0,
  1554. },
  1555. {
  1556. **self.term_line_vals_1,
  1557. 'currency_id': self.currency_data['currency'].id,
  1558. 'amount_currency': 1128.0,
  1559. 'debit': 564.0,
  1560. 'credit': 0,
  1561. },
  1562. ], {
  1563. **self.move_vals,
  1564. 'date': fields.Date.from_string('2019-01-31'),
  1565. 'currency_id': self.currency_data['currency'].id,
  1566. })
  1567. def test_in_invoice_switch_in_refund_2(self):
  1568. # Test creating an account_move with an in_invoice_type and switch it in an in_refund and a negative quantity.
  1569. move = self.env['account.move'].create({
  1570. 'move_type': 'in_invoice',
  1571. 'partner_id': self.partner_a.id,
  1572. 'invoice_date': fields.Date.from_string('2019-01-01'),
  1573. 'currency_id': self.currency_data['currency'].id,
  1574. 'invoice_payment_term_id': self.pay_terms_a.id,
  1575. 'invoice_line_ids': [
  1576. Command.create({
  1577. 'product_id': self.product_line_vals_1['product_id'],
  1578. 'product_uom_id': self.product_line_vals_1['product_uom_id'],
  1579. 'price_unit': self.product_line_vals_1['price_unit'],
  1580. 'quantity': -self.product_line_vals_1['quantity'],
  1581. 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])],
  1582. }),
  1583. Command.create({
  1584. 'product_id': self.product_line_vals_2['product_id'],
  1585. 'product_uom_id': self.product_line_vals_2['product_uom_id'],
  1586. 'price_unit': self.product_line_vals_2['price_unit'],
  1587. 'quantity': -self.product_line_vals_2['quantity'],
  1588. 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])],
  1589. }),
  1590. ],
  1591. })
  1592. self.assertInvoiceValues(move, [
  1593. {
  1594. **self.product_line_vals_1,
  1595. 'currency_id': self.currency_data['currency'].id,
  1596. 'amount_currency': -800.0,
  1597. 'price_subtotal': -800.0,
  1598. 'price_total': -920.0,
  1599. 'credit': 400.0,
  1600. 'debit': 0,
  1601. 'quantity': -1.0,
  1602. },
  1603. {
  1604. **self.product_line_vals_2,
  1605. 'currency_id': self.currency_data['currency'].id,
  1606. 'amount_currency': -160.0,
  1607. 'price_subtotal': -160.0,
  1608. 'price_total': -208.0,
  1609. 'credit': 80.0,
  1610. 'debit': 0,
  1611. 'quantity': -1.0,
  1612. },
  1613. {
  1614. **self.tax_line_vals_1,
  1615. 'currency_id': self.currency_data['currency'].id,
  1616. 'amount_currency': -144.0,
  1617. 'credit': 72.0,
  1618. 'debit': 0,
  1619. },
  1620. {
  1621. **self.tax_line_vals_2,
  1622. 'currency_id': self.currency_data['currency'].id,
  1623. 'amount_currency': -24.0,
  1624. 'credit': 12.0,
  1625. 'debit': 0,
  1626. },
  1627. {
  1628. **self.term_line_vals_1,
  1629. 'currency_id': self.currency_data['currency'].id,
  1630. 'amount_currency': 1128.0,
  1631. 'debit': 564.0,
  1632. 'credit': 0,
  1633. },
  1634. ], {
  1635. **self.move_vals,
  1636. 'date': fields.Date.from_string('2019-01-31'),
  1637. 'currency_id': self.currency_data['currency'].id,
  1638. 'amount_tax' : -self.move_vals['amount_tax'],
  1639. 'amount_total' : -self.move_vals['amount_total'],
  1640. 'amount_untaxed' : -self.move_vals['amount_untaxed'],
  1641. })
  1642. move.action_switch_invoice_into_refund_credit_note()
  1643. self.assertRecordValues(move, [{'move_type': 'in_refund'}])
  1644. self.assertInvoiceValues(move, [
  1645. {
  1646. **self.product_line_vals_1,
  1647. 'currency_id': self.currency_data['currency'].id,
  1648. 'amount_currency': -800.0,
  1649. 'credit': 400.0,
  1650. 'debit': 0,
  1651. },
  1652. {
  1653. **self.product_line_vals_2,
  1654. 'currency_id': self.currency_data['currency'].id,
  1655. 'amount_currency': -160.0,
  1656. 'credit': 80.0,
  1657. 'debit': 0,
  1658. },
  1659. {
  1660. **self.tax_line_vals_1,
  1661. 'currency_id': self.currency_data['currency'].id,
  1662. 'amount_currency': -144.0,
  1663. 'credit': 72.0,
  1664. 'debit': 0,
  1665. },
  1666. {
  1667. **self.tax_line_vals_2,
  1668. 'currency_id': self.currency_data['currency'].id,
  1669. 'amount_currency': -24.0,
  1670. 'credit': 12.0,
  1671. 'debit': 0,
  1672. },
  1673. {
  1674. **self.term_line_vals_1,
  1675. 'currency_id': self.currency_data['currency'].id,
  1676. 'amount_currency': 1128.0,
  1677. 'debit': 564.0,
  1678. 'credit': 0,
  1679. },
  1680. ], {
  1681. **self.move_vals,
  1682. 'date': fields.Date.from_string('2019-01-31'),
  1683. 'currency_id': self.currency_data['currency'].id,
  1684. 'amount_tax' : self.move_vals['amount_tax'],
  1685. 'amount_total' : self.move_vals['amount_total'],
  1686. 'amount_untaxed' : self.move_vals['amount_untaxed'],
  1687. })
  1688. def test_in_invoice_change_period_accrual_1(self):
  1689. move = self.env['account.move'].create({
  1690. 'move_type': 'in_invoice',
  1691. 'date': '2017-01-01',
  1692. 'partner_id': self.partner_a.id,
  1693. 'invoice_date': fields.Date.from_string('2017-01-01'),
  1694. 'currency_id': self.currency_data['currency'].id,
  1695. 'invoice_payment_term_id': self.pay_terms_a.id,
  1696. 'invoice_line_ids': [
  1697. (0, None, {
  1698. 'name': self.product_line_vals_1['name'],
  1699. 'product_id': self.product_line_vals_1['product_id'],
  1700. 'product_uom_id': self.product_line_vals_1['product_uom_id'],
  1701. 'quantity': self.product_line_vals_1['quantity'],
  1702. 'price_unit': self.product_line_vals_1['price_unit'],
  1703. 'tax_ids': self.product_line_vals_1['tax_ids'],
  1704. }),
  1705. (0, None, {
  1706. 'name': self.product_line_vals_2['name'],
  1707. 'product_id': self.product_line_vals_2['product_id'],
  1708. 'product_uom_id': self.product_line_vals_2['product_uom_id'],
  1709. 'quantity': self.product_line_vals_2['quantity'],
  1710. 'price_unit': self.product_line_vals_2['price_unit'],
  1711. 'tax_ids': self.product_line_vals_2['tax_ids'],
  1712. }),
  1713. ]
  1714. })
  1715. move.action_post()
  1716. wizard = self.env['account.automatic.entry.wizard'].with_context(
  1717. active_model='account.move.line',
  1718. active_ids=move.invoice_line_ids.ids,
  1719. ).create({
  1720. 'action': 'change_period',
  1721. 'date': '2018-01-01',
  1722. 'percentage': 60,
  1723. 'journal_id': self.company_data['default_journal_misc'].id,
  1724. 'expense_accrual_account': self.env['account.account'].create({
  1725. 'name': 'Accrual Expense Account',
  1726. 'code': '234567',
  1727. 'account_type': 'expense',
  1728. 'reconcile': True,
  1729. }).id,
  1730. 'revenue_accrual_account': self.env['account.account'].create({
  1731. 'name': 'Accrual Revenue Account',
  1732. 'code': '765432',
  1733. 'account_type': 'expense',
  1734. 'reconcile': True,
  1735. }).id,
  1736. })
  1737. wizard_res = wizard.do_action()
  1738. self.assertInvoiceValues(move, [
  1739. {
  1740. **self.product_line_vals_1,
  1741. 'currency_id': self.currency_data['currency'].id,
  1742. 'amount_currency': 800.0,
  1743. 'debit': 400.0,
  1744. 'credit': 0.0,
  1745. },
  1746. {
  1747. **self.product_line_vals_2,
  1748. 'currency_id': self.currency_data['currency'].id,
  1749. 'amount_currency': 160.0,
  1750. 'debit': 80.0,
  1751. 'credit': 0.0,
  1752. },
  1753. {
  1754. **self.tax_line_vals_1,
  1755. 'currency_id': self.currency_data['currency'].id,
  1756. 'amount_currency': 144.0,
  1757. 'debit': 72.0,
  1758. 'credit': 0.0,
  1759. },
  1760. {
  1761. **self.tax_line_vals_2,
  1762. 'currency_id': self.currency_data['currency'].id,
  1763. 'amount_currency': 24.0,
  1764. 'debit': 12.0,
  1765. 'credit': 0.0,
  1766. },
  1767. {
  1768. **self.term_line_vals_1,
  1769. 'currency_id': self.currency_data['currency'].id,
  1770. 'amount_currency': -1128.0,
  1771. 'debit': 0.0,
  1772. 'credit': 564.0,
  1773. 'date_maturity': fields.Date.from_string('2017-01-01'),
  1774. },
  1775. ], {
  1776. **self.move_vals,
  1777. 'currency_id': self.currency_data['currency'].id,
  1778. 'date': fields.Date.from_string('2017-01-01'),
  1779. })
  1780. accrual_lines = self.env['account.move'].browse(wizard_res['domain'][0][2]).line_ids.sorted('date')
  1781. self.assertRecordValues(accrual_lines, [
  1782. {'amount_currency': -480.0, 'debit': 0.0, 'credit': 240.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
  1783. {'amount_currency': 480.0, 'debit': 240.0, 'credit': 0.0, 'account_id': wizard.expense_accrual_account.id, 'reconciled': True},
  1784. {'amount_currency': -96.0, 'debit': 0.0, 'credit': 48.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
  1785. {'amount_currency': 96.0, 'debit': 48.0, 'credit': 0.0, 'account_id': wizard.expense_accrual_account.id, 'reconciled': True},
  1786. {'amount_currency': 480.0, 'debit': 240.0, 'credit': 0.0, 'account_id': self.product_line_vals_1['account_id'], 'reconciled': False},
  1787. {'amount_currency': -480.0, 'debit': 0.0, 'credit': 240.0, 'account_id': wizard.expense_accrual_account.id, 'reconciled': True},
  1788. {'amount_currency': 96.0, 'debit': 48.0, 'credit': 0.0, 'account_id': self.product_line_vals_2['account_id'], 'reconciled': False},
  1789. {'amount_currency': -96.0, 'debit': 0.0, 'credit': 48.0, 'account_id': wizard.expense_accrual_account.id, 'reconciled': True},
  1790. ])
  1791. def test_in_invoice_reverse_caba(self):
  1792. tax_waiting_account = self.env['account.account'].create({
  1793. 'name': 'TAX_WAIT',
  1794. 'code': 'TWAIT',
  1795. 'account_type': 'liability_current',
  1796. 'reconcile': True,
  1797. 'company_id': self.company_data['company'].id,
  1798. })
  1799. tax_final_account = self.env['account.account'].create({
  1800. 'name': 'TAX_TO_DEDUCT',
  1801. 'code': 'TDEDUCT',
  1802. 'account_type': 'asset_current',
  1803. 'company_id': self.company_data['company'].id,
  1804. })
  1805. tax_base_amount_account = self.env['account.account'].create({
  1806. 'name': 'TAX_BASE',
  1807. 'code': 'TBASE',
  1808. 'account_type': 'asset_current',
  1809. 'company_id': self.company_data['company'].id,
  1810. })
  1811. self.env.company.account_cash_basis_base_account_id = tax_base_amount_account
  1812. self.env.company.tax_exigibility = True
  1813. tax_tags = defaultdict(dict)
  1814. for line_type, repartition_type in [(l, r) for l in ('invoice', 'refund') for r in ('base', 'tax')]:
  1815. tax_tags[line_type][repartition_type] = self.env['account.account.tag'].create({
  1816. 'name': '%s %s tag' % (line_type, repartition_type),
  1817. 'applicability': 'taxes',
  1818. 'country_id': self.env.ref('base.us').id,
  1819. })
  1820. tax = self.env['account.tax'].create({
  1821. 'name': 'cash basis 10%',
  1822. 'type_tax_use': 'purchase',
  1823. 'amount': 10,
  1824. 'tax_exigibility': 'on_payment',
  1825. 'cash_basis_transition_account_id': tax_waiting_account.id,
  1826. 'invoice_repartition_line_ids': [
  1827. (0, 0, {
  1828. 'repartition_type': 'base',
  1829. 'tag_ids': [(6, 0, tax_tags['invoice']['base'].ids)],
  1830. }),
  1831. (0, 0, {
  1832. 'repartition_type': 'tax',
  1833. 'account_id': tax_final_account.id,
  1834. 'tag_ids': [(6, 0, tax_tags['invoice']['tax'].ids)],
  1835. }),
  1836. ],
  1837. 'refund_repartition_line_ids': [
  1838. (0, 0, {
  1839. 'repartition_type': 'base',
  1840. 'tag_ids': [(6, 0, tax_tags['refund']['base'].ids)],
  1841. }),
  1842. (0, 0, {
  1843. 'repartition_type': 'tax',
  1844. 'account_id': tax_final_account.id,
  1845. 'tag_ids': [(6, 0, tax_tags['refund']['tax'].ids)],
  1846. }),
  1847. ],
  1848. })
  1849. # create invoice
  1850. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1851. move_form.partner_id = self.partner_a
  1852. move_form.invoice_date = fields.Date.from_string('2017-01-01')
  1853. with move_form.invoice_line_ids.new() as line_form:
  1854. line_form.product_id = self.product_a
  1855. line_form.tax_ids.clear()
  1856. line_form.tax_ids.add(tax)
  1857. invoice = move_form.save()
  1858. invoice.action_post()
  1859. # make payment
  1860. self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
  1861. 'payment_date': invoice.date,
  1862. })._create_payments()
  1863. # check caba move
  1864. partial_rec = invoice.mapped('line_ids.matched_debit_ids')
  1865. caba_move = self.env['account.move'].search([('tax_cash_basis_rec_id', '=', partial_rec.id)])
  1866. expected_values = [
  1867. {
  1868. 'tax_line_id': False,
  1869. 'tax_repartition_line_id': False,
  1870. 'tax_ids': [],
  1871. 'tax_tag_ids': [],
  1872. 'account_id': tax_base_amount_account.id,
  1873. 'debit': 0.0,
  1874. 'credit': 800.0,
  1875. },
  1876. {
  1877. 'tax_line_id': False,
  1878. 'tax_repartition_line_id': False,
  1879. 'tax_ids': tax.ids,
  1880. 'tax_tag_ids': tax_tags['invoice']['base'].ids,
  1881. 'account_id': tax_base_amount_account.id,
  1882. 'debit': 800.0,
  1883. 'credit': 0.0,
  1884. },
  1885. {
  1886. 'tax_line_id': False,
  1887. 'tax_repartition_line_id': False,
  1888. 'tax_ids': [],
  1889. 'tax_tag_ids': [],
  1890. 'account_id': tax_waiting_account.id,
  1891. 'debit': 0.0,
  1892. 'credit': 80.0,
  1893. },
  1894. {
  1895. 'tax_line_id': tax.id,
  1896. 'tax_repartition_line_id': tax.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id,
  1897. 'tax_ids': [],
  1898. 'tax_tag_ids': tax_tags['invoice']['tax'].ids,
  1899. 'account_id': tax_final_account.id,
  1900. 'debit': 80.0,
  1901. 'credit': 0.0,
  1902. },
  1903. ]
  1904. self.assertRecordValues(caba_move.line_ids, expected_values)
  1905. # unreconcile
  1906. credit_aml = invoice.line_ids.filtered('credit')
  1907. credit_aml.remove_move_reconcile()
  1908. # check caba move reverse is same as caba move with only debit/credit inverted
  1909. reversed_caba_move = self.env['account.move'].search([('reversed_entry_id', '=', caba_move.id)])
  1910. for value in expected_values:
  1911. value.update({
  1912. 'debit': value['credit'],
  1913. 'credit': value['debit'],
  1914. })
  1915. self.assertRecordValues(reversed_caba_move.line_ids, expected_values)
  1916. def test_in_invoice_line_tax_line_delete(self):
  1917. with self.assertRaisesRegex(ValidationError, "You cannot delete a tax line"):
  1918. with Form(self.invoice) as invoice_form:
  1919. invoice_form.line_ids.remove(2)
  1920. @freeze_time('2022-06-17')
  1921. def test_fiduciary_mode_date_suggestion(self):
  1922. """Test that the fiduciary mode invoice date suggestion is correct."""
  1923. # Fiduciary mode not enabled, no date suggestion
  1924. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1925. self.assertFalse(move_form.invoice_date)
  1926. # Fiduciary mode enabled, date suggestion
  1927. self.env.company.quick_edit_mode = "out_and_in_invoices"
  1928. # We are June 17th. No Lock date. Bill Date of the most recent Vendor Bill : March 15th
  1929. # ==> Default New Vendor Bill date = March 31st (last day of March)
  1930. self.init_invoice(move_type='in_invoice', invoice_date='2022-03-15', products=self.product_a, post=True)
  1931. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1932. self.assertEqual(move_form.invoice_date.strftime('%Y-%m-%d'), '2022-03-31')
  1933. # We are June 17th. No Lock date. Bill Date of the most recent Vendor Bill : March 31st
  1934. # ==> Default New Vendor Bill date = March 31st 2022 (last day of March)
  1935. self.init_invoice(move_type='in_invoice', invoice_date='2022-03-31', products=self.product_b, post=True)
  1936. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1937. self.assertEqual(move_form.invoice_date.strftime('%Y-%m-%d'), '2022-03-31')
  1938. # We are June 17th. No Lock date. Bill Date of the most recent Vendor Bill : June 16th
  1939. # ==> Default New Vendor Bill date = June 17th (today is smaller than end of June)
  1940. move = self.init_invoice(move_type='in_invoice', invoice_date='2022-06-16', products=self.product_b, post=True)
  1941. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1942. self.assertEqual(move_form.invoice_date, date.today())
  1943. move.button_draft()
  1944. move.unlink()
  1945. # We are June 17th. Lock date : April 30th. Bill Date of the most recent Vendor Bill : April 30th
  1946. # ==> Default New Vendor Bill date = May 31st (last day of the first month not locked)
  1947. self.env['account.move'].search([('state', '!=', 'posted')]).unlink()
  1948. move = self.init_invoice(move_type='in_invoice', invoice_date='2022-04-30', products=self.product_a, post=True)
  1949. move.company_id.fiscalyear_lock_date = fields.Date.from_string('2022-04-30')
  1950. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1951. self.assertEqual(move_form.invoice_date.strftime('%Y-%m-%d'), '2022-05-31')
  1952. # If the user changes the invoice date, we should not override it
  1953. self.init_invoice(move_type='in_invoice', invoice_date='2022-05-01', products=self.product_b, post=True)
  1954. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
  1955. self.assertEqual(move_form.invoice_date.strftime('%Y-%m-%d'), '2022-05-31')
  1956. move_form.invoice_date = fields.Date.from_string('2022-05-06')
  1957. move = move_form.save()
  1958. self.assertEqual(move.invoice_date.strftime('%Y-%m-%d'), '2022-05-06')
  1959. def _assert_payment_move_state(self, move_type, amount, counterpart_values_list, payment_state):
  1960. def assert_partial(line1, line2):
  1961. partial = self.env['account.partial.reconcile'].search(expression.OR([
  1962. [('debit_move_id', '=', line1.id), ('credit_move_id', '=', line2.id)],
  1963. [('debit_move_id', '=', line2.id), ('credit_move_id', '=', line1.id)],
  1964. ]), limit=1)
  1965. self.assertTrue(partial)
  1966. def create_move(move_type, amount, account=None):
  1967. move_vals = {
  1968. 'move_type': move_type,
  1969. 'date': '2020-01-10',
  1970. }
  1971. if move_type in self.env['account.move'].get_sale_types(include_receipts=True) + self.env['account.move'].get_purchase_types(include_receipts=True):
  1972. move_vals.update({
  1973. 'partner_id': self.partner_a.id,
  1974. 'invoice_date': '2020-01-10',
  1975. 'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': amount, 'tax_ids': []})],
  1976. })
  1977. else:
  1978. if amount > 0.0:
  1979. debit_account = account or self.company_data['default_account_receivable']
  1980. credit_account = self.company_data['default_account_revenue']
  1981. debit_balance = amount
  1982. else:
  1983. credit_account = account or self.company_data['default_account_receivable']
  1984. debit_account = self.company_data['default_account_revenue']
  1985. debit_balance = -amount
  1986. move_vals['line_ids'] = [
  1987. Command.create({
  1988. 'name': "line1",
  1989. 'account_id': debit_account.id,
  1990. 'balance': debit_balance,
  1991. }),
  1992. Command.create({
  1993. 'name': "line2",
  1994. 'account_id': credit_account.id,
  1995. 'balance': -debit_balance,
  1996. }),
  1997. ]
  1998. move = self.env['account.move'].create(move_vals)
  1999. move.action_post()
  2000. return move
  2001. def create_payment(move, amount):
  2002. self.env['account.payment.register']\
  2003. .with_context(active_ids=move.ids, active_model='account.move')\
  2004. .create({
  2005. 'amount': amount,
  2006. })\
  2007. ._create_payments()
  2008. def create_reverse(move, amount):
  2009. move_reversal = self.env['account.move.reversal']\
  2010. .with_context(active_model='account.move', active_ids=move.ids)\
  2011. .create({
  2012. 'reason': 'no reason',
  2013. 'refund_method': 'refund',
  2014. 'journal_id': move.journal_id.id,
  2015. })
  2016. reversal = move_reversal.reverse_moves()
  2017. reverse_move = self.env['account.move'].browse(reversal['res_id'])
  2018. if reverse_move.move_type in ('out_refund', 'in_refund'):
  2019. reverse_move.write({
  2020. 'invoice_line_ids': [
  2021. Command.update(reverse_move.invoice_line_ids.id, {'price_unit': amount}),
  2022. ],
  2023. })
  2024. else:
  2025. line = move.line_ids.filtered(lambda line: line.account_type in ('asset_receivable', 'liability_payable'))
  2026. reverse_move.write({
  2027. 'line_ids': [
  2028. Command.update(line.id, {'balance': amount}),
  2029. ],
  2030. })
  2031. reverse_move.action_post()
  2032. (move + reverse_move).line_ids\
  2033. .filtered(lambda line: line.account_type in ('asset_receivable', 'liability_payable'))\
  2034. .reconcile()
  2035. def create_statement_line(move, amount):
  2036. statement_line = self.env['account.bank.statement.line'].create({
  2037. 'payment_ref': 'ref',
  2038. 'journal_id': self.company_data['default_journal_bank'].id,
  2039. 'amount': amount,
  2040. 'date': '2020-01-10',
  2041. })
  2042. _st_liquidity_lines, st_suspense_lines, _st_other_lines = statement_line\
  2043. .with_context(skip_account_move_synchronization=True)\
  2044. ._seek_for_lines()
  2045. line = move.line_ids.filtered(lambda line: line.account_type in ('asset_receivable', 'liability_payable'))
  2046. st_suspense_lines.account_id = line.account_id
  2047. (st_suspense_lines + line).reconcile()
  2048. assert_partial(st_suspense_lines, line)
  2049. move = create_move(move_type, amount)
  2050. line = move.line_ids.filtered(lambda line: line.account_type in ('asset_receivable', 'liability_payable'))
  2051. for counterpart_move_type, counterpart_amount in counterpart_values_list:
  2052. if counterpart_move_type == 'payment':
  2053. create_payment(move, counterpart_amount)
  2054. elif counterpart_move_type == 'reverse':
  2055. create_reverse(move, counterpart_amount)
  2056. elif counterpart_move_type == 'statement_line':
  2057. create_statement_line(move, counterpart_amount)
  2058. else:
  2059. counterpart_move = create_move(counterpart_move_type, counterpart_amount, account=line.account_id)
  2060. counterpart_line = counterpart_move.line_ids.filtered(lambda x: x.account_id == line.account_id)
  2061. (line + counterpart_line).reconcile()
  2062. assert_partial(line, counterpart_line)
  2063. if payment_state == 'in_payment' and move._get_invoice_in_payment_state() == 'paid':
  2064. payment_state = 'paid'
  2065. self.assertRecordValues(move, [{'payment_state': payment_state}])
  2066. def test_payment_move_state(self):
  2067. for move_type, amount, counterpart_values_list, payment_state in (
  2068. ('out_invoice', 1000.0, [('out_refund', 1000.0)], 'reversed'),
  2069. ('out_invoice', 1000.0, [('out_refund', 500.0), ('out_refund', 500.0)], 'reversed'),
  2070. ('out_invoice', 1000.0, [('out_refund', 500.0), ('entry', -500.0)], 'reversed'),
  2071. ('out_invoice', 1000.0, [('reverse', 1000.0)], 'reversed'),
  2072. ('out_receipt', 1000.0, [('out_refund', 1000.0)], 'reversed'),
  2073. ('out_receipt', 1000.0, [('out_refund', 500.0), ('out_refund', 500.0)], 'reversed'),
  2074. ('out_receipt', 1000.0, [('reverse', 1000.0)], 'reversed'),
  2075. ('out_refund', 1000.0, [('reverse', -1000.0)], 'reversed'),
  2076. ('in_invoice', 1000.0, [('in_refund', 1000.0)], 'reversed'),
  2077. ('in_invoice', 1000.0, [('in_refund', 500.0), ('in_refund', 500.0)], 'reversed'),
  2078. ('in_invoice', 1000.0, [('in_refund', 500.0), ('entry', 500.0)], 'reversed'),
  2079. ('in_invoice', 1000.0, [('reverse', 1000.0)], 'reversed'),
  2080. ('in_receipt', 1000.0, [('in_refund', 1000.0)], 'reversed'),
  2081. ('in_receipt', 1000.0, [('in_refund', 500.0), ('in_refund', 500.0)], 'reversed'),
  2082. ('in_receipt', 1000.0, [('reverse', 1000.0)], 'reversed'),
  2083. ('in_refund', 1000.0, [('reverse', 1000.0)], 'reversed'),
  2084. ('entry', 1000.0, [('entry', -1000.0)], 'not_paid'),
  2085. ('entry', 1000.0, [('reverse', 1000.0)], 'not_paid'),
  2086. ('out_invoice', 1000.0, [('payment', 500.0)], 'partial'),
  2087. ('out_invoice', 1000.0, [('payment', 1000.0)], 'in_payment'),
  2088. ('out_invoice', 1000.0, [('statement_line', 500.0)], 'partial'),
  2089. ('out_invoice', 1000.0, [('statement_line', 1000.0)], 'paid'),
  2090. ('out_receipt', 1000.0, [('payment', 500.0)], 'partial'),
  2091. ('out_receipt', 1000.0, [('payment', 1000.0)], 'in_payment'),
  2092. ('out_receipt', 1000.0, [('statement_line', 500.0)], 'partial'),
  2093. ('out_receipt', 1000.0, [('statement_line', 1000.0)], 'paid'),
  2094. ('out_refund', 1000.0, [('payment', 500.0)], 'partial'),
  2095. ('out_refund', 1000.0, [('payment', 1000.0)], 'in_payment'),
  2096. ('out_refund', 1000.0, [('statement_line', -500.0)], 'partial'),
  2097. ('out_refund', 1000.0, [('statement_line', -1000.0)], 'paid'),
  2098. ('in_invoice', 1000.0, [('payment', 500.0)], 'partial'),
  2099. ('in_invoice', 1000.0, [('payment', 1000.0)], 'in_payment'),
  2100. ('in_invoice', 1000.0, [('statement_line', -500.0)], 'partial'),
  2101. ('in_invoice', 1000.0, [('statement_line', -1000.0)], 'paid'),
  2102. ('in_receipt', 1000.0, [('payment', 500.0)], 'partial'),
  2103. ('in_receipt', 1000.0, [('payment', 1000.0)], 'in_payment'),
  2104. ('in_receipt', 1000.0, [('statement_line', -500.0)], 'partial'),
  2105. ('in_receipt', 1000.0, [('statement_line', -1000.0)], 'paid'),
  2106. ('in_refund', 1000.0, [('payment', 500.0)], 'partial'),
  2107. ('in_refund', 1000.0, [('payment', 1000.0)], 'in_payment'),
  2108. ('in_refund', 1000.0, [('statement_line', 500.0)], 'partial'),
  2109. ('in_refund', 1000.0, [('statement_line', 1000.0)], 'paid'),
  2110. ('entry', 1000.0, [('payment', 500.0)], 'not_paid'),
  2111. ('entry', 1000.0, [('payment', 1000.0)], 'not_paid'),
  2112. ('entry', 1000.0, [('statement_line', 500.0)], 'not_paid'),
  2113. ('entry', 1000.0, [('statement_line', 1000.0)], 'not_paid'),
  2114. ('out_invoice', 1000.0, [('out_refund', 500.0), ('payment', 500.0)], 'in_payment'),
  2115. ('out_invoice', 1000.0, [('out_refund', 500.0), ('payment', 400.0)], 'partial'),
  2116. ('out_invoice', 1000.0, [('out_refund', 500.0), ('statement_line', 500.0)], 'paid'),
  2117. ('out_invoice', 1000.0, [('out_refund', 500.0), ('statement_line', 400.0)], 'partial'),
  2118. ('out_invoice', 1000.0, [('entry', -1000.0)], 'paid'),
  2119. ('in_invoice', 1000.0, [('in_refund', 500.0), ('payment', 500.0)], 'in_payment'),
  2120. ('in_invoice', 1000.0, [('in_refund', 500.0), ('payment', 400.0)], 'partial'),
  2121. ('in_invoice', 1000.0, [('in_refund', 500.0), ('statement_line', -500.0)], 'paid'),
  2122. ('in_invoice', 1000.0, [('in_refund', 500.0), ('statement_line', -400.0)], 'partial'),
  2123. ('in_invoice', 1000.0, [('entry', 1000.0)], 'paid'),
  2124. ):
  2125. with self.subTest(
  2126. move_type=move_type,
  2127. amount=amount,
  2128. counterpart_values_list=counterpart_values_list,
  2129. payment_state=payment_state,
  2130. ):
  2131. self._assert_payment_move_state(move_type, amount, counterpart_values_list, payment_state)
  2132. def test_invoice_sent_to_additional_partner(self):
  2133. """
  2134. Make sure that when an invoice is sent to a partner who is not
  2135. the invoiced customer, they receive a link containing an access token,
  2136. allowing them to view the invoice without needing to log in.
  2137. """
  2138. # Create a simple invoice for the partner
  2139. invoice = self.init_invoice(
  2140. 'out_invoice', partner=self.partner_a, invoice_date='2023-04-17', amounts=[100])
  2141. # Set the invoice to the 'posted' state
  2142. invoice.action_post()
  2143. # Create a partner not related to the invoice
  2144. additional_partner = self.env['res.partner'].create({
  2145. 'name': "Additional Partner",
  2146. 'email': "additional@example.com",
  2147. })
  2148. # Send the invoice
  2149. action = invoice.with_context(discard_logo_check=True).action_invoice_sent()
  2150. action_context = action['context']
  2151. # Create the email using the wizard and add the additional partner as a recipient
  2152. invoice_send_wizard = self.env['account.invoice.send'].with_context(
  2153. action_context,
  2154. active_ids=[invoice.id]
  2155. ).create({'is_print': False})
  2156. invoice_send_wizard.partner_ids |= additional_partner
  2157. # By default, `mail.mail` are automatically deleted after being sent.
  2158. # This line desables this behavior, ensuring that the record remains
  2159. # available for further testing
  2160. invoice_send_wizard.template_id.auto_delete = False
  2161. invoice_send_wizard.send_and_print_action()
  2162. # Find the email sent to the additional partner
  2163. additional_partner_mail = self.env['mail.mail'].search([
  2164. ('res_id', '=', invoice.id),
  2165. ('recipient_ids', '=', additional_partner.id)
  2166. ])
  2167. self.assertTrue(additional_partner_mail)
  2168. self.assertIn('access_token=', additional_partner_mail.body_html,
  2169. "The additional partner should be sent the link including the token")
  2170. def test_onchange_journal_currency(self):
  2171. """
  2172. Ensure invoice currency changes on journal change, iff the journal
  2173. has a currency_id set.
  2174. """
  2175. chf = self.env.ref('base.CHF')
  2176. eur = self.env.ref('base.EUR')
  2177. journal_gen_exp = self.env['account.journal'].create({
  2178. 'name': 'Expenses (generic)',
  2179. 'type': 'purchase',
  2180. 'code': 'EXPGEN',
  2181. })
  2182. journal_swiss_exp = self.env['account.journal'].create({
  2183. 'name': 'Expenses (CHF)',
  2184. 'type': 'purchase',
  2185. 'code': 'EXPCHF',
  2186. 'currency_id': chf.id,
  2187. })
  2188. self.invoice.currency_id = eur
  2189. move_form = Form(self.invoice)
  2190. invoice = move_form.save()
  2191. self.assertEqual(invoice.currency_id, eur)
  2192. # No change expected with generic journal
  2193. move_form.journal_id = journal_gen_exp
  2194. move_form.save()
  2195. self.assertEqual(invoice.currency_id, eur,
  2196. "Changing to a journal without set currency shouldn't affect invoice currency")
  2197. # Currency should change
  2198. move_form.journal_id = journal_swiss_exp
  2199. move_form.save()
  2200. self.assertEqual(invoice.currency_id, chf,
  2201. "Changing to a journal with a set currency should change invoice currency")