Merge lp:~unifield-team/unifield-wm/uftp-326 into lp:unifield-wm

Proposed by jftempo
Status: Merged
Merged at revision: 2324
Proposed branch: lp:~unifield-team/unifield-wm/uftp-326
Merge into: lp:unifield-wm
Diff against target: 1006 lines (+796/-12)
14 files modified
.bzrignore (+1/-0)
delivery_mechanism/wizard/enter_reason.py (+2/-3)
msf_outgoing/msf_outgoing.py (+3/-1)
msf_outgoing/wizard/incoming_shipment_processor.py (+3/-0)
sale_override/sale.py (+1/-1)
stock_override/stock.py (+7/-0)
unifield_tests/master_data/020_partners.yml (+12/-0)
unifield_tests/tests/connection.py (+1/-0)
unifield_tests/tests/resourcing.py (+66/-6)
unifield_tests/tests/test_uftp_324.py (+195/-0)
unifield_tests/tests/test_uftp_326.py (+266/-0)
unifield_tests/tests/test_utp_1007.py (+197/-0)
unifield_tests/tests/unifield_test.py (+41/-0)
unifield_tests/unifield.config (+1/-1)
To merge this branch: bzr merge lp:~unifield-team/unifield-wm/uftp-326
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+239955@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2014-10-09 06:56:59 +0000
3+++ .bzrignore 2014-10-29 08:35:37 +0000
4@@ -1,1 +1,2 @@
5 unifield_tests/output.html
6+unifield.config
7
8=== modified file 'delivery_mechanism/wizard/enter_reason.py'
9--- delivery_mechanism/wizard/enter_reason.py 2014-08-04 15:19:38 +0000
10+++ delivery_mechanism/wizard/enter_reason.py 2014-10-29 08:35:37 +0000
11@@ -76,9 +76,8 @@
12 pol_qty[move.purchase_line_id.id] += move.product_qty
13
14 # if full cancel (no resource), we updated corresponding out and correct po state
15- if cancel_type == 'update_out':
16- picking_obj.cancel_and_update_out(cr, uid, [obj.id], context=context)
17- else:
18+ picking_obj.cancel_and_update_out(cr, uid, [obj.id], context=context)
19+ if cancel_type != 'update_out':
20 context['pol_qty'] = pol_qty
21 pol_obj.write(cr, uid, pol_ids, {'has_to_be_resourced': True}, context=context)
22 pol_obj.cancel_sol(cr, uid, pol_ids, context=context)
23
24=== modified file 'msf_outgoing/msf_outgoing.py'
25--- msf_outgoing/msf_outgoing.py 2014-09-26 13:09:16 +0000
26+++ msf_outgoing/msf_outgoing.py 2014-10-29 08:35:37 +0000
27@@ -4151,9 +4151,11 @@
28 pick_state = move.picking_id.state
29 subtype_ok = pick_type == 'out' and (pick_subtype == 'standard' or (pick_subtype == 'picking' and pick_state == 'draft'))
30
31- if pick_type == 'in' and move.purchase_line_id and not pick_cancel:
32+ if pick_type == 'in' and move.purchase_line_id:
33 sol_ids = pol_obj.get_sol_ids_from_pol_ids(cr, uid, [move.purchase_line_id.id], context=context)
34 for sol in sol_obj.browse(cr, uid, sol_ids, context=context):
35+ if sol.order_id.procurement_request:
36+ continue
37 diff_qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, sol.product_uom.id)
38 if move.has_to_be_resourced or move.picking_id.has_to_be_resourced:
39 sol_obj.add_resource_line(cr, uid, sol.id, False, diff_qty, context=context)
40
41=== modified file 'msf_outgoing/wizard/incoming_shipment_processor.py'
42--- msf_outgoing/wizard/incoming_shipment_processor.py 2014-09-29 15:30:49 +0000
43+++ msf_outgoing/wizard/incoming_shipment_processor.py 2014-10-29 08:35:37 +0000
44@@ -152,6 +152,9 @@
45 picking_obj = self.pool.get('stock.picking')
46 data_obj = self.pool.get('ir.model.data')
47
48+ if context is None:
49+ context = {}
50+
51 if not ids:
52 raise osv.except_osv(
53 _('Error'),
54
55=== modified file 'sale_override/sale.py'
56--- sale_override/sale.py 2014-10-14 14:46:33 +0000
57+++ sale_override/sale.py 2014-10-29 08:35:37 +0000
58@@ -2300,7 +2300,7 @@
59 proc_obj.write(cr, uid, [proc], {'product_qty': minus_qty}, context=context)
60
61 so_to_cancel_id = False
62- if so_obj._get_ready_to_cancel(cr, uid, order, context=context)[order]:
63+ if context.get('cancel_type', False) != 'update_out' and so_obj._get_ready_to_cancel(cr, uid, order, context=context)[order]:
64 so_to_cancel_id = order
65 else:
66 wf_service.trg_write(uid, 'sale.order', order, cr)
67
68=== modified file 'stock_override/stock.py'
69--- stock_override/stock.py 2014-09-22 14:41:45 +0000
70+++ stock_override/stock.py 2014-10-29 08:35:37 +0000
71@@ -581,6 +581,13 @@
72 # Variables
73 wf_service = netsvc.LocalService("workflow")
74
75+ if isinstance(ids, (int, long)):
76+ ids = [ids]
77+
78+ if context is None:
79+ context = {}
80+
81+ context['cancel_type'] = 'update_out'
82 res = super(stock_picking, self).action_cancel(cr, uid, ids, context=context)
83
84 # Re-source the sale.order.line
85
86=== modified file 'unifield_tests/master_data/020_partners.yml'
87--- unifield_tests/master_data/020_partners.yml 2014-10-10 08:02:07 +0000
88+++ unifield_tests/master_data/020_partners.yml 2014-10-29 08:35:37 +0000
89@@ -53,6 +53,8 @@
90 supplier: 1
91 customer: 0
92 partner_type: 'external'
93+ property_account_receivable: account_account_receivable_supplier0
94+ property_account_payable: account_account_payable_supplier0
95 -
96 Create an address for external supplier 1
97 -
98@@ -67,6 +69,8 @@
99 supplier: 1
100 customer: 0
101 partner_type: 'external'
102+ property_account_receivable: account_account_receivable_supplier0
103+ property_account_payable: account_account_payable_supplier0
104 -
105 Create an address for external supplier 2
106 -
107@@ -81,6 +85,8 @@
108 supplier: 1
109 customer: 0
110 partner_type: 'external'
111+ property_account_receivable: account_account_receivable_supplier0
112+ property_account_payable: account_account_payable_supplier0
113 -
114 Create an address for external supplier 3
115 -
116@@ -97,6 +103,8 @@
117 customer: 1
118 supplier: 0
119 partner_type: 'external'
120+ property_account_receivable: account_account_receivable_supplier0
121+ property_account_payable: account_account_payable_supplier0
122 -
123 Create an address for external customer 1
124 -
125@@ -111,6 +119,8 @@
126 customer: 1
127 supplier: 0
128 partner_type: 'external'
129+ property_account_receivable: account_account_receivable_supplier0
130+ property_account_payable: account_account_payable_supplier0
131 -
132 Create an address for external customer 2
133 -
134@@ -125,6 +135,8 @@
135 customer: 1
136 supplier: 0
137 partner_type: 'external'
138+ property_account_receivable: account_account_receivable_supplier0
139+ property_account_payable: account_account_payable_supplier0
140 -
141 Create an address for external customer 3
142 -
143
144=== modified file 'unifield_tests/tests/connection.py'
145--- unifield_tests/tests/connection.py 2014-03-18 13:19:21 +0000
146+++ unifield_tests/tests/connection.py 2014-10-29 08:35:37 +0000
147@@ -54,6 +54,7 @@
148 # Login initialization
149 db_name = '%s%s' % (db_prefix, db_suffix)
150 self.login(uid, pwd, db_name)
151+ self.db_name = db_name
152
153 if __name__ == '__main__':
154 c = XMLRPCConnection('HQ1C1P1')
155
156=== modified file 'unifield_tests/tests/resourcing.py'
157--- unifield_tests/tests/resourcing.py 2014-10-15 09:18:02 +0000
158+++ unifield_tests/tests/resourcing.py 2014-10-29 08:35:37 +0000
159@@ -53,7 +53,10 @@
160 :return True
161 :rtype bool
162 """
163- pr = self.order_obj.browse(order_to_check).procurement_request
164+ order_obj = db.get('sale.order')
165+ proc_obj = db.get('procurement.order')
166+
167+ pr = order_obj.browse(order_to_check).procurement_request
168
169 new_order_id = None
170 if pr:
171@@ -61,15 +64,15 @@
172 else:
173 state = 'done'
174
175- order_state = self.order_obj.read(order_to_check, ['state'])['state']
176+ order_state = order_obj.read(order_to_check, ['state'])['state']
177 while order_state != state:
178 time.sleep(0.5)
179- order_state = self.order_obj.read(order_to_check, ['state'])['state']
180+ order_state = order_obj.read(order_to_check, ['state'])['state']
181
182 if pr:
183 new_order_id = order_to_check
184 else:
185- new_order_ids = self.order_obj.search([
186+ new_order_ids = order_obj.search([
187 ('original_so_id_sale_order', '=', order_to_check)
188 ])
189
190@@ -78,7 +81,7 @@
191 if new_order_ids:
192 new_order_id = new_order_ids[0]
193
194- self.proc_obj.run_scheduler()
195+ proc_obj.run_scheduler()
196
197 return new_order_id
198
199@@ -98,7 +101,6 @@
200
201 # Prepare values for the field order
202 partner_id = self.get_record(db, 'ext_customer_1')
203- p_addr_id = self.get_record(db, 'ext_customer_1_addr')
204 order_type = 'regular'
205
206 change_vals = self.order_obj.\
207@@ -378,4 +380,62 @@
208 else:
209 return self._get_number_of_fo_valid_lines(db, order_id)
210
211+ def create_analytic_distribution(self, db):
212+ """
213+ Create an analytic distribution
214+ :param db: Connection on which the distribution must be created
215+ :return: The ID of distribution
216+ """
217+ distrib_obj = db.get('analytic.distribution')
218+ cc_line_obj = db.get('cost.center.distribution.line')
219+ fp_line_obj = db.get('funding.pool.distribution.line')
220+
221+ distrib_id = distrib_obj.create({
222+ 'name': 'Distrib 2',
223+ })
224+
225+ cc_line1_id = cc_line_obj.create({
226+ 'name': 'CC Line 1',
227+ 'amount': 0.0,
228+ 'percentage': 75.0,
229+ 'currency_id': self.get_record(db, 'EUR', module='base'),
230+ 'analytic_id': self.get_record(db, 'analytic_cc1'),
231+ 'distribution_id': distrib_id,
232+ 'destination_id': self.get_record(db, 'analytic_account_destination_operation', module='analytic_distribution'),
233+ })
234+
235+ cc_line2_id = cc_line_obj.create({
236+ 'name': 'CC Line 2',
237+ 'amount': 0.0,
238+ 'percentage': 25.0,
239+ 'currency_id': self.get_record(db, 'EUR', module='base'),
240+ 'analytic_id': self.get_record(db, 'analytic_cc2'),
241+ 'distribution_id': distrib_id,
242+ 'destination_id': self.get_record(db, 'analytic_account_destination_operation', module='analytic_distribution'),
243+ })
244+
245+ fp_line1_id = fp_line_obj.create({
246+ 'name': 'FP Line 1',
247+ 'amount': 0.0,
248+ 'percentage': 75.0,
249+ 'currency_id': self.get_record(db, 'EUR', module='base'),
250+ 'analytic_id': self.get_record(db, 'analytic_cc1'),
251+ 'distribution_id': distrib_id,
252+ 'cost_center_id': self.get_record(db, 'analytic_cc1'),
253+ 'destination_id': self.get_record(db, 'analytic_account_destination_operation', module='analytic_distribution'),
254+ })
255+
256+ fp_line2_id = fp_line_obj.create({
257+ 'name': 'FP Line 2',
258+ 'amount': 0.0,
259+ 'percentage': 25.0,
260+ 'currency_id': self.get_record(db, 'EUR', module='base'),
261+ 'analytic_id': self.get_record(db, 'analytic_cc2'),
262+ 'distribution_id': distrib_id,
263+ 'cost_center_id': self.get_record(db, 'analytic_cc1'),
264+ 'destination_id': self.get_record(db, 'analytic_account_destination_operation', module='analytic_distribution'),
265+ })
266+
267+ return distrib_id
268+
269 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
270
271=== added file 'unifield_tests/tests/test_uftp_324.py'
272--- unifield_tests/tests/test_uftp_324.py 1970-01-01 00:00:00 +0000
273+++ unifield_tests/tests/test_uftp_324.py 2014-10-29 08:35:37 +0000
274@@ -0,0 +1,195 @@
275+#!/usr/bin/env python
276+# -*- coding: utf8 -*-
277+
278+__author__ = 'qt'
279+
280+from resourcing import ResourcingTest
281+
282+import time
283+
284+
285+class UFTP324Test(ResourcingTest):
286+
287+ def setUp(self):
288+ """
289+ Create a PO at Project side to Coordo with
290+ two lines.
291+ :return:
292+ """
293+
294+ super(UFTP324Test, self).setUp()
295+
296+ self.synchronize(self.c1)
297+ self.synchronize(self.p1)
298+
299+ # C1
300+ self.c_so_obj = self.c1.get('sale.order')
301+ self.c_sol_obj = self.c1.get('sale.order.line')
302+ self.c_po_obj = self.c1.get('purchase.order')
303+ self.c_pol_obj = self.c1.get('purchase.order.line')
304+ self.c_partner_obj = self.c1.get('res.partner')
305+ self.c_lc_obj = self.c1.get('sale.order.leave.close')
306+ self.c_so_cancel_obj = self.c1.get('sale.order.cancelation.wizard')
307+
308+ # P1
309+ self.p_so_obj = self.p1.get('sale.order')
310+ self.p_sol_obj = self.p1.get('sale.order.line')
311+ self.p_po_obj = self.p1.get('purchase.order')
312+ self.p_pol_obj = self.p1.get('purchase.order.line')
313+ self.p_partner_obj = self.p1.get('res.partner')
314+ self.p_lc_obj = self.p1.get('sale.order.leave.close')
315+ self.p_so_cancel_obj = self.p1.get('sale.order.cancelation.wizard')
316+
317+ # Create a PO at P1 with two products to C1
318+ # Prepare values for the field order
319+ prod_log1_id = self.get_record(self.p1, 'prod_log_1')
320+ prod_log2_id = self.get_record(self.p1, 'prod_log_2')
321+ uom_pce_id = self.get_record(self.p1, 'product_uom_unit', module='product')
322+ location_id = self.get_record(self.p1, 'stock_location_stock', module='stock')
323+
324+ partner_name = self.get_db_partner_name(self.c1)
325+ partner_ids = self.p_partner_obj.search([('name', '=', partner_name)])
326+ self.assert_(
327+ partner_ids,
328+ "No partner found for %s" % self.c1.db_name,
329+ )
330+
331+ distrib_id = self.create_analytic_distribution(self.p1)
332+
333+ order_values = {
334+ 'order_type': 'regular',
335+ 'partner_id': partner_ids[0],
336+ 'rfq_ok': False,
337+ 'location_id': location_id,
338+ 'analytic_distribution_id': distrib_id,
339+ }
340+
341+ change_vals = self.p_po_obj.\
342+ onchange_partner_id(None, partner_ids[0], time.strftime('%Y-%m-%d')).get('value', {})
343+ order_values.update(change_vals)
344+
345+ self.p_po_id = self.p_po_obj.create(order_values)
346+
347+ # Create order lines
348+ # First line
349+ line_values = {
350+ 'order_id': self.p_po_id,
351+ 'product_id': prod_log1_id,
352+ 'product_uom': uom_pce_id,
353+ 'product_qty': 10.0,
354+ 'price_unit': 10.00,
355+ 'type': 'make_to_order',
356+ }
357+ self.p_pol_obj.create(line_values)
358+
359+ # Second line
360+ line_values.update({
361+ 'product_id': prod_log2_id,
362+ 'product_uom_qty': 20.0,
363+ 'price_unit': 10.0,
364+ })
365+ self.p_pol_obj.create(line_values)
366+
367+ # Validate the sale order
368+ self.p1.exec_workflow('purchase.order', 'purchase_confirm', self.p_po_id)
369+
370+ self.p_po_name = self.p_po_obj.read(self.p_po_id, ['name'])['name']
371+
372+ # Synchronize
373+ self.synchronize(self.p1)
374+ self.synchronize(self.c1)
375+
376+ self.c_so_id = None
377+
378+ c_so_ids = self.c_so_obj.search([('client_order_ref', 'like', self.p_po_name)])
379+ for c_so_id in c_so_ids:
380+ self.assert_(
381+ self.c_so_obj.read(c_so_id, ['state'])['state'] == 'draft',
382+ "The FO at Coordo is not 'Draft'.",
383+ )
384+ self.c_so_id = c_so_id
385+
386+ # Validate the sale order
387+ self.c1.exec_workflow('sale.order', 'order_validated', self.c_so_id)
388+
389+ # Source all lines on a Purchase Order to ext_supplier_1
390+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
391+ self.c_sol_obj.write(line_ids, {
392+ 'type': 'make_to_order',
393+ 'po_cft': 'po',
394+ 'supplier': self.get_record(self.c1, 'ext_supplier_1'),
395+ })
396+ self.c_sol_obj.confirmLine(line_ids)
397+
398+ # Run the scheduler
399+ self.c_so_id = self.run_auto_pos_creation(self.c1, order_to_check=self.c_so_id)
400+
401+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
402+ not_sourced = True
403+ while not_sourced:
404+ not_sourced = False
405+ for line in self.c_sol_obj.browse(line_ids):
406+ if line.procurement_id and line.procurement_id.state != 'running':
407+ not_sourced = True
408+ if not_sourced:
409+ time.sleep(1)
410+
411+ po_ids = set()
412+ po_line_ids = []
413+ for line in self.c_sol_obj.browse(line_ids):
414+ if line.procurement_id:
415+ po_line_ids.extend(self.c_pol_obj.search([
416+ ('procurement_id', '=', line.procurement_id.id),
417+ ]))
418+
419+ for po_line in self.c_pol_obj.read(po_line_ids, ['order_id']):
420+ po_ids.add(po_line['order_id'][0])
421+
422+ self.c_po_id = po_line['order_id'][0]
423+
424+ def test_utp_324(self):
425+ """
426+ Cancel the PO at coordo side, synchronize and check the state of the PO at
427+ project side.
428+ :return:
429+ """
430+ wiz_model = 'purchase.order.cancel.wizard'
431+ c_wiz_obj = self.c1.get(wiz_model)
432+ c_lc_wiz_obj = self.c1.get('sale.order.leave.close')
433+ c_cancel_so_wiz_obj = self.c1.get('sale.order.cancelation.wizard')
434+
435+ # Cancel PO at coordo side
436+ c_res = self.c_po_obj.purchase_cancel(self.c_po_id)
437+ # Validate cancellation
438+ w_res = c_wiz_obj.cancel_po(c_res.get('res_id'))
439+ # Close the FO
440+ w_line_ids = c_lc_wiz_obj.search([
441+ ('wizard_id', '=', w_res.get('res_id')),
442+ ('order_id', '=', self.c_so_id),
443+ ])
444+
445+
446+ # Choose close it
447+ c_lc_wiz_obj.write(w_line_ids, {'action': 'close'})
448+ c_cancel_so_wiz_obj.close_fo(w_res.get('res_id'))
449+
450+ self.synchronize(self.c1)
451+ self.synchronize(self.p1)
452+
453+ # Check state of the PO at project side
454+ c_so_name = self.c_so_obj.read(self.c_so_id, ['name'])['name']
455+ self.p_po_id = self.p_po_obj.search([('partner_ref', 'like', c_so_name)])[0]
456+ p_po_state = self.p_po_obj.read(self.p_po_id, ['state'])['state']
457+ self.assert_(
458+ p_po_state == 'done',
459+ "The PO at project side is not closed",
460+ )
461+ # Check number of lines in PO at project side
462+ p_po_line_ids = self.p_pol_obj.search([('order_id', '=', self.p_po_id)])
463+ self.assert_(
464+ len(p_po_line_ids) == 0,
465+ "There is always lines in PO at project side"
466+ )
467+
468+def get_test_class():
469+ return UFTP324Test
470\ No newline at end of file
471
472=== added file 'unifield_tests/tests/test_uftp_326.py'
473--- unifield_tests/tests/test_uftp_326.py 1970-01-01 00:00:00 +0000
474+++ unifield_tests/tests/test_uftp_326.py 2014-10-29 08:35:37 +0000
475@@ -0,0 +1,266 @@
476+#!/usr/bin/env python
477+# -*- coding: utf8 -*-
478+
479+__author__ = 'qt'
480+
481+from resourcing import ResourcingTest
482+
483+import time
484+
485+
486+class UFTP326Test(ResourcingTest):
487+
488+ def setUp(self):
489+ """
490+ Create a PO at Project side to Coordo with
491+ two lines.
492+ :return:
493+ """
494+ super(UFTP326Test, self).setUp()
495+
496+ self.synchronize(self.c1)
497+ self.synchronize(self.p1)
498+
499+ # C1
500+ self.c_so_obj = self.c1.get('sale.order')
501+ self.c_sol_obj = self.c1.get('sale.order.line')
502+ self.c_po_obj = self.c1.get('purchase.order')
503+ self.c_pol_obj = self.c1.get('purchase.order.line')
504+ self.c_partner_obj = self.c1.get('res.partner')
505+ self.c_lc_obj = self.c1.get('sale.order.leave.close')
506+ self.c_so_cancel_obj = self.c1.get('sale.order.cancelation.wizard')
507+ self.c_pick_obj = self.c1.get('stock.picking')
508+ self.c_enter_reason_obj = self.c1.get('enter.reason')
509+
510+ # Prepare values for the field order
511+ prod_log1_id = self.get_record(self.c1, 'prod_log_1')
512+ prod_log2_id = self.get_record(self.c1, 'prod_log_2')
513+ uom_pce_id = self.get_record(self.c1, 'product_uom_unit', module='product')
514+
515+ partner_name = self.get_db_partner_name(self.p1)
516+ partner_ids = self.c_partner_obj.search([('name', '=', partner_name)])
517+ self.assert_(
518+ partner_ids,
519+ "No partner found for %s" % self.p1.db_name,
520+ )
521+
522+ distrib_id = self.create_analytic_distribution(self.c1)
523+
524+ order_values = {
525+ 'order_type': 'regular',
526+ 'partner_id': partner_ids[0],
527+ 'procurement_request': False,
528+ 'analytic_distribution_id': distrib_id,
529+ }
530+
531+ change_vals = self.c_so_obj.\
532+ onchange_partner_id(None, partner_ids[0], 'regular').get('value', {})
533+ order_values.update(change_vals)
534+
535+ order_values['ready_to_ship_date'] = time.strftime('%Y-%m-%d')
536+
537+ self.c_so_id = self.c_so_obj.create(order_values)
538+
539+ # Create order lines
540+ # First line
541+ line_values = {
542+ 'order_id': self.c_so_id,
543+ 'product_id': prod_log1_id,
544+ 'product_uom': uom_pce_id,
545+ 'product_uom_qty': 10.0,
546+ 'type': 'make_to_order',
547+ }
548+ self.c_sol_obj.create(line_values)
549+
550+ # Second line
551+ line_values.update({
552+ 'product_id': prod_log2_id,
553+ 'product_uom_qty': 20.0,
554+ })
555+ self.c_sol_obj.create(line_values)
556+
557+ # Validate the sale order
558+ self.c1.exec_workflow('sale.order', 'order_validated', self.c_so_id)
559+
560+ # Source all lines on a Purchase Order to ext_supplier_1
561+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
562+ self.c_sol_obj.write(line_ids, {
563+ 'po_cft': 'po',
564+ 'supplier': self.get_record(self.c1, 'ext_supplier_1'),
565+ })
566+ self.c_sol_obj.confirmLine(line_ids)
567+
568+ # Run the scheduler
569+ self.c_so_id = self.run_auto_pos_creation(self.c1, order_to_check=self.c_so_id)
570+
571+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
572+ not_sourced = True
573+ while not_sourced:
574+ not_sourced = False
575+ for line in self.c_sol_obj.browse(line_ids):
576+ if line.procurement_id and line.procurement_id.state != 'running':
577+ not_sourced = True
578+ if not_sourced:
579+ time.sleep(1)
580+
581+ po_ids = set()
582+ po_line_ids = []
583+ for line in self.c_sol_obj.browse(line_ids):
584+ if line.procurement_id:
585+ po_line_ids.extend(self.c_pol_obj.search([
586+ ('procurement_id', '=', line.procurement_id.id),
587+ ]))
588+
589+ for po_line in self.c_pol_obj.read(po_line_ids, ['order_id']):
590+ po_ids.add(po_line['order_id'][0])
591+
592+ self.c_po_id = po_ids and list(po_ids)[0] or False
593+ self.c_so_name = self.c_so_obj.read(self.c_so_id, ['name'])['name']
594+
595+ self.synchronize(self.c1)
596+ self.synchronize(self.p1)
597+ self.synchronize(self.c1)
598+
599+ # P1
600+ self.p_so_obj = self.p1.get('sale.order')
601+ self.p_sol_obj = self.p1.get('sale.order.line')
602+ self.p_po_obj = self.p1.get('purchase.order')
603+ self.p_pol_obj = self.p1.get('purchase.order.line')
604+ self.p_partner_obj = self.p1.get('res.partner')
605+ self.p_lc_obj = self.p1.get('sale.order.leave.close')
606+ self.p_so_cancel_obj = self.p1.get('sale.order.cancelation.wizard')
607+
608+ self.p_po_id = None
609+
610+ p_po_ids = self.p_po_obj.search([('partner_ref', 'like', self.c_so_name)])
611+ for p_po_id in p_po_ids:
612+ self.assert_(
613+ self.p_po_obj.read(p_po_id, ['state'])['state'] == 'sourced',
614+ "The PO at Project is '%s' - Should be 'sourced'." % self.p_po_obj.read(p_po_id, ['state'])['state'],
615+ )
616+ self.p_po_id = p_po_id
617+
618+ def test_cancel_po_at_coordo(self):
619+ """
620+ Cancel the PO at coordo side.
621+ Check if the PO at project side is canceled.
622+ :return:
623+ """
624+ wiz_model = 'purchase.order.cancel.wizard'
625+ c_wiz_obj = self.c1.get(wiz_model)
626+ c_lc_wiz_obj = self.c1.get('sale.order.leave.close')
627+ c_cancel_so_wiz_obj = self.c1.get('sale.order.cancelation.wizard')
628+
629+ # Cancel PO at coordo side
630+ c_res = self.c_po_obj.purchase_cancel(self.c_po_id)
631+ # Validate cancellation
632+ w_res = c_wiz_obj.cancel_po(c_res.get('res_id'))
633+ # Close the FO
634+ w_line_ids = c_lc_wiz_obj.search([
635+ ('wizard_id', '=', w_res.get('res_id')),
636+ ('order_id', '=', self.c_so_id),
637+ ])
638+
639+
640+ # Choose close it
641+ c_lc_wiz_obj.write(w_line_ids, {'action': 'close'})
642+ c_cancel_so_wiz_obj.close_fo(w_res.get('res_id'))
643+
644+ self.synchronize(self.c1)
645+ self.synchronize(self.p1)
646+
647+ # Check state of the PO at project side
648+ p_po_state = self.p_po_obj.read(self.p_po_id, ['state'])['state']
649+ self.assert_(
650+ p_po_state == 'done',
651+ "The PO at project side is not closed",
652+ )
653+ # Check number of lines in PO at project side
654+ p_po_line_ids = self.p_pol_obj.search([('order_id', '=', self.p_po_id)])
655+ self.assert_(
656+ len(p_po_line_ids) == 0,
657+ "There is always lines in PO at project side"
658+ )
659+
660+ def cancel_or_resource_in_at_coordo(self, resource=False):
661+ """
662+ Cancel or Cancel & Resource the IN at coordo side.
663+ Check if the PO and the FO at coordo side are canceled.
664+ Check if the PO at project side is canceled.
665+ :return:
666+ """
667+ # Validate and confirm the PO
668+ self._validate_po(self.c1, [self.c_po_id])
669+ self._confirm_po(self.c1, [self.c_po_id])
670+
671+ # Get the IN associated to this PO
672+ c_in_ids = self.c_pick_obj.search([('purchase_id', '=', self.c_po_id), ('type', '=', 'in')])
673+ c_out_ids = self.c_pick_obj.search([('sale_id', '=', self.c_so_id), ('type', '=', 'out')])
674+ self.assert_(
675+ len(c_in_ids) == 1,
676+ "There are %s IN associated to PO - Should be 1" % len(c_in_ids),
677+ )
678+ self.assert_(
679+ len(c_out_ids) == 1,
680+ "There are %s OUT/PICK associated to FO - Should be 1" % len(c_out_ids),
681+ )
682+
683+ # Cancel the IN
684+ wiz_id = self.c_enter_reason_obj.create({
685+ 'picking_id': c_in_ids[0],
686+ 'change_reason': 'test_cancel_in_at_coordo',
687+ })
688+ ctx = {
689+ 'active_ids': c_in_ids,
690+ }
691+ if not resource:
692+ ctx['cancel_type'] = 'update_out'
693+
694+ self.c_enter_reason_obj.do_cancel([wiz_id], ctx)
695+
696+ # Check IN and OUT states
697+ in_state = self.c_pick_obj.read(c_in_ids, ['state'])
698+ out_state = self.c_pick_obj.read(c_out_ids, ['state'])
699+ self.assert_(
700+ all([x['state'] == 'cancel' for x in in_state]),
701+ "All IN are not canceled",
702+ )
703+ self.assert_(
704+ all([x['state'] == 'cancel' for x in out_state]),
705+ "All OUT/PICK are not canceled",
706+ )
707+
708+ # Check PO state
709+ po_state = self.c_po_obj.read(self.c_po_id, ['state'])['state']
710+ self.assert_(
711+ po_state == 'done',
712+ "The PO state is '%s' - Should be 'done'" % po_state,
713+ )
714+
715+ # Check FO state
716+ fo_state = self.c_so_obj.read(self.c_so_id, ['state'])['state']
717+ self.assert_(
718+ fo_state == 'done',
719+ "The FO state is '%s' - Should be 'done'" % fo_state,
720+ )
721+
722+ def test_cancel_in_at_coordo(self):
723+ """
724+ Cancel the IN at coordo side.
725+ Check if the PO and the FO at coordo side are canceled.
726+ Check if the PO at project side is canceled.
727+ :return:
728+ """
729+ self.cancel_or_resource_in_at_coordo()
730+
731+ def test_resource_in_at_coordo(self):
732+ """
733+ Cancel & Resource the IN at coordo side.
734+ Check if the PO and the FO at coordo side are canceled.
735+ Check if the PO at project side is canceled.
736+ :return:
737+ """
738+ self.cancel_or_resource_in_at_coordo(resource=True)
739+
740+def get_test_class():
741+ return UFTP326Test
742
743=== added file 'unifield_tests/tests/test_utp_1007.py'
744--- unifield_tests/tests/test_utp_1007.py 1970-01-01 00:00:00 +0000
745+++ unifield_tests/tests/test_utp_1007.py 2014-10-29 08:35:37 +0000
746@@ -0,0 +1,197 @@
747+#!/usr/bin/env python
748+# -*- coding: utf8 -*-
749+
750+__author__ = 'qt'
751+
752+from resourcing import ResourcingTest
753+
754+import time
755+
756+
757+class UTP1007Test(ResourcingTest):
758+
759+ def setUp(self):
760+ """
761+ Set the test as an IR test
762+
763+ 1/ Create an IR with one line of 100 PCE
764+ 2/ Source the IR to external partner
765+ 3/ Validate and confirm the PO
766+ 4/ Receive 98 PCE
767+ 5/ Cancel and resource the backorder
768+ """
769+ super(UTP1007Test, self).setUp()
770+ self.c_so_obj = self.c1.get('sale.order')
771+ self.c_sol_obj = self.c1.get('sale.order.line')
772+ self.c_po_obj = self.c1.get('purchase.order')
773+ self.c_pol_obj = self.c1.get('purchase.order.line')
774+ self.c_proc_obj = self.c1.get('stock.incoming.processor')
775+ self.c_proc_line_obj = self.c1.get('stock.move.in.processor')
776+ self.c_pick_obj = self.c1.get('stock.picking')
777+ self.c_enter_reason_obj = self.c1.get('enter.reason')
778+
779+ # Prepare values for the internal request
780+ prod_log1_id = self.get_record(self.c1, 'prod_log_1')
781+ uom_pce_id = self.get_record(self.c1, 'product_uom_unit', module='product')
782+ distrib_id = self.create_analytic_distribution(self.c1)
783+
784+ """
785+ 1/ Create an IR with one line of 10
786+
787+ """
788+ order_values = {
789+ 'procurement_request': True,
790+ 'location_requestor_id': self.get_record(self.c1, 'stock_location_stock', module='stock'),
791+ }
792+
793+ self.c_so_id = self.c_so_obj.create(order_values)
794+
795+ # Create order lines
796+ # First line
797+ line_values = {
798+ 'order_id': self.c_so_id,
799+ 'product_id': prod_log1_id,
800+ 'product_uom': uom_pce_id,
801+ 'product_uom_qty': 100.0,
802+ 'type': 'make_to_order',
803+ }
804+ self.c_sol_obj.create(line_values)
805+
806+ # Validate the sale order
807+ self.c1.exec_workflow('sale.order', 'procurement_validate', self.c_so_id)
808+
809+ """
810+ 2/ Source the IR to an external partner
811+ """
812+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
813+ self.c_sol_obj.write(line_ids, {
814+ 'po_cft': 'po',
815+ 'supplier': self.get_record(self.c1, 'ext_supplier_1'),
816+ })
817+ self.c_sol_obj.confirmLine(line_ids)
818+
819+ # Run the scheduler
820+ self.c_so_id = self.run_auto_pos_creation(self.c1, order_to_check=self.c_so_id)
821+
822+ line_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
823+ not_sourced = True
824+ while not_sourced:
825+ not_sourced = False
826+ for line in self.c_sol_obj.browse(line_ids):
827+ if line.procurement_id and line.procurement_id.state != 'running':
828+ not_sourced = True
829+ if not_sourced:
830+ time.sleep(1)
831+
832+ po_ids = set()
833+ po_line_ids = []
834+ for line in self.c_sol_obj.browse(line_ids):
835+ if line.procurement_id:
836+ po_line_ids.extend(self.c_pol_obj.search([
837+ ('procurement_id', '=', line.procurement_id.id),
838+ ]))
839+
840+ for po_line in self.c_pol_obj.read(po_line_ids, ['order_id']):
841+ po_ids.add(po_line['order_id'][0])
842+
843+ self.c_po_id = po_ids and list(po_ids)[0] or False
844+ self.c_so_name = self.c_so_obj.read(self.c_so_id, ['name'])['name']
845+
846+ """
847+ 3/ Validate and confirm the PO
848+ """
849+ self._validate_po(self.c1, [self.c_po_id])
850+ self._confirm_po(self.c1, [self.c_po_id])
851+
852+ """
853+ 4/ Receive 98 PCE
854+ """
855+ # Get the IN associated to this PO
856+ c_in_ids = self.c_pick_obj.search([('purchase_id', '=', self.c_po_id), ('type', '=', 'in')])
857+ self.assert_(
858+ len(c_in_ids) == 1,
859+ "There are %s IN associated to PO - Should be 1" % len(c_in_ids),
860+ )
861+
862+ self.c_in_id = c_in_ids[0]
863+
864+ wiz_res = self.c_pick_obj.action_process(self.c_in_id)
865+ proc_line_ids = self.c_proc_line_obj.search([('wizard_id', '=', wiz_res['res_id'])])
866+ self.c_proc_line_obj.write(proc_line_ids, {'quantity': 98.0})
867+ bo_res = self.c_proc_obj.do_incoming_shipment([wiz_res['res_id']])
868+
869+ def test_cancel_bo(self):
870+ """
871+ Cancel the backorder without resourcing and check the quantity in
872+ FO line
873+ """
874+ # Cancel the back order
875+ wiz_id = self.c_enter_reason_obj.create({
876+ 'picking_id': self.c_in_id,
877+ 'change_reason': 'test_cancel_bo',
878+ })
879+ self.c_enter_reason_obj.do_cancel([wiz_id], {
880+ 'active_ids': [self.c_in_id],
881+ 'cancel_type': 'update_out',
882+ })
883+
884+ # Check IN state
885+ in_state = self.c_pick_obj.read(self.c_in_id, ['state'])['state']
886+ self.assert_(
887+ in_state == 'cancel',
888+ "The BO is not canceled",
889+ )
890+
891+ # Check quantity on the original IR line
892+ sol_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
893+ sol_qty = self.c_sol_obj.read(sol_ids[0], ['product_uom_qty'])['product_uom_qty']
894+ self.assert_(
895+ sol_qty == 100.0,
896+ "The quantity on original IR is %s - Should be 100.00" % sol_qty
897+ )
898+
899+ def test_resource_bo(self):
900+ """
901+ Cancel & Resource the backorder without resourcing and check the
902+ quantity in FO line
903+ """
904+ # Cancel the back order
905+ wiz_id = self.c_enter_reason_obj.create({
906+ 'picking_id': self.c_in_id,
907+ 'change_reason': 'test_cancel_bo',
908+ })
909+ self.c_enter_reason_obj.do_cancel([wiz_id], {
910+ 'active_ids': [self.c_in_id],
911+ 'cancel_type': '',
912+ })
913+
914+ # Check IN state
915+ in_state = self.c_pick_obj.read(self.c_in_id, ['state'])['state']
916+ self.assert_(
917+ in_state == 'cancel',
918+ "The BO is not canceled",
919+ )
920+
921+ # Check quantity on the original IR line
922+ sol_ids = self.c_sol_obj.search([('order_id', '=', self.c_so_id)])
923+ sol_qty = self.c_sol_obj.read(sol_ids[0], ['product_uom_qty'])['product_uom_qty']
924+ self.assert_(
925+ sol_qty == 98.0,
926+ "The quantity on original IR is %s - Should be 98.00" % sol_qty
927+ )
928+
929+ # Check quantity on new IR line
930+ new_ir_ids = self.c_so_obj.search([('parent_order_name', '=', self.c_so_name), ('procurement_request', '=', True)])
931+ self.assert_(
932+ len(new_ir_ids) == 1,
933+ "No new order created after resourcing",
934+ )
935+ sol_ids = self.c_sol_obj.search([('order_id', '=', new_ir_ids[0])])
936+ sol_qty = self.c_sol_obj.read(sol_ids[0], ['product_uom_qty'])['product_uom_qty']
937+ self.assert_(
938+ sol_qty == 2.0,
939+ "The quantity on original IR is %s - Should be 2.00" % sol_qty
940+ )
941+
942+def get_test_class():
943+ return UTP1007Test
944
945=== modified file 'unifield_tests/tests/unifield_test.py'
946--- unifield_tests/tests/unifield_test.py 2014-10-14 11:44:42 +0000
947+++ unifield_tests/tests/unifield_test.py 2014-10-29 08:35:37 +0000
948@@ -141,4 +141,45 @@
949
950 return False
951
952+ def synchronize(self, db=None):
953+ '''
954+ Connect the 'db' database to the sync. server
955+ and run synchronization.
956+ If no database givent in parameters, sync. all
957+ databases.
958+ :param db: DB connection to synchronize (can be None
959+ or a list.
960+ :return: True
961+ '''
962+ if not db:
963+ for db_conn in self.db:
964+ self.synchronize(db=db_conn)
965+
966+ if db and isinstance(db, list):
967+ for db_conn in db:
968+ self.synchronize(db=db_conn)
969+
970+ conn_obj = db.get('sync.client.sync_server_connection')
971+ sync_obj = db.get('sync.client.sync_manager')
972+
973+ conn_ids = conn_obj.search([])
974+ conn_obj.action_connect(conn_ids)
975+ sync_ids = sync_obj.search([])
976+ sync_obj.sync(sync_ids)
977+
978+ def get_db_partner_name(self, db):
979+ '''
980+ Return the name of partner associated
981+ to the company of the database
982+ :param db: DB connection of which we
983+ get the partner.
984+ :return: Name of the partner associated
985+ to the company of the database
986+ '''
987+ company_obj = db.get('res.company')
988+
989+ company_ids = company_obj.search([])
990+ return company_obj.browse(company_ids[0]).partner_id.name
991+
992+
993 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
994
995=== modified file 'unifield_tests/unifield.config'
996--- unifield_tests/unifield.config 2014-10-13 07:28:32 +0000
997+++ unifield_tests/unifield.config 2014-10-29 08:35:37 +0000
998@@ -3,7 +3,7 @@
999 port: 8069
1000
1001 [DB]
1002-db_prefix: unifield_test_
1003+db_prefix: uftp-326_
1004 username: admin
1005 password: admin
1006 # If tempo_mkdb is True, it means you use mkdb from OpenERP to create DB. If not, you use tempo's one.

Subscribers

People subscribed via source and target branches