odoo-addon-project-task-stock 18.0.1.0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. odoo/addons/project_task_stock/README.rst +146 -0
  2. odoo/addons/project_task_stock/__init__.py +1 -0
  3. odoo/addons/project_task_stock/__manifest__.py +24 -0
  4. odoo/addons/project_task_stock/demo/project_data.xml +28 -0
  5. odoo/addons/project_task_stock/demo/stock_picking_type_data.xml +11 -0
  6. odoo/addons/project_task_stock/i18n/es.po +337 -0
  7. odoo/addons/project_task_stock/i18n/fr.po +337 -0
  8. odoo/addons/project_task_stock/i18n/hr.po +345 -0
  9. odoo/addons/project_task_stock/i18n/it.po +344 -0
  10. odoo/addons/project_task_stock/i18n/project_task_stock.pot +329 -0
  11. odoo/addons/project_task_stock/i18n/pt_BR.po +345 -0
  12. odoo/addons/project_task_stock/models/__init__.py +7 -0
  13. odoo/addons/project_task_stock/models/account_analytic_line.py +21 -0
  14. odoo/addons/project_task_stock/models/project_project.py +45 -0
  15. odoo/addons/project_task_stock/models/project_task.py +279 -0
  16. odoo/addons/project_task_stock/models/stock_move.py +135 -0
  17. odoo/addons/project_task_stock/models/stock_scrap.py +25 -0
  18. odoo/addons/project_task_stock/readme/CONFIGURE.md +25 -0
  19. odoo/addons/project_task_stock/readme/CONTRIBUTORS.md +3 -0
  20. odoo/addons/project_task_stock/readme/DESCRIPTION.md +1 -0
  21. odoo/addons/project_task_stock/readme/USAGE.md +21 -0
  22. odoo/addons/project_task_stock/static/description/icon.png +0 -0
  23. odoo/addons/project_task_stock/static/description/index.html +485 -0
  24. odoo/addons/project_task_stock/tests/__init__.py +4 -0
  25. odoo/addons/project_task_stock/tests/common.py +100 -0
  26. odoo/addons/project_task_stock/tests/test_project_task_stock.py +350 -0
  27. odoo/addons/project_task_stock/views/project_project_view.xml +24 -0
  28. odoo/addons/project_task_stock/views/project_task_type_view.xml +14 -0
  29. odoo/addons/project_task_stock/views/project_task_view.xml +142 -0
  30. odoo/addons/project_task_stock/views/stock_move_view.xml +65 -0
  31. odoo/addons/project_task_stock/views/stock_scrap_views.xml +13 -0
  32. odoo_addon_project_task_stock-18.0.1.0.0.2.dist-info/METADATA +161 -0
  33. odoo_addon_project_task_stock-18.0.1.0.0.2.dist-info/RECORD +35 -0
  34. odoo_addon_project_task_stock-18.0.1.0.0.2.dist-info/WHEEL +5 -0
  35. odoo_addon_project_task_stock-18.0.1.0.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,350 @@
1
+ # Copyright 2022-2025 Tecnativa - Víctor Martínez
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+ from odoo import fields
4
+ from odoo.tests import Form
5
+ from odoo.tests.common import users
6
+ from odoo.tools import mute_logger
7
+
8
+ from .common import TestProjectStockBase
9
+
10
+
11
+ class TestProjectTaskStock(TestProjectStockBase):
12
+ @classmethod
13
+ def setUpClass(cls):
14
+ super().setUpClass()
15
+ cls.quant_a = cls._create_stock_quant(cls.product_a, cls.location, 2)
16
+ cls.quant_b = cls._create_stock_quant(cls.product_b, cls.location, 1)
17
+ cls._create_stock_quant(cls.product_c, cls.location, 1)
18
+ cls.task = cls._create_task([(cls.product_a, 2), (cls.product_b, 1)])
19
+ cls.move_product_a = cls.task.move_ids.filtered(
20
+ lambda x: x.product_id == cls.product_a
21
+ )
22
+ cls.move_product_b = cls.task.move_ids.filtered(
23
+ lambda x: x.product_id == cls.product_b
24
+ )
25
+ cls.env.ref("base.user_admin").write(
26
+ {
27
+ "groups_id": [
28
+ (4, cls.env.ref("analytic.group_analytic_accounting").id),
29
+ ],
30
+ }
31
+ )
32
+
33
+ @classmethod
34
+ def _create_stock_quant(cls, product, location, qty):
35
+ return cls.env["stock.quant"].create(
36
+ {"product_id": product.id, "location_id": location.id, "quantity": qty}
37
+ )
38
+
39
+ def test_project_task_misc(self):
40
+ self.assertTrue(self.task.group_id)
41
+ self.assertEqual(self.task.picking_type_id, self.picking_type)
42
+ self.assertEqual(self.task.location_id, self.location)
43
+ self.assertEqual(self.task.location_dest_id, self.location_dest)
44
+ self.assertEqual(self.move_product_a.name, self.task.name)
45
+ self.assertEqual(self.move_product_a.group_id, self.task.group_id)
46
+ self.assertEqual(self.move_product_a.reference, self.task.name)
47
+ self.assertEqual(self.move_product_a.location_id, self.location)
48
+ self.assertEqual(self.move_product_a.location_dest_id, self.location_dest)
49
+ self.assertEqual(self.move_product_a.picking_type_id, self.picking_type)
50
+ self.assertEqual(self.move_product_a.raw_material_task_id, self.task)
51
+ self.assertEqual(self.move_product_b.group_id, self.task.group_id)
52
+ self.assertEqual(self.move_product_b.location_id, self.location)
53
+ self.assertEqual(self.move_product_b.location_dest_id, self.location_dest)
54
+ self.assertEqual(self.move_product_b.picking_type_id, self.picking_type)
55
+ self.assertEqual(self.move_product_b.raw_material_task_id, self.task)
56
+
57
+ def _test_task_analytic_lines_from_task(self, amount):
58
+ self.task = self.env["project.task"].browse(self.task.id)
59
+ # Prevent error when hr_timesheet addon is installed.
60
+ stock_analytic_lines = self.task.sudo().stock_analytic_line_ids
61
+ self.assertEqual(len(stock_analytic_lines), 2)
62
+ self.assertEqual(sum(stock_analytic_lines.mapped("unit_amount")), 3)
63
+ self.assertEqual(sum(stock_analytic_lines.mapped("amount")), amount)
64
+ self.assertIn(
65
+ self.analytic_account,
66
+ stock_analytic_lines.mapped("account_id"),
67
+ )
68
+ # Prevent incoherence when hr_timesheet addon is installed.
69
+ if "project_id" in self.task.stock_analytic_line_ids._fields:
70
+ self.assertFalse(self.task.stock_analytic_line_ids.project_id)
71
+
72
+ def test_project_task_without_analytic_account(self):
73
+ self.task = self.env["project.task"].browse(self.task.id)
74
+ # Prevent error when hr_timesheet addon is installed.
75
+ if "allow_timesheets" in self.task.project_id._fields:
76
+ self.task.project_id.allow_timesheets = False
77
+ self.task.project_id.account_id = False
78
+ self.task.write({"stage_id": self.stage_done.id})
79
+ self.task.action_done()
80
+ self.assertFalse(self.task.sudo().stock_analytic_line_ids)
81
+
82
+ @users("manager-user")
83
+ def test_project_task_without_analytic_account_manager_user(self):
84
+ self.test_project_task_without_analytic_account()
85
+
86
+ def test_project_task_user_access_without_stock_group(self):
87
+ project_user_group = self.env.ref("project.group_project_user")
88
+ self.basic_user.write(
89
+ {
90
+ "groups_id": [(6, 0, [project_user_group.id])],
91
+ }
92
+ )
93
+ task_form = Form(self.task.with_user(self.basic_user))
94
+ self.assertEqual(task_form.project_id, self.project)
95
+
96
+ def test_project_task_analytic_lines_without_tags(self):
97
+ self.task = self.env["project.task"].browse(self.task.id)
98
+ self.task.write({"stage_id": self.stage_done.id})
99
+ self.task.action_done()
100
+ self._test_task_analytic_lines_from_task(-40)
101
+ self.assertEqual(
102
+ fields.first(self.task.stock_analytic_line_ids).date,
103
+ fields.Date.from_string("1990-01-01"),
104
+ )
105
+
106
+ @users("manager-user")
107
+ def test_project_task_analytic_lines_without_tags_manager_user(self):
108
+ self.test_project_task_analytic_lines_without_tags()
109
+
110
+ def test_project_task_analytic_lines_with_tag_1(self):
111
+ self.task = self.env["project.task"].browse(self.task.id)
112
+ self.task.write({"stock_analytic_date": "1991-01-01"})
113
+ self.task.write({"stage_id": self.stage_done.id})
114
+ self.task.action_done()
115
+ self._test_task_analytic_lines_from_task(-40)
116
+ self.assertEqual(
117
+ fields.first(self.task.stock_analytic_line_ids).date,
118
+ fields.Date.from_string("1991-01-01"),
119
+ )
120
+
121
+ @users("manager-user")
122
+ def test_project_task_analytic_lines_with_tag_1_manager_user(self):
123
+ self.task.stock_analytic_distribution = {self.analytic_account.id: 100}
124
+ self.test_project_task_analytic_lines_with_tag_1()
125
+
126
+ def test_project_task_analytic_lines_with_tag_2(self):
127
+ self.task = self.env["project.task"].browse(self.task.id)
128
+ self.task.project_id.stock_analytic_date = False
129
+ self.task.write({"stage_id": self.stage_done.id})
130
+ self.task.action_done()
131
+ self._test_task_analytic_lines_from_task(-40)
132
+ self.assertEqual(
133
+ fields.first(self.task.stock_analytic_line_ids).date, fields.date.today()
134
+ )
135
+
136
+ @users("manager-user")
137
+ def test_project_task_analytic_lines_with_tag_2_manager_user(self):
138
+ self.task.stock_analytic_distribution = {
139
+ self.analytic_account.id: 50,
140
+ self.analytic_account_2.id: 50,
141
+ }
142
+ self.test_project_task_analytic_lines_with_tag_2()
143
+
144
+ def test_project_task_process_done(self):
145
+ self.task = self.env["project.task"].browse(self.task.id)
146
+ self.assertEqual(self.move_product_a.state, "draft")
147
+ self.assertEqual(self.move_product_b.state, "draft")
148
+ # Change task stage (auto-confirm + auto-assign)
149
+ self.task.write({"stage_id": self.stage_done.id})
150
+ self.assertEqual(self.move_product_a.state, "assigned")
151
+ self.assertEqual(self.move_product_b.state, "assigned")
152
+ self.assertEqual(self.move_product_a.quantity, 2)
153
+ self.assertEqual(self.move_product_b.quantity, 1)
154
+ self.assertTrue(self.task.stock_moves_is_locked)
155
+ self.task.action_toggle_stock_moves_is_locked()
156
+ self.assertFalse(self.task.stock_moves_is_locked)
157
+ # Add new stock_move
158
+ self.task.write({"stage_id": self.stage_in_progress.id})
159
+ task_form = Form(self.task)
160
+ with task_form.move_ids.new() as move_form:
161
+ move_form.product_id = self.product_c
162
+ move_form.product_uom_qty = 1
163
+ task_form.save()
164
+ move_product_c = self.task.move_ids.filtered(
165
+ lambda x: x.product_id == self.product_c
166
+ )
167
+ self.assertEqual(move_product_c.group_id, self.task.group_id)
168
+ self.assertEqual(move_product_c.state, "draft")
169
+ self.task.action_assign()
170
+ self.assertEqual(move_product_c.state, "assigned")
171
+ self.task.write({"stage_id": self.stage_done.id})
172
+ # action_done
173
+ self.task.action_done()
174
+ self.assertEqual(self.move_product_a.state, "done")
175
+ self.assertEqual(self.move_product_b.state, "done")
176
+ self.assertEqual(self.move_product_a.quantity, 2)
177
+ self.assertEqual(self.move_product_b.quantity, 1)
178
+ self.assertEqual(move_product_c.quantity, 1)
179
+
180
+ @users("basic-user")
181
+ def test_project_task_process_done_basic_user(self):
182
+ self.test_project_task_process_done()
183
+
184
+ @mute_logger("odoo.models.unlink")
185
+ def test_project_task_process_cancel(self):
186
+ self.task = self.env["project.task"].browse(self.task.id)
187
+ self.assertEqual(self.move_product_a.state, "draft")
188
+ self.assertEqual(self.move_product_b.state, "draft")
189
+ # Change task stage
190
+ self.task.write({"stage_id": self.stage_done.id})
191
+ self.assertEqual(self.move_product_a.state, "assigned")
192
+ self.assertEqual(self.move_product_b.state, "assigned")
193
+ # action_done
194
+ self.task.action_done()
195
+ self.assertEqual(self.move_product_a.state, "done")
196
+ self.assertEqual(self.move_product_b.state, "done")
197
+ self.assertEqual(self.move_product_a.quantity, 2)
198
+ self.assertEqual(self.move_product_b.quantity, 1)
199
+ self.assertTrue(self.task.sudo().stock_analytic_line_ids)
200
+ # action_cancel
201
+ self.task.action_cancel()
202
+ self.assertEqual(self.move_product_a.state, "done")
203
+ self.assertEqual(self.move_product_b.state, "done")
204
+ self.assertEqual(self.move_product_a.quantity, 0)
205
+ self.assertEqual(self.move_product_b.quantity, 0)
206
+ self.assertFalse(self.task.sudo().stock_analytic_line_ids)
207
+ quant_a = self.product_a.stock_quant_ids.filtered(
208
+ lambda x: x.location_id == self.location
209
+ )
210
+ quant_b = self.product_b.stock_quant_ids.filtered(
211
+ lambda x: x.location_id == self.location
212
+ )
213
+ quant_c = self.product_c.stock_quant_ids.filtered(
214
+ lambda x: x.location_id == self.location
215
+ )
216
+ self.assertEqual(quant_a.quantity, 2)
217
+ self.assertEqual(quant_b.quantity, 1)
218
+ self.assertEqual(quant_c.quantity, 1)
219
+
220
+ @users("manager-user")
221
+ def test_project_task_process_cancel_manager_user(self):
222
+ self.test_project_task_process_cancel()
223
+
224
+ @mute_logger("odoo.models.unlink")
225
+ def test_project_task_process_unreserve(self):
226
+ self.task = self.env["project.task"].browse(self.task.id)
227
+ self.assertEqual(self.move_product_a.state, "draft")
228
+ self.assertEqual(self.move_product_b.state, "draft")
229
+ # Change task stage (auto-confirm + auto-assign)
230
+ self.task.write({"stage_id": self.stage_done.id})
231
+ self.assertTrue(self.move_product_a.move_line_ids)
232
+ self.assertEqual(self.move_product_a.move_line_ids.task_id, self.task)
233
+ self.assertEqual(self.move_product_a.state, "assigned")
234
+ self.assertEqual(self.move_product_b.state, "assigned")
235
+ self.assertEqual(self.move_product_a.quantity, 2)
236
+ self.assertEqual(self.move_product_b.quantity, 1)
237
+ self.assertTrue(self.task.unreserve_visible)
238
+ # button_unreserve
239
+ self.task.button_unreserve()
240
+ self.assertEqual(self.move_product_a.state, "confirmed")
241
+ self.assertEqual(self.move_product_b.state, "confirmed")
242
+ self.assertEqual(self.move_product_a.quantity, 0)
243
+ self.assertEqual(self.move_product_b.quantity, 0)
244
+ self.assertFalse(self.task.unreserve_visible)
245
+
246
+ @mute_logger("odoo.models.unlink")
247
+ def test_project_task_process_01(self):
248
+ """Product A move cancel + Product B move OK."""
249
+ self.task = self.env["project.task"].browse(self.task.id)
250
+ self.move_product_b.unlink()
251
+ self.assertEqual(self.move_product_a.state, "draft")
252
+ # Confirm + Edit to qty=0
253
+ self.task.action_confirm()
254
+ self.assertEqual(self.move_product_a.state, "assigned")
255
+ self.move_product_a.product_uom_qty = 0
256
+ self.task.action_done()
257
+ self.assertEqual(self.move_product_a.state, "cancel")
258
+ self.assertEqual(self.move_product_a.quantity, 0)
259
+ # Add extra line
260
+ task_form = Form(self.task)
261
+ with task_form.move_ids.new() as move_form:
262
+ move_form.product_id = self.product_b
263
+ move_form.product_uom_qty = 1
264
+ task_form.save()
265
+ self.move_product_b = self.task.move_ids.filtered(
266
+ lambda x: x.product_id == self.product_b
267
+ )
268
+ self.task.action_confirm()
269
+ self.assertEqual(self.move_product_b.state, "assigned")
270
+ self.task.action_done()
271
+ self.assertEqual(self.move_product_b.state, "done")
272
+ self.assertEqual(self.move_product_b.quantity, 1)
273
+
274
+ def test_project_task_process_02(self):
275
+ self.task.action_confirm()
276
+ self.assertEqual(self.move_product_a.state, "assigned")
277
+ self.assertEqual(self.move_product_b.state, "assigned")
278
+ self.task.action_done()
279
+ self.assertEqual(self.move_product_a.state, "done")
280
+ self.assertEqual(self.move_product_b.state, "done")
281
+ self.assertEqual(len(self.task.stock_analytic_line_ids), 2)
282
+ self.task.action_done()
283
+ self.assertEqual(len(self.task.stock_analytic_line_ids), 2)
284
+
285
+ @users("basic-user")
286
+ def test_project_task_process_unreserve_basic_user(self):
287
+ self.test_project_task_process_unreserve()
288
+
289
+ def test_project_task_action_cancel(self):
290
+ self.assertTrue(self.env["project.task"].browse(self.task.id).action_cancel())
291
+
292
+ @users("basic-user")
293
+ def test_project_task_action_cancel_basic_user(self):
294
+ self.test_project_task_action_cancel()
295
+
296
+ def test_project_task_action_done(self):
297
+ self.task = self.env["project.task"].browse(self.task.id)
298
+ self.task.write({"stage_id": self.stage_done.id})
299
+ self.task.action_done()
300
+ self.assertTrue(self.task.sudo().stock_analytic_line_ids)
301
+
302
+ @users("basic-user")
303
+ def test_project_task_action_done_basic_user(self):
304
+ self.test_project_task_action_done()
305
+
306
+ @mute_logger("odoo.models.unlink")
307
+ def test_project_task_unlink(self):
308
+ self.assertTrue(self.env["project.task"].browse(self.task.id).unlink())
309
+
310
+ @users("basic-user")
311
+ def test_project_task_unlink_basic_user(self):
312
+ self.test_project_task_unlink()
313
+
314
+ @mute_logger("odoo.models.unlink")
315
+ def test_project_project_onchange(self):
316
+ # We do the unreserve first + unlink the quants, otherwise, changing the
317
+ # picking_type_id with the _onchange_picking_type_id() method will change
318
+ # the status of the stock move to "assigned" showing the error of the
319
+ # _check_tasks_with_pending_moves() method.
320
+ self.task.do_unreserve()
321
+ self.quant_a.unlink()
322
+ self.quant_b.unlink()
323
+ new_type = self.env.ref("stock.picking_type_out")
324
+ self.project.write({"picking_type_id": new_type.id})
325
+ self.project._onchange_picking_type_id()
326
+ self.assertEqual(self.project.location_id, new_type.default_location_src_id)
327
+ self.assertEqual(
328
+ self.project.location_dest_id, new_type.default_location_dest_id
329
+ )
330
+ self.task.write({"picking_type_id": new_type.id})
331
+ self.task._onchange_picking_type_id()
332
+ self.assertEqual(self.task.location_id, new_type.default_location_src_id)
333
+ self.assertEqual(self.task.location_dest_id, new_type.default_location_dest_id)
334
+ move = fields.first(self.task.move_ids)
335
+ self.assertEqual(move.location_id, new_type.default_location_src_id)
336
+
337
+ def test_project_task_scrap(self):
338
+ move = fields.first(self.task.move_ids)
339
+ scrap = self.env["stock.scrap"].create(
340
+ {
341
+ "product_id": move.product_id.id,
342
+ "product_uom_id": move.product_id.uom_id.id,
343
+ "scrap_qty": 1,
344
+ "task_id": self.task.id,
345
+ }
346
+ )
347
+ scrap.action_validate()
348
+ self.assertEqual(scrap.state, "done")
349
+ self.assertEqual(len(scrap.move_ids), 1)
350
+ self.assertEqual(scrap.move_ids.raw_material_task_id, self.task)
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <odoo>
3
+ <record id="edit_project" model="ir.ui.view">
4
+ <field name="name">project.project.form</field>
5
+ <field name="model">project.project</field>
6
+ <field name="inherit_id" ref="project.edit_project" />
7
+ <field name="arch" type="xml">
8
+ <xpath expr="///group[@name='extra_settings']" position="before">
9
+ <group string="Stock" name="stock_misc" groups="stock.group_stock_user">
10
+ <field name="picking_type_id" />
11
+ <field
12
+ name="location_id"
13
+ groups="stock.group_stock_multi_locations"
14
+ />
15
+ <field
16
+ name="location_dest_id"
17
+ groups="stock.group_stock_multi_locations"
18
+ />
19
+ <field name="stock_analytic_date" />
20
+ </group>
21
+ </xpath>
22
+ </field>
23
+ </record>
24
+ </odoo>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <odoo>
3
+ <record id="task_type_edit" model="ir.ui.view">
4
+ <field name="name">project.task.type.form</field>
5
+ <field name="model">project.task.type</field>
6
+ <field name="inherit_id" ref="project.task_type_edit" />
7
+ <field name="arch" type="xml">
8
+ <field name="fold" position="after">
9
+ <field name="use_stock_moves" />
10
+ <field name="done_stock_moves" invisible="not use_stock_moves" />
11
+ </field>
12
+ </field>
13
+ </record>
14
+ </odoo>
@@ -0,0 +1,142 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <odoo>
3
+ <record id="view_task_form2" model="ir.ui.view">
4
+ <field name="name">project.task.form</field>
5
+ <field name="model">project.task</field>
6
+ <field name="inherit_id" ref="project.view_task_form2" />
7
+ <field name="arch" type="xml">
8
+ <xpath expr="///button[@name='action_open_parent_task']" position="after">
9
+ <button
10
+ name="%(action_project_task_moves)d"
11
+ type="action"
12
+ string="Product Moves"
13
+ class="oe_stat_button"
14
+ icon="fa-exchange"
15
+ invisible="not done_stock_moves"
16
+ groups="stock.group_stock_user"
17
+ />
18
+ <button
19
+ class="oe_stat_button"
20
+ name="action_see_move_scrap"
21
+ type="object"
22
+ icon="fa-arrows-v"
23
+ invisible="scrap_count==0"
24
+ groups="stock.group_stock_user"
25
+ >
26
+ <field name="scrap_count" widget="statinfo" string="Scraps" />
27
+ </button>
28
+ </xpath>
29
+ <field name="date_last_stage_update" position="after">
30
+ <field
31
+ name="stock_analytic_account_id"
32
+ groups="analytic.group_analytic_accounting"
33
+ required="not project_id"
34
+ invisible="not use_stock_moves"
35
+ />
36
+ <field
37
+ name="stock_analytic_distribution"
38
+ widget="analytic_distribution"
39
+ groups="analytic.group_analytic_accounting"
40
+ invisible="not use_stock_moves"
41
+ />
42
+ <field name="stock_analytic_date" />
43
+ </field>
44
+ <field name="stage_id" position="before">
45
+ <button
46
+ name="action_confirm"
47
+ string="Confirm materials"
48
+ type="object"
49
+ class="oe_highlight"
50
+ invisible="not allow_moves_action_confirm"
51
+ groups="stock.group_stock_user"
52
+ />
53
+ <button
54
+ name="action_assign"
55
+ string="Check availability materials"
56
+ type="object"
57
+ class="oe_highlight"
58
+ invisible="not allow_moves_action_assign"
59
+ groups="stock.group_stock_user"
60
+ />
61
+ <button
62
+ name="button_scrap"
63
+ type="object"
64
+ string="Scrap"
65
+ invisible="stock_state=='done' or not done_stock_moves or not stock_moves_is_locked"
66
+ groups="stock.group_stock_user"
67
+ />
68
+ <button
69
+ name="button_unreserve"
70
+ type="object"
71
+ string="Unreserve"
72
+ invisible="stock_state=='cancel' or not unreserve_visible or not done_stock_moves or not stock_moves_is_locked"
73
+ groups="stock.group_stock_user"
74
+ />
75
+ <button
76
+ name="action_cancel"
77
+ type="object"
78
+ string="Cancel Materials"
79
+ invisible="stock_state in ('draft', 'cancel') or not done_stock_moves or not stock_moves_is_locked"
80
+ groups="stock.group_stock_user"
81
+ />
82
+ <button
83
+ name="action_done"
84
+ type="object"
85
+ string="Transfer Materials"
86
+ invisible="stock_state!='assigned' or not done_stock_moves or not stock_moves_is_locked"
87
+ class="oe_highlight"
88
+ groups="stock.group_stock_user"
89
+ />
90
+ <button
91
+ name="action_toggle_stock_moves_is_locked"
92
+ invisible="stock_state in ('draft','cancel') or not stock_moves_is_locked or not done_stock_moves"
93
+ string="Unlock"
94
+ groups="stock.group_stock_manager"
95
+ type="object"
96
+ />
97
+ <button
98
+ name="action_toggle_stock_moves_is_locked"
99
+ invisible="stock_moves_is_locked or not done_stock_moves"
100
+ string="Lock"
101
+ class="oe_highlight"
102
+ groups="stock.group_stock_manager"
103
+ type="object"
104
+ />
105
+ </field>
106
+ <xpath expr="///page[@name='extra_info']" position="before">
107
+ <!-- Field without groups used as domain in stock_analytic_* fields !-->
108
+ <field name="use_stock_moves" invisible="1" />
109
+ <page
110
+ name="stock_info"
111
+ string="Stock Info"
112
+ invisible="not use_stock_moves"
113
+ groups="stock.group_stock_user"
114
+ >
115
+ <field name="done_stock_moves" invisible="1" />
116
+ <field name="stock_moves_is_locked" invisible="1" />
117
+ <field name="stock_state" invisible="1" />
118
+ <field name="allow_moves_action_confirm" invisible="1" />
119
+ <field name="allow_moves_action_assign" invisible="1" />
120
+ <field name="unreserve_visible" invisible="1" />
121
+ <field
122
+ name="move_ids"
123
+ context="{'list_view_ref': 'project_task_stock.view_stock_move_raw_list', 'form_view_ref':'stock.view_move_form', 'default_raw_material_task_id': id}"
124
+ readonly="done_stock_moves and stock_moves_is_locked"
125
+ />
126
+ </page>
127
+ </xpath>
128
+ <xpath expr="///page[@name='extra_info']/group[1]" position="inside">
129
+ <group
130
+ string="Stock Info"
131
+ name="stock_info_misc"
132
+ groups="stock.group_stock_user"
133
+ invisible="not use_stock_moves"
134
+ >
135
+ <field name="picking_type_id" />
136
+ <field name="location_id" />
137
+ <field name="location_dest_id" />
138
+ </group>
139
+ </xpath>
140
+ </field>
141
+ </record>
142
+ </odoo>
@@ -0,0 +1,65 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <odoo>
3
+ <record model="ir.actions.act_window" id="action_project_task_moves">
4
+ <field name="name">Inventory Moves</field>
5
+ <field name="type">ir.actions.act_window</field>
6
+ <field name="res_model">stock.move.line</field>
7
+ <field name="view_mode">list,form</field>
8
+ <field
9
+ name="domain"
10
+ >['|', ('move_id.raw_material_task_id', '=', active_id), ('move_id.task_id', '=', active_id)]</field>
11
+ </record>
12
+ <record id="view_stock_move_raw_list" model="ir.ui.view">
13
+ <field name="name">stock.move.raw.list</field>
14
+ <field name="model">stock.move</field>
15
+ <field name="priority">1000</field>
16
+ <field name="arch" type="xml">
17
+ <list
18
+ editable="bottom"
19
+ default_order="sequence"
20
+ decoration-muted="state in ('done', 'cancel')"
21
+ decoration-warning="quantity - product_uom_qty &gt; 0.0001"
22
+ decoration-success="state not in ('done', 'cancel') and quantity - product_uom_qty &lt; 0.0001"
23
+ >
24
+ <field name="company_id" column_invisible="1" />
25
+ <field name="product_id" required="1" readonly="state!='draft'" />
26
+ <field name="sequence" column_invisible="1" />
27
+ <field name="location_id" optional="hide" readonly="1" force_save="1" />
28
+ <field
29
+ name="location_dest_id"
30
+ optional="hide"
31
+ readonly="1"
32
+ force_save="1"
33
+ />
34
+ <field
35
+ name="picking_type_id"
36
+ optional="hide"
37
+ readonly="1"
38
+ force_save="1"
39
+ />
40
+ <field name="name" column_invisible="1" />
41
+ <field name="state" column_invisible="1" />
42
+ <field
43
+ name="product_uom"
44
+ groups="uom.group_uom"
45
+ readonly="state!='draft'"
46
+ />
47
+ <field
48
+ name="product_uom_qty"
49
+ string="To Consume"
50
+ readonly="state!='draft'"
51
+ />
52
+ <button
53
+ name="action_task_product_forecast_report"
54
+ type="object"
55
+ icon="fa-area-chart"
56
+ title="Forecasted Report"
57
+ invisible="not product_id or state in ['done', 'cancel']"
58
+ />
59
+ <field name="product_uom_category_id" column_invisible="1" />
60
+ <field name="quantity" string="Consumed" readonly="1" />
61
+ <field name="group_id" column_invisible="1" />
62
+ </list>
63
+ </field>
64
+ </record>
65
+ </odoo>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <odoo>
3
+ <record id="stock_scrap_form_view" model="ir.ui.view">
4
+ <field name="name">stock.scrap.form</field>
5
+ <field name="model">stock.scrap</field>
6
+ <field name="inherit_id" ref="stock.stock_scrap_form_view" />
7
+ <field name="arch" type="xml">
8
+ <field name="origin" position="after">
9
+ <field name="task_id" invisible="not task_id" readonly="True" />
10
+ </field>
11
+ </field>
12
+ </record>
13
+ </odoo>