test_valuation_layers.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. """ Implementation of "INVENTORY VALUATION TESTS (With valuation layers)" spreadsheet. """
  4. from odoo.addons.stock_account.tests.test_stockvaluationlayer import TestStockValuationCommon
  5. from odoo.tests import Form
  6. class TestMrpValuationCommon(TestStockValuationCommon):
  7. @classmethod
  8. def setUpClass(cls):
  9. super(TestMrpValuationCommon, cls).setUpClass()
  10. cls.component_category = cls.env['product.category'].create(
  11. {'name': 'category2'}
  12. )
  13. cls.component = cls.env['product.product'].create({
  14. 'name': 'component1',
  15. 'type': 'product',
  16. 'categ_id': cls.component_category.id,
  17. })
  18. cls.bom = cls.env['mrp.bom'].create({
  19. 'product_id': cls.product1.id,
  20. 'product_tmpl_id': cls.product1.product_tmpl_id.id,
  21. 'product_uom_id': cls.uom_unit.id,
  22. 'product_qty': 1.0,
  23. 'type': 'normal',
  24. 'bom_line_ids': [
  25. (0, 0, {'product_id': cls.component.id, 'product_qty': 1})
  26. ]})
  27. def _make_mo(self, bom, quantity=1):
  28. mo_form = Form(self.env['mrp.production'])
  29. mo_form.product_id = bom.product_id
  30. mo_form.bom_id = bom
  31. mo_form.product_qty = quantity
  32. mo = mo_form.save()
  33. mo.action_confirm()
  34. return mo
  35. def _produce(self, mo, quantity=0):
  36. mo_form = Form(mo)
  37. if not quantity:
  38. quantity = mo.product_qty - mo.qty_produced
  39. mo_form.qty_producing += quantity
  40. mo = mo_form.save()
  41. class TestMrpValuationStandard(TestMrpValuationCommon):
  42. def test_fifo_fifo_1(self):
  43. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  44. self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  45. self._make_in_move(self.component, 1, 10)
  46. self._make_in_move(self.component, 1, 20)
  47. mo = self._make_mo(self.bom, 2)
  48. self._produce(mo, 1)
  49. action = mo.button_mark_done()
  50. backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
  51. backorder.save().action_backorder()
  52. mo = mo.procurement_group_id.mrp_production_ids[-1]
  53. self.assertEqual(self.component.value_svl, 20)
  54. self.assertEqual(self.product1.value_svl, 10)
  55. self.assertEqual(self.component.quantity_svl, 1)
  56. self.assertEqual(self.product1.quantity_svl, 1)
  57. self._produce(mo)
  58. mo.button_mark_done()
  59. self.assertEqual(self.component.value_svl, 0)
  60. self.assertEqual(self.product1.value_svl, 30)
  61. self.assertEqual(self.component.quantity_svl, 0)
  62. self.assertEqual(self.product1.quantity_svl, 2)
  63. def test_fifo_fifo_2(self):
  64. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  65. self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  66. self._make_in_move(self.component, 1, 10)
  67. self._make_in_move(self.component, 1, 20)
  68. mo = self._make_mo(self.bom, 2)
  69. self._produce(mo)
  70. mo.button_mark_done()
  71. self.assertEqual(self.component.value_svl, 0)
  72. self.assertEqual(self.product1.value_svl, 30)
  73. self.assertEqual(self.component.quantity_svl, 0)
  74. self.assertEqual(self.product1.quantity_svl, 2)
  75. self._make_out_move(self.product1, 1)
  76. self.assertEqual(self.product1.value_svl, 15)
  77. def test_fifo_byproduct(self):
  78. """ Check that a MO byproduct with a cost share calculates correct svl """
  79. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  80. self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  81. self._make_in_move(self.component, 1, 10)
  82. self._make_in_move(self.component, 1, 20)
  83. # add byproduct
  84. byproduct_cost_share = 10
  85. byproduct = self.env['product.product'].create({
  86. 'name': 'byproduct',
  87. 'type': 'product',
  88. 'categ_id': self.product1.product_tmpl_id.categ_id.id,
  89. })
  90. self.bom.write({
  91. 'byproduct_ids': [(0, 0, {'product_id': byproduct.id, 'product_uom_id': self.uom_unit.id, 'product_qty': 1, 'cost_share': byproduct_cost_share})]
  92. })
  93. mo = self._make_mo(self.bom, 2)
  94. self._produce(mo, 1)
  95. action = mo.button_mark_done()
  96. backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
  97. backorder.save().action_backorder()
  98. mo = mo.procurement_group_id.mrp_production_ids[-1]
  99. self.assertEqual(self.component.value_svl, 20)
  100. self.assertEqual(self.product1.value_svl, 10 * (100 - byproduct_cost_share) / 100)
  101. self.assertEqual(byproduct.value_svl, 10 * byproduct_cost_share / 100)
  102. self.assertEqual(self.component.quantity_svl, 1)
  103. self.assertEqual(self.product1.quantity_svl, 1)
  104. self.assertEqual(byproduct.quantity_svl, 1)
  105. self._produce(mo)
  106. mo.button_mark_done()
  107. self.assertEqual(self.component.value_svl, 0)
  108. self.assertEqual(self.product1.value_svl, 30 * (100 - byproduct_cost_share) / 100)
  109. self.assertEqual(byproduct.value_svl, 30 * byproduct_cost_share / 100)
  110. self.assertEqual(self.component.quantity_svl, 0)
  111. self.assertEqual(self.product1.quantity_svl, 2)
  112. self.assertEqual(byproduct.quantity_svl, 2)
  113. def test_fifo_unbuild(self):
  114. """ This test creates an MO and then creates an unbuild
  115. orders and checks the stock valuation.
  116. """
  117. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  118. # ---------------------------------------------------
  119. # MO
  120. # ---------------------------------------------------
  121. self._make_in_move(self.component, 1, 10)
  122. self._make_in_move(self.component, 1, 20)
  123. mo = self._make_mo(self.bom, 1)
  124. self._produce(mo)
  125. mo.button_mark_done()
  126. self.assertEqual(self.component.value_svl, 20)
  127. # ---------------------------------------------------
  128. # Unbuild
  129. # ---------------------------------------------------
  130. unbuild_form = Form(self.env['mrp.unbuild'])
  131. unbuild_form.mo_id = mo
  132. unbuild_form.save().action_unbuild()
  133. self.assertEqual(self.component.value_svl, 30)
  134. def test_fifo_avco_1(self):
  135. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  136. self.product1.product_tmpl_id.categ_id.property_cost_method = 'average'
  137. self._make_in_move(self.component, 1, 10)
  138. self._make_in_move(self.component, 1, 20)
  139. mo = self._make_mo(self.bom, 2)
  140. self._produce(mo, 1)
  141. action = mo.button_mark_done()
  142. backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
  143. backorder.save().action_backorder()
  144. mo = mo.procurement_group_id.mrp_production_ids[-1]
  145. self.assertEqual(self.component.value_svl, 20)
  146. self.assertEqual(self.product1.value_svl, 10)
  147. self.assertEqual(self.component.quantity_svl, 1)
  148. self.assertEqual(self.product1.quantity_svl, 1)
  149. self._produce(mo)
  150. mo.button_mark_done()
  151. self.assertEqual(self.component.value_svl, 0)
  152. self.assertEqual(self.product1.value_svl, 30)
  153. self.assertEqual(self.component.quantity_svl, 0)
  154. self.assertEqual(self.product1.quantity_svl, 2)
  155. def test_fifo_avco_2(self):
  156. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  157. self.product1.product_tmpl_id.categ_id.property_cost_method = 'average'
  158. self._make_in_move(self.component, 1, 10)
  159. self._make_in_move(self.component, 1, 20)
  160. mo = self._make_mo(self.bom, 2)
  161. self._produce(mo)
  162. mo.button_mark_done()
  163. self.assertEqual(self.component.value_svl, 0)
  164. self.assertEqual(self.product1.value_svl, 30)
  165. self.assertEqual(self.component.quantity_svl, 0)
  166. self.assertEqual(self.product1.quantity_svl, 2)
  167. self._make_out_move(self.product1, 1)
  168. self.assertEqual(self.product1.value_svl, 15)
  169. def test_fifo_std_1(self):
  170. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  171. self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard'
  172. self.product1.standard_price = 8.8
  173. self._make_in_move(self.component, 1, 10)
  174. self._make_in_move(self.component, 1, 20)
  175. mo = self._make_mo(self.bom, 2)
  176. self._produce(mo, 1)
  177. mo._post_inventory()
  178. self.assertEqual(self.component.value_svl, 20)
  179. self.assertEqual(self.product1.value_svl, 8.8)
  180. self.assertEqual(self.component.quantity_svl, 1)
  181. self.assertEqual(self.product1.quantity_svl, 1)
  182. self._produce(mo)
  183. mo.button_mark_done()
  184. self.assertEqual(self.component.value_svl, 0)
  185. self.assertEqual(self.product1.value_svl, 8.8 * 2)
  186. self.assertEqual(self.component.quantity_svl, 0)
  187. self.assertEqual(self.product1.quantity_svl, 2)
  188. def test_fifo_std_2(self):
  189. self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo'
  190. self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard'
  191. self.product1.standard_price = 8.8
  192. self._make_in_move(self.component, 1, 10)
  193. self._make_in_move(self.component, 1, 20)
  194. mo = self._make_mo(self.bom, 2)
  195. self._produce(mo)
  196. mo.button_mark_done()
  197. self.assertEqual(self.component.value_svl, 0)
  198. self.assertEqual(self.product1.value_svl, 8.8 * 2)
  199. self.assertEqual(self.component.quantity_svl, 0)
  200. self.assertEqual(self.product1.quantity_svl, 2)
  201. self._make_out_move(self.product1, 1)
  202. self.assertEqual(self.product1.value_svl, 8.8)
  203. def test_std_avco_1(self):
  204. self.component.product_tmpl_id.categ_id.property_cost_method = 'standard'
  205. self.product1.product_tmpl_id.categ_id.property_cost_method = 'average'
  206. self.component.standard_price = 8.8
  207. self._make_in_move(self.component, 1)
  208. self._make_in_move(self.component, 1)
  209. mo = self._make_mo(self.bom, 2)
  210. self._produce(mo, 1)
  211. mo._post_inventory()
  212. self.assertEqual(self.component.value_svl, 8.8)
  213. self.assertEqual(self.product1.value_svl, 8.8)
  214. self.assertEqual(self.component.quantity_svl, 1)
  215. self.assertEqual(self.product1.quantity_svl, 1)
  216. self._produce(mo)
  217. mo.button_mark_done()
  218. self.assertEqual(self.component.value_svl, 0)
  219. self.assertEqual(self.product1.value_svl, 8.8 * 2)
  220. self.assertEqual(self.component.quantity_svl, 0)
  221. self.assertEqual(self.product1.quantity_svl, 2)
  222. def test_std_avco_2(self):
  223. self.component.product_tmpl_id.categ_id.property_cost_method = 'standard'
  224. self.product1.product_tmpl_id.categ_id.property_cost_method = 'average'
  225. self.component.standard_price = 8.8
  226. self._make_in_move(self.component, 1)
  227. self._make_in_move(self.component, 1)
  228. mo = self._make_mo(self.bom, 2)
  229. self._produce(mo)
  230. mo.button_mark_done()
  231. self.assertEqual(self.component.value_svl, 0)
  232. self.assertEqual(self.product1.value_svl, 8.8 * 2)
  233. self.assertEqual(self.component.quantity_svl, 0)
  234. self.assertEqual(self.product1.quantity_svl, 2)
  235. self.assertEqual(self.product1.standard_price, 8.8)
  236. self._make_out_move(self.product1, 1)
  237. self.assertEqual(self.product1.value_svl, 8.8)
  238. # Update component price
  239. self.component.standard_price = 0
  240. self._make_in_move(self.component, 3)
  241. mo = self._make_mo(self.bom, 3)
  242. self._produce(mo)
  243. mo.button_mark_done()
  244. self.assertEqual(self.product1.value_svl, 8.8)
  245. self.assertEqual(self.product1.quantity_svl, 4)
  246. self.assertEqual(self.product1.standard_price, 2.2)
  247. def test_std_std_1(self):
  248. self.component.product_tmpl_id.categ_id.property_cost_method = 'standard'
  249. self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard'
  250. self.component.standard_price = 8.8
  251. self.product1.standard_price = 7.2
  252. self._make_in_move(self.component, 1)
  253. self._make_in_move(self.component, 1)
  254. mo = self._make_mo(self.bom, 2)
  255. self._produce(mo, 1)
  256. mo._post_inventory()
  257. self.assertEqual(self.component.value_svl, 8.8)
  258. self.assertEqual(self.product1.value_svl, 7.2)
  259. self.assertEqual(self.component.quantity_svl, 1)
  260. self.assertEqual(self.product1.quantity_svl, 1)
  261. self._produce(mo)
  262. mo.button_mark_done()
  263. self.assertEqual(self.component.value_svl, 0)
  264. self.assertEqual(self.product1.value_svl, 7.2 * 2)
  265. self.assertEqual(self.component.quantity_svl, 0)
  266. self.assertEqual(self.product1.quantity_svl, 2)
  267. def test_std_std_2(self):
  268. self.component.product_tmpl_id.categ_id.property_cost_method = 'standard'
  269. self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard'
  270. self.component.standard_price = 8.8
  271. self.product1.standard_price = 7.2
  272. self._make_in_move(self.component, 1)
  273. self._make_in_move(self.component, 1)
  274. mo = self._make_mo(self.bom, 2)
  275. self._produce(mo)
  276. mo.button_mark_done()
  277. self.assertEqual(self.component.value_svl, 0)
  278. self.assertEqual(self.product1.value_svl, 7.2 * 2)
  279. self.assertEqual(self.component.quantity_svl, 0)
  280. self.assertEqual(self.product1.quantity_svl, 2)
  281. self._make_out_move(self.product1, 1)
  282. self.assertEqual(self.product1.value_svl, 7.2)
  283. def test_avco_avco_1(self):
  284. self.component.product_tmpl_id.categ_id.property_cost_method = 'average'
  285. self.product1.product_tmpl_id.categ_id.property_cost_method = 'average'
  286. self._make_in_move(self.component, 1, 10)
  287. self._make_in_move(self.component, 1, 20)
  288. mo = self._make_mo(self.bom, 2)
  289. self._produce(mo, 1)
  290. mo._post_inventory()
  291. self.assertEqual(self.component.value_svl, 15)
  292. self.assertEqual(self.product1.value_svl, 15)
  293. self.assertEqual(self.component.quantity_svl, 1)
  294. self.assertEqual(self.product1.quantity_svl, 1)
  295. self._produce(mo)
  296. mo.button_mark_done()
  297. self.assertEqual(self.component.value_svl, 0)
  298. self.assertEqual(self.product1.value_svl, 30)
  299. self.assertEqual(self.component.quantity_svl, 0)
  300. self.assertEqual(self.product1.quantity_svl, 2)
  301. def test_avco_avco_2(self):
  302. self.component.product_tmpl_id.categ_id.property_cost_method = 'average'
  303. self.product1.product_tmpl_id.categ_id.property_cost_method = 'average'
  304. self._make_in_move(self.component, 1, 10)
  305. self._make_in_move(self.component, 1, 20)
  306. mo = self._make_mo(self.bom, 2)
  307. self._produce(mo)
  308. mo.button_mark_done()
  309. self.assertEqual(self.component.value_svl, 0)
  310. self.assertEqual(self.product1.value_svl, 30)
  311. self.assertEqual(self.component.quantity_svl, 0)
  312. self.assertEqual(self.product1.quantity_svl, 2)
  313. self._make_out_move(self.product1, 1)
  314. self.assertEqual(self.product1.value_svl, 15)
  315. def test_validate_draft_kit(self):
  316. """
  317. Create a draft receipt, add a kit to its move lines and directly
  318. validate it. From client side, such a behaviour is possible with
  319. the Barcode app.
  320. """
  321. self.component.product_tmpl_id.categ_id.property_cost_method = 'average'
  322. self.product1.type = 'consu'
  323. self.bom.type = 'phantom'
  324. self.component.standard_price = 1424
  325. receipt = self.env['stock.picking'].create({
  326. 'location_id': self.customer_location.id,
  327. 'location_dest_id': self.stock_location.id,
  328. 'picking_type_id': self.picking_type_in.id,
  329. 'move_line_ids': [(0, 0, {
  330. 'product_id': self.product1.id,
  331. 'qty_done': 1,
  332. 'product_uom_id': self.product1.uom_id.id,
  333. 'location_id': self.customer_location.id,
  334. 'location_dest_id': self.stock_location.id,
  335. })]
  336. })
  337. receipt.button_validate()
  338. self.assertEqual(receipt.state, 'done')
  339. self.assertRecordValues(receipt.move_ids, [
  340. {'product_id': self.component.id, 'quantity_done': 1, 'state': 'done'},
  341. ])
  342. self.assertEqual(self.component.qty_available, 1)
  343. self.assertEqual(self.component.value_svl, 1424)