Merge lp:~unifield-team/unifield-wm/us-311 into lp:unifield-wm

Proposed by Quentin THEURET @Amaris
Status: Merged
Merged at revision: 2539
Proposed branch: lp:~unifield-team/unifield-wm/us-311
Merge into: lp:unifield-wm
Diff against target: 823 lines (+700/-11)
6 files modified
msf_outgoing/msf_outgoing.py (+3/-0)
purchase_override/purchase.py (+2/-0)
purchase_override/wizard/split_order_line.py (+9/-1)
sale_override/sale.py (+4/-2)
unifield_tests/tests/resourcing.py (+13/-8)
unifield_tests/tests/test_us_311.py (+669/-0)
To merge this branch: bzr merge lp:~unifield-team/unifield-wm/us-311
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+261084@code.launchpad.net
To post a comment you must log in.
lp:~unifield-team/unifield-wm/us-311 updated
2537. By Quentin THEURET @Amaris

US-311 [FIX] Force check of state of the Internal request when the OUT is done

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'msf_outgoing/msf_outgoing.py'
2--- msf_outgoing/msf_outgoing.py 2015-06-03 15:29:06 +0000
3+++ msf_outgoing/msf_outgoing.py 2015-06-04 14:18:29 +0000
4@@ -3199,6 +3199,9 @@
5 delivered_pack = self.browse(cr, uid, delivered_pack_id, context=context)
6 res[picking.id] = {'delivered_picking': delivered_pack.id or False}
7
8+ if picking.type == 'out' and picking.sale_id and picking.sale_id.procurement_request:
9+ wf_service.trg_write(uid, 'sale.order', picking.sale_id.id, cr)
10+
11 return res
12
13 @check_cp_rw
14
15=== modified file 'purchase_override/purchase.py'
16--- purchase_override/purchase.py 2015-05-29 15:29:07 +0000
17+++ purchase_override/purchase.py 2015-06-04 14:18:29 +0000
18@@ -1216,6 +1216,7 @@
19 'created_by_rfq_line': l.order_id.rfq_ok and l.id or False,
20 'po_cft': l.order_id.rfq_ok and 'rfq' or 'po',
21 'sync_sourced_origin': l.instance_sync_order_ref and l.instance_sync_order_ref.name or False,
22+ #'is_line_split': l.is_line_split,
23 'name': '[%s] %s' % (l.product_id.default_code, l.product_id.name)}
24
25 new_line_id = sol_obj.create(cr, uid, vals, context=context)
26@@ -1444,6 +1445,7 @@
27 'nomen_sub_4': line.nomen_sub_4 and line.nomen_sub_4.id or False,
28 'nomen_sub_5': line.nomen_sub_5 and line.nomen_sub_5.id or False,
29 'confirmed_delivery_date': line_confirmed,
30+ #'is_line_split': line.is_line_split,
31 }
32 """
33 UFTP-336: Update the analytic distribution at FO line when
34
35=== modified file 'purchase_override/wizard/split_order_line.py'
36--- purchase_override/wizard/split_order_line.py 2014-09-19 12:18:46 +0000
37+++ purchase_override/wizard/split_order_line.py 2015-06-04 14:18:29 +0000
38@@ -133,8 +133,16 @@
39 'so_back_update_dest_pol_id_sale_order_line': split.purchase_line_id.id,
40 }
41 new_so_line_id = so_line_obj.copy(cr, uid, split.corresponding_so_line_id_split_po_line_wizard.id, so_copy_data, context=dict(context, keepDateAndDistrib=True))
42+ so_line_obj.write(cr, uid, new_so_line_id, {
43+ 'supplier': split.corresponding_so_line_id_split_po_line_wizard.supplier.id,
44+ 'type': 'make_to_order',
45+ 'is_line_split': True,
46+ }, context=context)
47 # change the initial qty on the initial FO line
48- so_line_obj.write(cr, uid, split.corresponding_so_line_id_split_po_line_wizard.id, {'product_uom_qty': split.original_qty - split.new_line_qty, 'product_uos_qty': split.original_qty - split.new_line_qty}, context=dict(context, keepDateAndDistrib=True))
49+ so_line_obj.write(cr, uid, split.corresponding_so_line_id_split_po_line_wizard.id, {
50+ 'product_uom_qty': split.original_qty - split.new_line_qty,
51+ 'product_uos_qty': split.original_qty - split.new_line_qty,
52+ }, context=dict(context, keepDateAndDistrib=True))
53 # call the new procurement creation method
54 so_obj.action_ship_proc_create(cr, uid, [split.corresponding_so_id_split_po_line_wizard.id], context=context)
55 # run the procurement, the make_po function detects the link to original po
56
57=== modified file 'sale_override/sale.py'
58--- sale_override/sale.py 2015-05-29 15:29:07 +0000
59+++ sale_override/sale.py 2015-06-04 14:18:29 +0000
60@@ -2201,7 +2201,8 @@
61 'created_by_rfq_line': fields.many2one('purchase.order.line', string='Created by RfQ line'),
62 'dpo_line_id': fields.many2one('purchase.order.line', string='DPO line'),
63 'sync_sourced_origin': fields.char(string='Sync. Origin', size=256),
64- 'cancel_split_ok': fields.boolean(
65+ 'cancel_split_ok': fields.float(
66+ digits=(16,2),
67 string='Cancel split',
68 help='If the line has been canceled/removed on the splitted FO',
69 ),
70@@ -2313,7 +2314,8 @@
71 pick_obj.validate(cr, uid, [pick.id])
72
73 if line.original_line_id:
74- self.write(cr, uid, [line.original_line_id.id], {'cancel_split_ok': True}, context=context)
75+ cancel_split_qty = line.original_line_id.cancel_split_ok + line.product_uom_qty
76+ self.write(cr, uid, [line.original_line_id.id], {'cancel_split_ok': cancel_split_qty}, context=context)
77
78 # UFTP-82:
79 # do not delete cancelled IR line from PO cancelled
80
81=== modified file 'unifield_tests/tests/resourcing.py'
82--- unifield_tests/tests/resourcing.py 2015-03-17 09:46:54 +0000
83+++ unifield_tests/tests/resourcing.py 2015-06-04 14:18:29 +0000
84@@ -293,23 +293,26 @@
85 :param po_ids: List of ID of purchase.order to validate
86 :return The list of ID of purchase.order validated
87 """
88+ po_obj = db.get('purchase.order')
89+ pol_obj = db.get('purchase.order.line')
90+
91 # Add an analytic distribution on PO lines that have no
92- no_ana_line_ids = self.pol_obj.search([
93+ no_ana_line_ids = pol_obj.search([
94 ('order_id', 'in', po_ids),
95 ('analytic_distribution_id', '=', False),
96 ])
97- self.pol_obj.write(no_ana_line_ids, {
98+ pol_obj.write(no_ana_line_ids, {
99 'analytic_distribution_id': self.get_record(db, 'distrib_1'),
100 })
101
102 # Check if the PO is draft
103 for po_id in po_ids:
104- po_state = self.po_obj.read(po_id, ['state'])['state']
105+ po_state = po_obj.read(po_id, ['state'])['state']
106 self.assert_(po_state == 'draft', msg="""
107 The state of the generated PO is %s - Should be 'draft'""" % po_state)
108 # Validate the PO
109 db.exec_workflow('purchase.order', 'purchase_confirm', po_id)
110- po_state = self.po_obj.browse(po_id).state
111+ po_state = po_obj.browse(po_id).state
112 self.assert_(po_state == 'confirmed', msg="""
113 The state of the generated PO is %s - Should be 'confirmed'""" % po_state)
114
115@@ -325,16 +328,18 @@
116 :param dcd: Delivery confirmed date to set
117 :return: The list of ID of purchase.order confirmed
118 """
119+ po_obj = db.get('purchase.order')
120+
121 if not dcd:
122 dcd = time.strftime('%Y-%m-%d')
123
124- self.po_obj.write(po_ids, {'delivery_confirmed_date': dcd})
125+ po_obj.write(po_ids, {'delivery_confirmed_date': dcd})
126
127 for po_id in po_ids:
128 """
129 1/ Check if the PO are in 'confirmed' state
130 """
131- po_state = self.po_obj.read(po_id, ['state'])['state']
132+ po_state = po_obj.read(po_id, ['state'])['state']
133 self.assert_(
134 po_state == 'confirmed',
135 "The state of the generated PO is %s - Should be 'confirmed'" % po_state,
136@@ -342,11 +347,11 @@
137 """
138 2/ Confirm the PO
139 """
140- self.po_obj.confirm_button([po_id])
141+ po_obj.confirm_button([po_id])
142 """
143 3/ Check if all PO are now in 'approved' state
144 """
145- po_state = self.po_obj.read(po_id, ['state'])['state']
146+ po_state = po_obj.read(po_id, ['state'])['state']
147 self.assert_(
148 po_state == 'approved',
149 "The state of the generated PO is %s - Should be 'approved'" % po_state,
150
151=== added file 'unifield_tests/tests/test_us_311.py'
152--- unifield_tests/tests/test_us_311.py 1970-01-01 00:00:00 +0000
153+++ unifield_tests/tests/test_us_311.py 2015-06-04 14:18:29 +0000
154@@ -0,0 +1,669 @@
155+#!/usr/bin/env python
156+# -*- coding: utf8 -*-
157+
158+__author__ = 'qt'
159+
160+from resourcing import ResourcingTest
161+
162+
163+class US311Test(ResourcingTest):
164+
165+ def setUp(self):
166+ """
167+ 1/ Create an IR with two lines at project:
168+ * One with 18 PCE of product 1
169+ * One with 25 PCE of product 2
170+ 2/ Validate the IR
171+ 3/ Source all lines to the coordo
172+ 4/ Validate the PO
173+ 5/ Sync.
174+ 6/ At coordo, validate the FO
175+ 7/ Source the two lines to an external supplier
176+ 8/ On the generated PO, split the line of 25 PCE to two lines:
177+ * One line with 15 PCE
178+ * One line with 10 PCE
179+ """
180+ super(US311Test, self).setUp()
181+ # Project objects mapper
182+ self.p_so_obj = self.p1.get('sale.order')
183+ self.p_sol_obj = self.p1.get('sale.order.line')
184+ self.p_po_obj = self.p1.get('purchase.order')
185+ self.p_pol_obj = self.p1.get('purchase.order.line')
186+ self.p_pick_obj = self.p1.get('stock.picking')
187+ self.p_move_obj = self.p1.get('stock.move')
188+ self.p_partner_obj = self.p1.get('res.partner')
189+ # Coordo objects mapper
190+ self.c_so_obj = self.c1.get('sale.order')
191+ self.c_sol_obj = self.c1.get('sale.order.line')
192+ self.c_po_obj = self.c1.get('purchase.order')
193+ self.c_pol_obj = self.c1.get('purchase.order.line')
194+ self.c_pick_obj = self.c1.get('stock.picking')
195+ self.c_move_obj = self.c1.get('stock.move')
196+ self.c_partner_obj = self.c1.get('res.partner')
197+
198+ # Products
199+ self.p_prd1_id = self.get_record(self.p1, 'prod_log_1')
200+ self.p_prd2_id = self.get_record(self.p1, 'prod_log_2')
201+ self.p_prd3_id = self.get_record(self.p1, 'prod_log_3')
202+ self.c_prd1_id = self.get_record(self.c1, 'prod_log_1')
203+ self.c_prd2_id = self.get_record(self.c1, 'prod_log_2')
204+ self.c_prd3_id = self.get_record(self.c1, 'prod_log_3')
205+
206+ # Get Project and Coordo partners
207+ project_name = self.get_db_partner_name(self.p1)
208+ coordo_name = self.get_db_partner_name(self.c1)
209+ c_proj_ids = self.c_partner_obj.search([('name', '=', project_name)])
210+ p_coordo_ids = self.p_partner_obj.search([('name', '=', coordo_name)])
211+
212+ self.assert_(
213+ c_proj_ids,
214+ "No project partner found in Coordination",
215+ )
216+ self.assert_(
217+ p_coordo_ids,
218+ "No coordination partner found in Project",
219+ )
220+ self.c_prj_id = c_proj_ids[0]
221+ self.p_crd_id = p_coordo_ids[0]
222+
223+ # Prepare values for IR
224+ uom_pce_id = self.get_record(self.p1, 'product_uom_unit', module='product')
225+ distrib_id = self.create_analytic_distribution(self.p1)
226+
227+ """
228+ 1/ Create an IR with two lines at project:
229+ * One with 18 PCE of product 1
230+ * One with 25 PCE of product 2
231+ """
232+ ir_values = {
233+ 'procurement_request': True,
234+ 'location_requestor_id': self.get_record(self.p1, 'external_cu'),
235+ }
236+ self.p_ir_id = self.p_so_obj.create(ir_values)
237+ l1_values = {
238+ 'order_id': self.p_ir_id,
239+ 'product_id': self.p_prd1_id,
240+ 'product_uom': uom_pce_id,
241+ 'product_uom_qty': 18.00,
242+ 'type': 'make_to_order',
243+ 'price_unit': 1.00,
244+ }
245+ self.p_irl1_id = self.p_sol_obj.create(l1_values)
246+
247+ l2_values = l1_values.copy()
248+ l2_values.update({
249+ 'product_id': self.p_prd2_id,
250+ 'product_uom_qty': 25.00,
251+ })
252+ self.p_irl2_id = self.p_sol_obj.create(l2_values)
253+
254+ """
255+ 2/ Validate the IR
256+ """
257+ self.p1.exec_workflow('sale.order', 'procurement_validate', self.p_ir_id)
258+
259+ """
260+ 3/ Source all lines to the coordo
261+ """
262+ self.p_sol_obj.write([self.p_irl1_id, self.p_irl2_id], {
263+ 'po_cft': 'po',
264+ 'supplier': self.p_crd_id,
265+ })
266+ self.p_sol_obj.confirmLine([self.p_irl1_id, self.p_irl2_id])
267+
268+ # Run the scheduler
269+ self.p_ir_id = self.run_auto_pos_creation(self.p1, order_to_check=self.p_ir_id)
270+ line_ids = self.p_sol_obj.search([('order_id', '=', self.p_ir_id)])
271+ not_sourced = True
272+ while not_sourced:
273+ not_sourced = False
274+ for line in self.p_sol_obj.browse(line_ids):
275+ if line.procurement_id.state != 'running':
276+ not_source = True
277+ if not_sourced:
278+ time.sleep(1)
279+
280+ po_ids = set()
281+ po_line_ids = []
282+ for line in self.p_sol_obj.browse(line_ids):
283+ po_line_ids.extend(self.p_pol_obj.search([
284+ ('procurement_id', '=', line.procurement_id.id),
285+ ]))
286+
287+ for po_line in self.p_pol_obj.read(po_line_ids, ['order_id']):
288+ po_ids.add(po_line['order_id'][0])
289+
290+ self.p_po_id = po_ids and list(po_ids)[0] or False
291+ self.p_po_name = self.p_po_obj.read(self.p_po_id, ['name'])['name']
292+
293+ """
294+ 4/ Validate the PO
295+ """
296+ self._validate_po(self.p1, [self.p_po_id])
297+
298+ """
299+ 5/ Sync.
300+ """
301+ self.synchronize(self.p1)
302+ self.synchronize(self.c1)
303+
304+ """
305+ 6/ At coordo, validate the FO
306+ """
307+ self.c_fo_id = None
308+ self.c_fo_ids = self.c_so_obj.search([('client_order_ref', 'like', self.p_po_name)])
309+ for c_fo_id in self.c_fo_ids:
310+ self.assert_(
311+ self.c_so_obj.read(c_fo_id, ['state'])['state'] == 'draft',
312+ "The FO at Coordo is not 'Draft'.",
313+ )
314+ self.c_fo_id = c_fo_id
315+
316+ # Validate the Field order
317+ self.c1.exec_workflow('sale.order', 'order_validated', self.c_fo_id)
318+
319+ """
320+ 7/ Source the two lines to an external supplier
321+ """
322+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_fo_id)])
323+ self.c_sol_obj.write(line_ids, {
324+ 'type': 'make_to_order',
325+ 'po_cft': 'po',
326+ 'supplier': self.get_record(self.c1, 'ext_supplier_1'),
327+ })
328+ self.c_sol_obj.confirmLine(line_ids)
329+
330+ # Get the generated PO
331+ self.c_fo_id = self.run_auto_pos_creation(self.c1, order_to_check=self.c_fo_id)
332+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_fo_id)])
333+ po_ids = set()
334+ po_line_ids = []
335+ self.c_pol_18 = None
336+ self.c_pol_25 = None
337+ self.c_pol_10 = None
338+ self.c_pol_15 = None
339+ for line in self.c_sol_obj.browse(line_ids):
340+ if line.procurement_id:
341+ po_line_ids.extend(self.c_pol_obj.search([
342+ ('procurement_id', '=', line.procurement_id.id),
343+ ]))
344+ for po_line in self.c_pol_obj.read(po_line_ids, ['order_id', 'product_qty']):
345+ po_ids.add(po_line['order_id'][0])
346+ self.c_po_id = po_line['order_id'][0]
347+ if po_line['product_qty'] == 18.00:
348+ self.c_pol_18 = po_line['id']
349+ elif po_line['product_qty'] == 25.00:
350+ self.c_pol_25 = po_line['id']
351+
352+ self.assert_(
353+ self.c_pol_18,
354+ "Line with 18 PCE not found on PO",
355+ )
356+ self.assert_(
357+ self.c_pol_25,
358+ "Line with 25 PCE not found on PO",
359+ )
360+
361+ """
362+ 8/ On the generated PO, split the line of 25 PCE to two lines:
363+ * One line with 15 PCE
364+ * One line with 10 PCE
365+ """
366+ split_obj = self.c1.get('split.purchase.order.line.wizard')
367+ split_id = split_obj.create({
368+ 'purchase_line_id': self.c_pol_25,
369+ 'original_qty': 25.00,
370+ 'old_line_qty': 10.00,
371+ 'new_line_qty': 15.00,
372+ })
373+ split_obj.split_line([split_id])
374+
375+ line_ids = self.c_pol_obj.search([('order_id', 'in', list(po_ids))])
376+ for pol in self.c_pol_obj.browse(line_ids):
377+ if pol.product_qty == 18.00:
378+ self.c_pol_18 = pol.id
379+ elif pol.product_qty == 10.00:
380+ self.c_pol_10 = pol.id
381+ elif pol.product_qty == 15.00:
382+ self.c_pol_15 = pol.id
383+
384+ self.assert_(
385+ self.c_pol_18 and self.c_pol_10 and self.c_pol_15,
386+ "Not all needed PO lines are found",
387+ )
388+
389+ def tearDown(self):
390+ """
391+ """
392+ super(US311Test, self).tearDown()
393+
394+ def run_flow(self):
395+ """
396+ Confirm the PO, then process the IN and the P/P/S at Coordo
397+ Sync
398+ """
399+ # Validate the PO
400+ self._validate_po(self.c1, [self.c_po_id])
401+
402+ # Confirm the PO
403+ self._confirm_po(self.c1, [self.c_po_id])
404+
405+ # Process the IN
406+ c_in_ids = self.c_pick_obj.search([('purchase_id', '=', self.c_po_id), ('type', '=', 'in')])
407+ self.assert_(
408+ len(c_in_ids) == 1,
409+ "There are %s IN association to PO - Should be 1" % len(c_in_ids),
410+ )
411+ proc_obj = self.c1.get('stock.incoming.processor')
412+ proc_res = self.c_pick_obj.action_process(c_in_ids)
413+ proc_id = proc_res.get('res_id')
414+ proc_obj.copy_all([proc_id])
415+ proc_obj.do_incoming_shipment([proc_id])
416+
417+ # Process P/P/S
418+ c_out_ids = self.c_pick_obj.search([('sale_id', '=', self.c_fo_id), ('type', '=', 'out'), ('state', '=', 'assigned')])
419+ self.assert_(
420+ len(c_out_ids) == 1,
421+ "There are %s OUT/PICK associated to FO - Should be 1" % len(c_out_ids),
422+ )
423+ out_proc_obj = self.c1.get('outgoing.delivery.processor')
424+ conv_res = self.c_pick_obj.convert_to_standard(c_out_ids)
425+ out_id = conv_res.get('res_id')
426+ proc_res = self.c_pick_obj.action_process([out_id])
427+ out_proc_obj.copy_all([proc_res.get('res_id')])
428+ out_proc_obj.do_partial([proc_res.get('res_id')])
429+
430+ self.synchronize(self.c1)
431+ self.synchronize(self.p1)
432+
433+ def close_flow(self):
434+ """
435+ Process the IN and the OUT at project
436+ """
437+ # Process the IN
438+ proc_obj = self.p1.get('stock.incoming.processor')
439+ for in_id in self.p_in_ids:
440+ proc_res = self.p_pick_obj.action_process([in_id])
441+ proc_id = proc_res.get('res_id')
442+ proc_obj.copy_all([proc_id])
443+ proc_obj.do_incoming_shipment([proc_id])
444+
445+ # Process the OUT
446+ out_proc_obj = self.p1.get('outgoing.delivery.processor')
447+ for out_id in self.out_ids:
448+ proc_res = self.p_pick_obj.action_process([out_id])
449+ out_proc_obj.copy_all([proc_res.get('res_id')])
450+ out_proc_obj.do_partial([proc_res.get('res_id')])
451+
452+ self.assert_(
453+ self.p_so_obj.browse(self.p_ir_id).state == 'done',
454+ "The Internal request is not Closed",
455+ )
456+
457+ def test_cancel_new_splitted_line(self):
458+ """
459+ Cancel the new line after the split, confirm the PO, process the IN and the P/P/S
460+ at coordo, then sync.
461+ At project, check the number of lines in OUT.
462+ Process the IN and the OUT.
463+ """
464+ # Cancel the PO line
465+ res = self.c_pol_obj.ask_unlink(self.c_pol_15)
466+ self.assert_(
467+ res.get('res_id', False) and res.get('res_model', False) == 'purchase.order.line.unlink.wizard',
468+ "There is no wizard displayed when cancel a PO line that sources a FO/IR line",
469+ )
470+ w_res = self.c1.get('purchase.order.line.unlink.wizard').just_cancel(res.get('res_id'))
471+
472+ self.run_flow()
473+
474+ # Check IR quantities
475+ prd1_qty = 0.00
476+ prd2_qty = 0.00
477+ for line in self.p_so_obj.browse(self.p_ir_id).order_line:
478+ if line.state == 'done':
479+ continue
480+ if line.product_id.id == self.p_prd1_id:
481+ prd1_qty += line.product_uom_qty
482+ elif line.product_id.id == self.p_prd2_id:
483+ prd2_qty += line.product_uom_qty
484+
485+ self.assert_(
486+ prd1_qty == 18.00 and prd2_qty == 10.00,
487+ "The quantities on IR moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
488+ )
489+
490+ # Check IN quantities
491+ prd1_qty = 0.00
492+ prd2_qty = 0.00
493+ ir_name = self.p_so_obj.read(self.p_ir_id, ['name'])['name']
494+ self.p_in_ids = self.p_pick_obj.search([
495+ ('type', '=', 'in'),
496+ ('origin', 'like', ir_name),
497+ ])
498+ for pick in self.p_pick_obj.browse(self.p_in_ids):
499+ for move in pick.move_lines:
500+ if move.product_id.id == self.p_prd1_id:
501+ prd1_qty += move.product_qty
502+ elif move.product_id.id == self.p_prd2_id:
503+ prd2_qty += move.product_qty
504+
505+ self.assert_(
506+ prd1_qty == 18.00 and prd2_qty == 10.00,
507+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
508+ )
509+
510+ # Check OUT quantities
511+ prd1_qty = 0.00
512+ prd2_qty = 0.00
513+ self.out_ids = self.p_pick_obj.search([('sale_id', '=', self.p_ir_id), ('type', '=', 'out')])
514+ for pick in self.p_pick_obj.browse(self.out_ids):
515+ for move in pick.move_lines:
516+ if move.product_id.id == self.p_prd1_id:
517+ prd1_qty += move.product_qty
518+ elif move.product_id.id == self.p_prd2_id:
519+ prd2_qty += move.product_qty
520+
521+ self.assert_(
522+ prd1_qty == 18.00 and prd2_qty == 10.00,
523+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
524+ )
525+
526+ self.close_flow()
527+
528+ def test_cancel_all_splitted_lines(self):
529+ """
530+ Cancel the splitted line, confirm the PO, process the IN and the P/P/S
531+ at coordo, then sync.
532+ At project, check the number of lines in OUT.
533+ Process the IN and the OUT.
534+ """
535+ # Cancel the PO lines
536+ res = self.c_pol_obj.ask_unlink(self.c_pol_10)
537+ self.assert_(
538+ res.get('res_id', False) and res.get('res_model', False) == 'purchase.order.line.unlink.wizard',
539+ "There is no wizard displayed when cancel a PO line that sources a FO/IR line",
540+ )
541+ w_res = self.c1.get('purchase.order.line.unlink.wizard').just_cancel(res.get('res_id'))
542+ res = self.c_pol_obj.ask_unlink(self.c_pol_15)
543+ self.assert_(
544+ res.get('res_id', False) and res.get('res_model', False) == 'purchase.order.line.unlink.wizard',
545+ "There is no wizard displayed when cancel a PO line that sources a FO/IR line",
546+ )
547+ w_res = self.c1.get('purchase.order.line.unlink.wizard').just_cancel(res.get('res_id'))
548+
549+ self.run_flow()
550+
551+ # Check IR quantities
552+ prd1_qty = 0.00
553+ prd2_qty = 0.00
554+ for line in self.p_so_obj.browse(self.p_ir_id).order_line:
555+ if line.state == 'done':
556+ continue
557+ if line.product_id.id == self.p_prd1_id:
558+ prd1_qty += line.product_uom_qty
559+ elif line.product_id.id == self.p_prd2_id:
560+ prd2_qty += line.product_uom_qty
561+
562+ self.assert_(
563+ prd1_qty == 18.00 and prd2_qty == 0.00,
564+ "The quantities on IR moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
565+ )
566+
567+ # Check IN quantities
568+ prd1_qty = 0.00
569+ prd2_qty = 0.00
570+ ir_name = self.p_so_obj.read(self.p_ir_id, ['name'])['name']
571+ self.p_in_ids = self.p_pick_obj.search([
572+ ('type', '=', 'in'),
573+ ('origin', 'like', ir_name),
574+ ])
575+ for pick in self.p_pick_obj.browse(self.p_in_ids):
576+ for move in pick.move_lines:
577+ if move.product_id.id == self.p_prd1_id:
578+ prd1_qty += move.product_qty
579+ elif move.product_id.id == self.p_prd2_id:
580+ prd2_qty += move.product_qty
581+
582+ self.assert_(
583+ prd1_qty == 18.00 and prd2_qty == 0.00,
584+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
585+ )
586+
587+ # Check OUT quantities
588+ prd1_qty = 0.00
589+ prd2_qty = 0.00
590+ self.out_ids = self.p_pick_obj.search([('sale_id', '=', self.p_ir_id), ('type', '=', 'out')])
591+ for pick in self.p_pick_obj.browse(self.out_ids):
592+ for move in pick.move_lines:
593+ if move.product_id.id == self.p_prd1_id:
594+ prd1_qty += move.product_qty
595+ elif move.product_id.id == self.p_prd2_id:
596+ prd2_qty += move.product_qty
597+
598+ self.assert_(
599+ prd1_qty == 18.00 and prd2_qty == 0.00,
600+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
601+ )
602+
603+ self.close_flow()
604+
605+ def test_cancel_original_splitted_line_more_on_new_line(self):
606+ """
607+ Cancel the splitted line, confirm the PO, process the IN and the P/P/S
608+ at coordo, then sync.
609+ At project, check the number of lines in OUT.
610+ Process the IN and the OUT.
611+ """
612+ # Add quantities on new line
613+ self.c_pol_obj.write(self.c_pol_15, {'product_qty': 50.0})
614+ # Cancel the PO line
615+ res = self.c_pol_obj.ask_unlink(self.c_pol_10)
616+ self.assert_(
617+ res.get('res_id', False) and res.get('res_model', False) == 'purchase.order.line.unlink.wizard',
618+ "There is no wizard displayed when cancel a PO line that sources a FO/IR line",
619+ )
620+ w_res = self.c1.get('purchase.order.line.unlink.wizard').just_cancel(res.get('res_id'))
621+
622+ self.run_flow()
623+
624+ # Check IR quantities
625+ prd1_qty = 0.00
626+ prd2_qty = 0.00
627+ for line in self.p_so_obj.browse(self.p_ir_id).order_line:
628+ if line.state == 'done':
629+ continue
630+ if line.product_id.id == self.p_prd1_id:
631+ prd1_qty += line.product_uom_qty
632+ elif line.product_id.id == self.p_prd2_id:
633+ prd2_qty += line.product_uom_qty
634+
635+ self.assert_(
636+ prd1_qty == 18.00 and prd2_qty == 50.00,
637+ "The quantities on IR moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
638+ )
639+
640+ # Check IN quantities
641+ prd1_qty = 0.00
642+ prd2_qty = 0.00
643+ ir_name = self.p_so_obj.read(self.p_ir_id, ['name'])['name']
644+ self.p_in_ids = self.p_pick_obj.search([
645+ ('type', '=', 'in'),
646+ ('origin', 'like', ir_name),
647+ ])
648+ for pick in self.p_pick_obj.browse(self.p_in_ids):
649+ for move in pick.move_lines:
650+ if move.product_id.id == self.p_prd1_id:
651+ prd1_qty += move.product_qty
652+ elif move.product_id.id == self.p_prd2_id:
653+ prd2_qty += move.product_qty
654+
655+ self.assert_(
656+ prd1_qty == 18.00 and prd2_qty == 50.00,
657+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
658+ )
659+
660+ # Check OUT quantities
661+ prd1_qty = 0.00
662+ prd2_qty = 0.00
663+ self.out_ids = self.p_pick_obj.search([('sale_id', '=', self.p_ir_id), ('type', '=', 'out')])
664+ for pick in self.p_pick_obj.browse(self.out_ids):
665+ for move in pick.move_lines:
666+ if move.product_id.id == self.p_prd1_id:
667+ prd1_qty += move.product_qty
668+ elif move.product_id.id == self.p_prd2_id:
669+ prd2_qty += move.product_qty
670+
671+ self.assert_(
672+ prd1_qty == 18.00 and prd2_qty == 50.00,
673+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
674+ )
675+
676+ self.close_flow()
677+
678+ def test_cancel_original_splitted_line(self):
679+ """
680+ Cancel the splitted line, confirm the PO, process the IN and the P/P/S
681+ at coordo, then sync.
682+ At project, check the number of lines in OUT.
683+ Process the IN and the OUT.
684+ """
685+ # Cancel the PO line
686+ res = self.c_pol_obj.ask_unlink(self.c_pol_10)
687+ self.assert_(
688+ res.get('res_id', False) and res.get('res_model', False) == 'purchase.order.line.unlink.wizard',
689+ "There is no wizard displayed when cancel a PO line that sources a FO/IR line",
690+ )
691+ w_res = self.c1.get('purchase.order.line.unlink.wizard').just_cancel(res.get('res_id'))
692+
693+ self.run_flow()
694+
695+ # Check IR quantities
696+ prd1_qty = 0.00
697+ prd2_qty = 0.00
698+ for line in self.p_so_obj.browse(self.p_ir_id).order_line:
699+ if line.state == 'done':
700+ continue
701+ if line.product_id.id == self.p_prd1_id:
702+ prd1_qty += line.product_uom_qty
703+ elif line.product_id.id == self.p_prd2_id:
704+ prd2_qty += line.product_uom_qty
705+
706+ self.assert_(
707+ prd1_qty == 18.00 and prd2_qty == 15.00,
708+ "The quantities on IR moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
709+ )
710+
711+ # Check IN quantities
712+ prd1_qty = 0.00
713+ prd2_qty = 0.00
714+ ir_name = self.p_so_obj.read(self.p_ir_id, ['name'])['name']
715+ self.p_in_ids = self.p_pick_obj.search([
716+ ('type', '=', 'in'),
717+ ('origin', 'like', ir_name),
718+ ])
719+ for pick in self.p_pick_obj.browse(self.p_in_ids):
720+ for move in pick.move_lines:
721+ if move.product_id.id == self.p_prd1_id:
722+ prd1_qty += move.product_qty
723+ elif move.product_id.id == self.p_prd2_id:
724+ prd2_qty += move.product_qty
725+
726+ self.assert_(
727+ prd1_qty == 18.00 and prd2_qty == 15.00,
728+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
729+ )
730+
731+ # Check OUT quantities
732+ prd1_qty = 0.00
733+ prd2_qty = 0.00
734+ self.out_ids = self.p_pick_obj.search([('sale_id', '=', self.p_ir_id), ('type', '=', 'out')])
735+ for pick in self.p_pick_obj.browse(self.out_ids):
736+ for move in pick.move_lines:
737+ if move.product_id.id == self.p_prd1_id:
738+ prd1_qty += move.product_qty
739+ elif move.product_id.id == self.p_prd2_id:
740+ prd2_qty += move.product_qty
741+
742+ self.assert_(
743+ prd1_qty == 18.00 and prd2_qty == 15.00,
744+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s)" % (prd1_qty, prd2_qty),
745+ )
746+
747+ self.close_flow()
748+
749+ def test_change_product_on_splitted_line(self):
750+ """
751+ Change the product of the splitted line, confirm the PO, process the
752+ IN and the P/P/S at coordo, then sync.
753+ At project, check the product of lines in OUT.
754+ Process the IN and the OUT.
755+ """
756+ # Change the product of the splitted line
757+ self.c_pol_obj.write(self.c_pol_10, {'product_id': self.c_prd3_id})
758+
759+ self.run_flow()
760+
761+ # Check IR quantities
762+ prd1_qty = 0.00
763+ prd2_qty = 0.00
764+ prd3_qty = 0.00
765+ for line in self.p_so_obj.browse(self.p_ir_id).order_line:
766+ if line.product_id.id == self.p_prd1_id:
767+ prd1_qty += line.product_uom_qty
768+ elif line.product_id.id == self.p_prd2_id:
769+ prd2_qty += line.product_uom_qty
770+ elif line.product_id.id == self.p_prd3_id:
771+ prd3_qty += line.product_uom_qty
772+
773+ self.assert_(
774+ prd1_qty == 18.00 and prd2_qty == 15.00 and prd3_qty == 10.00,
775+ "The quantities on IR moves are not good. (PRD1: %s - PRD2: %s - PRD3: %s)" % (prd1_qty, prd2_qty, prd3_qty),
776+ )
777+
778+ # Check IN quantities
779+ prd1_qty = 0.00
780+ prd2_qty = 0.00
781+ prd3_qty = 0.00
782+ ir_name = self.p_so_obj.read(self.p_ir_id, ['name'])['name']
783+ self.p_in_ids = self.p_pick_obj.search([
784+ ('type', '=', 'in'),
785+ ('origin', 'like', ir_name),
786+ ])
787+ for pick in self.p_pick_obj.browse(self.p_in_ids):
788+ for move in pick.move_lines:
789+ if move.product_id.id == self.p_prd1_id:
790+ prd1_qty += move.product_qty
791+ elif move.product_id.id == self.p_prd2_id:
792+ prd2_qty += move.product_qty
793+ elif move.product_id.id == self.p_prd3_id:
794+ prd3_qty += move.product_qty
795+
796+ self.assert_(
797+ prd1_qty == 18.00 and prd2_qty == 15.00 and prd3_qty == 10.00,
798+ "The quantities on IN moves are not good. (PRD1: %s - PRD2: %s - PRD3: %s)" % (prd1_qty, prd2_qty, prd3_qty),
799+ )
800+
801+ # Check OUT quantities
802+ prd1_qty = 0.00
803+ prd2_qty = 0.00
804+ prd3_qty = 0.00
805+ self.out_ids = self.p_pick_obj.search([('sale_id', '=', self.p_ir_id), ('type', '=', 'out')])
806+ for pick in self.p_pick_obj.browse(self.out_ids):
807+ for move in pick.move_lines:
808+ if move.product_id.id == self.p_prd1_id:
809+ prd1_qty += move.product_qty
810+ elif move.product_id.id == self.p_prd2_id:
811+ prd2_qty += move.product_qty
812+ elif move.product_id.id == self.p_prd3_id:
813+ prd3_qty += move.product_qty
814+
815+ self.assert_(
816+ prd1_qty == 18.00 and prd2_qty == 15.00 and prd3_qty == 10.00,
817+ "The quantities on OUT moves are not good. (PRD1: %s - PRD2: %s - PRD3: %s)" % (prd1_qty, prd2_qty, prd3_qty),
818+ )
819+
820+ self.close_flow()
821+
822+def get_test_class():
823+ return US311Test

Subscribers

People subscribed via source and target branches