test_event_sale.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. from odoo.addons.event_sale.tests.common import TestEventSaleCommon
  4. from odoo.addons.mail.tests.common import mail_new_test_user
  5. from odoo.tests import tagged
  6. from odoo.tests.common import users
  7. @tagged('event_flow')
  8. class TestEventSale(TestEventSaleCommon):
  9. @classmethod
  10. def setUpClass(cls):
  11. super(TestEventSale, cls).setUpClass()
  12. product = cls.env['product.product'].create({
  13. 'name': 'Event',
  14. 'detailed_type': 'event',
  15. })
  16. cls.user_salesperson = mail_new_test_user(cls.env, login='user_salesman', groups='sales_team.group_sale_salesman')
  17. cls.ticket = cls.env['event.event.ticket'].create({
  18. 'name': 'First Ticket',
  19. 'product_id': cls.event_product.id,
  20. 'seats_max': 30,
  21. 'event_id': cls.event_0.id,
  22. })
  23. cls.event_0.write({
  24. 'event_ticket_ids': [
  25. (6, 0, cls.ticket.ids),
  26. (0, 0, {
  27. 'name': 'Second Ticket',
  28. 'product_id': cls.event_product.id,
  29. })
  30. ],
  31. })
  32. cls.sale_order = cls.env['sale.order'].create({
  33. 'partner_id': cls.env.ref('base.res_partner_2').id,
  34. 'note': 'Invoice after delivery',
  35. 'payment_term_id': cls.env.ref('account.account_payment_term_end_following_month').id
  36. })
  37. # In the sales order I add some sales order lines. i choose event product
  38. cls.env['sale.order.line'].create({
  39. 'product_id': product.id,
  40. 'price_unit': 190.50,
  41. 'order_id': cls.sale_order.id,
  42. 'event_id': cls.event_0.id,
  43. 'event_ticket_id': cls.ticket.id,
  44. })
  45. cls.register_person = cls.env['registration.editor'].create({
  46. 'sale_order_id': cls.sale_order.id,
  47. 'event_registration_ids': [(0, 0, {
  48. 'event_id': cls.event_0.id,
  49. 'name': 'Administrator',
  50. 'email': 'abc@example.com',
  51. 'sale_order_line_id': cls.sale_order.order_line.id,
  52. })],
  53. })
  54. # make a SO for a customer, selling some tickets
  55. cls.customer_so = cls.env['sale.order'].with_user(cls.user_sales_salesman).create({
  56. 'partner_id': cls.event_customer.id,
  57. })
  58. @users('user_sales_salesman')
  59. def test_event_crm_sale(self):
  60. TICKET1_COUNT, TICKET2_COUNT = 3, 1
  61. customer_so = self.customer_so.with_user(self.env.user)
  62. ticket1 = self.event_0.event_ticket_ids[0]
  63. ticket2 = self.event_0.event_ticket_ids[1]
  64. # PREPARE SO DATA
  65. # ------------------------------------------------------------
  66. # adding some tickets to SO
  67. customer_so.write({
  68. 'order_line': [
  69. (0, 0, {
  70. 'event_id': self.event_0.id,
  71. 'event_ticket_id': ticket1.id,
  72. 'product_id': ticket1.product_id.id,
  73. 'product_uom_qty': TICKET1_COUNT,
  74. 'price_unit': 10,
  75. }), (0, 0, {
  76. 'event_id': self.event_0.id,
  77. 'event_ticket_id': ticket2.id,
  78. 'product_id': ticket2.product_id.id,
  79. 'product_uom_qty': TICKET2_COUNT,
  80. 'price_unit': 50,
  81. })
  82. ]
  83. })
  84. ticket1_line = customer_so.order_line.filtered(lambda line: line.event_ticket_id == ticket1)
  85. ticket2_line = customer_so.order_line.filtered(lambda line: line.event_ticket_id == ticket2)
  86. self.assertEqual(customer_so.amount_untaxed, TICKET1_COUNT * 10 + TICKET2_COUNT * 50)
  87. # one existing registration for first ticket
  88. ticket1_reg1 = self.env['event.registration'].create({
  89. 'event_id': self.event_0.id,
  90. 'event_ticket_id': ticket1.id,
  91. 'partner_id': self.event_customer2.id,
  92. 'sale_order_id': customer_so.id,
  93. 'sale_order_line_id': ticket1_line.id,
  94. })
  95. self.assertEqual(ticket1_reg1.partner_id, self.event_customer)
  96. for field in ['name', 'email', 'phone', 'mobile']:
  97. self.assertEqual(ticket1_reg1[field], self.event_customer[field])
  98. # EVENT REGISTRATION EDITOR
  99. # ------------------------------------------------------------
  100. # use event registration editor to create missing lines and update details
  101. editor = self.env['registration.editor'].with_context({
  102. 'default_sale_order_id': customer_so.id
  103. }).create({})
  104. self.assertEqual(len(editor.event_registration_ids), TICKET1_COUNT + TICKET2_COUNT)
  105. self.assertEqual(editor.sale_order_id, customer_so)
  106. self.assertEqual(editor.event_registration_ids.sale_order_line_id, ticket1_line | ticket2_line)
  107. # check line linked to existing registration (ticket1_reg1)
  108. ticket1_editor_reg1 = editor.event_registration_ids.filtered(lambda line: line.registration_id)
  109. for field in ['name', 'email', 'phone', 'mobile']:
  110. self.assertEqual(ticket1_editor_reg1[field], ticket1_reg1[field])
  111. # check new lines
  112. ticket1_editor_other = editor.event_registration_ids.filtered(lambda line: not line.registration_id and line.event_ticket_id == ticket1)
  113. self.assertEqual(len(ticket1_editor_other), 2)
  114. ticket2_editor_other = editor.event_registration_ids.filtered(lambda line: not line.registration_id and line.event_ticket_id == ticket2)
  115. self.assertEqual(len(ticket2_editor_other), 1)
  116. # update lines in editor and save them
  117. ticket1_editor_other[0].write({
  118. 'name': 'ManualEntry1',
  119. 'email': 'manual.email.1@test.example.com',
  120. 'phone': '+32456111111',
  121. })
  122. ticket1_editor_other[1].write({
  123. 'name': 'ManualEntry2',
  124. 'email': 'manual.email.2@test.example.com',
  125. 'mobile': '+32456222222',
  126. })
  127. self.assertFalse(editor.seats_available_insufficient)
  128. editor.action_make_registration()
  129. # check editor correctly created new registrations with information coming from it or SO as fallback
  130. self.assertEqual(len(self.event_0.registration_ids), TICKET1_COUNT + TICKET2_COUNT)
  131. new_registrations = self.event_0.registration_ids - ticket1_reg1
  132. self.assertEqual(new_registrations.sale_order_id, customer_so)
  133. ticket1_new_reg = new_registrations.filtered(lambda reg: reg.event_ticket_id == ticket1)
  134. ticket2_new_reg = new_registrations.filtered(lambda reg: reg.event_ticket_id == ticket2)
  135. self.assertEqual(len(ticket1_new_reg), 2)
  136. self.assertEqual(len(ticket2_new_reg), 1)
  137. self.assertEqual(
  138. set(ticket1_new_reg.mapped('name')),
  139. set(['ManualEntry1', 'ManualEntry2'])
  140. )
  141. self.assertEqual(
  142. set(ticket1_new_reg.mapped('email')),
  143. set(['manual.email.1@test.example.com', 'manual.email.2@test.example.com'])
  144. )
  145. self.assertEqual(
  146. set(ticket1_new_reg.mapped('phone')),
  147. set(['+32456111111', self.event_customer._phone_format(self.event_customer.phone)])
  148. )
  149. self.assertEqual(
  150. set(ticket1_new_reg.mapped('mobile')),
  151. set(['+32456222222', self.event_customer._phone_format(self.event_customer.mobile)])
  152. )
  153. for field in ['name', 'email']:
  154. self.assertEqual(ticket2_new_reg[field], self.event_customer[field])
  155. for field in ['phone', 'mobile']:
  156. self.assertEqual(ticket2_new_reg[field], self.event_customer._phone_format(self.event_customer[field]))
  157. # ADDING MANUAL LINES ON SO
  158. # ------------------------------------------------------------
  159. ticket2_line.write({'product_uom_qty': 3})
  160. # Whenever the quantity is modified the price is recomputed in function of the ticket,
  161. # so we reapply the wanted price.
  162. ticket2_line.write({'price_unit': 50})
  163. editor_action = customer_so.action_confirm()
  164. self.assertEqual(customer_so.state, 'sale')
  165. self.assertEqual(customer_so.amount_untaxed, TICKET1_COUNT * 10 + (TICKET2_COUNT + 2) * 50)
  166. # check confirm of SO correctly created new registrations with information coming from SO
  167. self.assertEqual(len(self.event_0.registration_ids), 6) # 3 for each ticket now
  168. new_registrations = self.event_0.registration_ids - (ticket1_reg1 | ticket1_new_reg | ticket2_new_reg)
  169. self.assertEqual(new_registrations.event_ticket_id, ticket2)
  170. self.assertEqual(new_registrations.partner_id, self.customer_so.partner_id)
  171. self.assertEqual(editor_action['type'], 'ir.actions.act_window')
  172. self.assertEqual(editor_action['res_model'], 'registration.editor')
  173. @users('user_sales_salesman')
  174. def test_event_sale_free_confirm(self):
  175. """Check that even with the event's `no_confirm`, free registrations are immediately
  176. confirmed if the seats are available.
  177. """
  178. TICKET_COUNT = 3
  179. customer_so = self.customer_so.with_user(self.env.user)
  180. ticket = self.event_0.event_ticket_ids[0]
  181. # Limiting seats
  182. self.event_0.write({
  183. "auto_confirm": False,
  184. "seats_limited": True,
  185. "seats_max": 5
  186. })
  187. customer_so.write({
  188. 'order_line': [
  189. (0, 0, {
  190. 'event_id': self.event_0.id,
  191. 'event_ticket_id': ticket.id,
  192. 'product_id': ticket.product_id.id,
  193. 'product_uom_qty': TICKET_COUNT,
  194. 'price_unit': 0,
  195. })
  196. ]
  197. })
  198. editor = self.env['registration.editor'].with_context({
  199. 'default_sale_order_id': customer_so.id
  200. }).create({})
  201. self.assertFalse(editor.seats_available_insufficient)
  202. editor.action_make_registration()
  203. self.assertEqual(len(self.event_0.registration_ids), TICKET_COUNT)
  204. self.assertTrue(all(reg.state == "open" for reg in self.event_0.registration_ids))
  205. @users('user_sales_salesman')
  206. def test_event_sale_free_full_event_no_confirm(self):
  207. """Check that even free registrations are not immediately confirmed if there are not
  208. enough seats available for the event.
  209. """
  210. TICKET_COUNT = 3
  211. customer_so = self.customer_so.with_user(self.env.user)
  212. ticket = self.event_0.event_ticket_ids[0]
  213. # Limiting event seats
  214. self.event_0.write({
  215. "auto_confirm": False,
  216. "seats_limited": True,
  217. "seats_max": 2
  218. })
  219. # adding too many tickets to SO in two different lines
  220. customer_so.write({
  221. 'order_line': [
  222. (0, 0, {
  223. 'event_id': self.event_0.id,
  224. 'event_ticket_id': ticket.id,
  225. 'product_id': ticket.product_id.id,
  226. 'product_uom_qty': TICKET_COUNT - 1,
  227. 'price_unit': 0,
  228. }),
  229. (0, 0, {
  230. 'event_id': self.event_0.id,
  231. 'event_ticket_id': ticket.id,
  232. 'product_id': ticket.product_id.id,
  233. 'product_uom_qty': 1,
  234. 'price_unit': 0,
  235. })
  236. ]
  237. })
  238. editor = self.env['registration.editor'].with_context({
  239. 'default_sale_order_id': customer_so.id
  240. }).create({})
  241. self.assertTrue(editor.seats_available_insufficient)
  242. editor.action_make_registration()
  243. self.assertEqual(len(self.event_0.registration_ids), TICKET_COUNT)
  244. self.assertTrue(all(reg.state == "draft" for reg in self.event_0.registration_ids))
  245. @users('user_sales_salesman')
  246. def test_event_sale_free_full_ticket_no_confirm(self):
  247. """Check that even free registrations are not immediately confirmed if there are not enough
  248. seats available for the requested tickets.
  249. """
  250. TICKET_COUNT = 3
  251. customer_so = self.customer_so.with_user(self.env.user)
  252. ticket = self.event_0.event_ticket_ids[0]
  253. self.event_0.write({"auto_confirm": False})
  254. # Limiting ticket seats
  255. ticket.write({
  256. "seats_limited": True,
  257. "seats_max": 2,
  258. })
  259. # adding too many tickets to SO in two different lines
  260. customer_so.write({
  261. 'order_line': [
  262. (0, 0, {
  263. 'event_id': self.event_0.id,
  264. 'event_ticket_id': ticket.id,
  265. 'product_id': ticket.product_id.id,
  266. 'product_uom_qty': TICKET_COUNT - 1,
  267. 'price_unit': 0,
  268. }),
  269. (0, 0, {
  270. 'event_id': self.event_0.id,
  271. 'event_ticket_id': ticket.id,
  272. 'product_id': ticket.product_id.id,
  273. 'product_uom_qty': 1,
  274. 'price_unit': 0,
  275. })
  276. ]
  277. })
  278. editor = self.env['registration.editor'].with_context({
  279. 'default_sale_order_id': customer_so.id
  280. }).create({})
  281. self.assertTrue(editor.seats_available_insufficient)
  282. editor.action_make_registration()
  283. self.assertEqual(len(self.event_0.registration_ids), TICKET_COUNT)
  284. self.assertTrue(all(reg.state == "draft" for reg in self.event_0.registration_ids))
  285. def test_ticket_price_with_currency_conversion(self):
  286. def _prepare_currency(self, currency_name):
  287. currency = self.env['res.currency'].with_context(active_test=False).search(
  288. [('name', '=', currency_name)]
  289. )
  290. currency.action_unarchive()
  291. return currency
  292. currency_VEF = _prepare_currency(self, 'VEF')
  293. currency_USD = _prepare_currency(self, 'USD')
  294. company_test = self.env['res.company'].create({
  295. 'name': 'TestCompany',
  296. 'country_id': self.env.ref('base.be').id,
  297. 'currency_id': currency_USD.id,
  298. })
  299. self.env.user.company_ids += company_test
  300. self.env.user.company_id = company_test
  301. pricelist_USD = self.env['product.pricelist'].create({
  302. 'name': 'pricelist_USD',
  303. 'currency_id': currency_USD.id,
  304. })
  305. pricelist_VEF = self.env['product.pricelist'].create({
  306. 'name': 'pricelist_VEF',
  307. 'currency_id': currency_VEF.id,
  308. })
  309. event_product = self.env['product.template'].create({
  310. 'name': 'Event Product',
  311. 'list_price': 10.0,
  312. 'taxes_id': False,
  313. })
  314. event = self.env['event.event'].create({
  315. 'name': 'New Event',
  316. 'date_begin': '2020-02-02',
  317. 'date_end': '2020-04-04',
  318. })
  319. event_ticket = self.env['event.event.ticket'].create({
  320. 'name': 'VIP',
  321. 'price': 1000.0,
  322. 'event_id': event.id,
  323. 'product_id': event_product.product_variant_id.id,
  324. })
  325. so = self.env['sale.order'].create({
  326. 'partner_id': self.env.user.partner_id.id,
  327. 'pricelist_id': pricelist_USD.id,
  328. })
  329. self.env['sale.order.line'].create({
  330. 'product_id': event_product.product_variant_id.id,
  331. 'order_id': so.id,
  332. 'event_id': event.id,
  333. 'event_ticket_id': event_ticket.id,
  334. })
  335. self.assertEqual(so.amount_total, event_ticket.price)
  336. so.pricelist_id = pricelist_VEF
  337. so.action_update_prices()
  338. self.assertAlmostEqual(
  339. so.amount_total,
  340. currency_USD._convert(
  341. event_ticket.price, currency_VEF, self.env.user.company_id, so.date_order
  342. ),
  343. delta=1,
  344. )
  345. def test_ticket_price_with_pricelist_and_tax(self):
  346. self.env.user.partner_id.country_id = False
  347. pricelist = self.env['product.pricelist'].search([], limit=1)
  348. tax = self.env['account.tax'].create({
  349. 'name': "Tax 10",
  350. 'amount': 10,
  351. })
  352. event_product = self.env['product.template'].create({
  353. 'name': 'Event Product',
  354. 'list_price': 10.0,
  355. })
  356. event_product.taxes_id = tax
  357. event = self.env['event.event'].create({
  358. 'name': 'New Event',
  359. 'date_begin': '2020-02-02',
  360. 'date_end': '2020-04-04',
  361. })
  362. event_ticket = self.env['event.event.ticket'].create({
  363. 'name': 'VIP',
  364. 'price': 1000.0,
  365. 'event_id': event.id,
  366. 'product_id': event_product.product_variant_id.id,
  367. })
  368. pricelist.item_ids = self.env['product.pricelist.item'].create({
  369. 'applied_on': "1_product",
  370. 'base': "list_price",
  371. 'compute_price': "fixed",
  372. 'fixed_price': 6.0,
  373. 'product_tmpl_id': event_product.id,
  374. })
  375. pricelist.discount_policy = 'without_discount'
  376. so = self.env['sale.order'].create({
  377. 'partner_id': self.env.user.partner_id.id,
  378. 'pricelist_id': pricelist.id,
  379. })
  380. sol = self.env['sale.order.line'].create({
  381. 'product_id': event_product.product_variant_id.id,
  382. 'order_id': so.id,
  383. 'event_id': event.id,
  384. 'event_ticket_id': event_ticket.id,
  385. })
  386. self.assertEqual(so.amount_total, 660.0, "Ticket is $1000 but the event product is on a pricelist 10 -> 6. So, $600 + a 10% tax.")
  387. @users('user_salesman')
  388. def test_unlink_so(self):
  389. """ This test ensures that when deleting a sale order, if the latter is linked to an event registration,
  390. the number of expected seats will be correctly updated """
  391. event = self.env['event.event'].browse(self.event_0.ids)
  392. self.register_person.action_make_registration()
  393. self.assertEqual(event.seats_expected, 1)
  394. self.sale_order.unlink()
  395. self.assertEqual(event.seats_expected, 0)
  396. @users('user_salesman')
  397. def test_unlink_soline(self):
  398. """ This test ensures that when deleting a sale order line, if the latter is linked to an event registration,
  399. the number of expected seats will be correctly updated """
  400. event = self.env['event.event'].browse(self.event_0.ids)
  401. self.register_person.action_make_registration()
  402. self.assertEqual(event.seats_expected, 1)
  403. self.sale_order.order_line.unlink()
  404. self.assertEqual(event.seats_expected, 0)
  405. @users('user_salesman')
  406. def test_cancel_so(self):
  407. """ This test ensures that when canceling a sale order, if the latter is linked to an event registration,
  408. the number of expected seats will be correctly updated """
  409. event = self.env['event.event'].browse(self.event_0.ids)
  410. self.register_person.action_make_registration()
  411. self.assertEqual(event.seats_expected, 1)
  412. self.sale_order._action_cancel()
  413. self.assertEqual(event.seats_expected, 0)