[FIX] sale: UOM qty should be consider if UOS is not specified on creating shipment.
[odoo/odoo.git] / addons / sale / test / order_process.yml
1 -
2   In order to test process of the Sale Order,
3 -
4   First I check the total amount of the Quotation before Approved.
5 -
6   !assert {model: sale.order, id: order, string: The amount of the Quotation is not correctly computed}:
7     - sum([l.price_subtotal for l in order_line]) == amount_untaxed
8 -
9   I confirm the quotation with "Invoice based on deliveries" policy.
10 -
11   !workflow {model: sale.order, action: order_confirm, ref: order}
12 -
13   I check that invoice should not created before dispatch delivery.
14 -
15   !python {model: sale.order}: |
16     order = self.pool.get('sale.order').browse(cr, uid, ref("order"))
17     assert len(order.invoice_ids) == False, "Invoice should not created."
18 -
19   I check the details of procurement after confirmed quotation.
20 -
21   !python {model: sale.order}: |
22     from datetime import datetime, timedelta
23     from dateutil.relativedelta import relativedelta
24     from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
25     order = self.browse(cr, uid, ref("order"))
26     for order_line in order.order_line:
27         procurement = order_line.procurement_id
28         date_planned = datetime.strptime(order.date_order, DEFAULT_SERVER_DATE_FORMAT) + relativedelta(days=order_line.delay or 0.0)
29         date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
30         assert procurement.date_planned == date_planned, "Scheduled date is not correspond."
31         assert procurement.product_id.id == order_line.product_id.id, "Product is not correspond."
32         assert procurement.product_qty == order_line.product_uom_qty, "Qty is not correspond."
33         assert procurement.product_uom.id == order_line.product_uom.id, "UOM is not correspond."
34         assert procurement.procure_method == order_line.type, "Procurement method is not correspond."
35 -
36   I run the scheduler.
37 -
38   !python {model: procurement.order}: |
39     self.run_scheduler(cr, uid)
40 -
41   I check the details of delivery order after confirmed quotation.
42 -
43   !python {model: sale.order}: |
44     from datetime import datetime, timedelta
45     from dateutil.relativedelta import relativedelta
46     from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
47     sale_order = self.browse(cr, uid, ref("order"))
48     assert sale_order.picking_ids, "Delivery order is not created."
49     for picking in sale_order.picking_ids:
50       assert picking.state == "auto" or "confirmed", "Delivery order should be in 'Waitting Availability' state."
51       assert picking.origin == sale_order.name,"Origin of Delivery order is not correspond with sequence number of sale order."
52       assert picking.type == 'out',"Shipment should be Outgoing."
53       assert picking.move_type == sale_order.picking_policy,"Delivery Method is not corresponding with delivery method of sale order."
54       assert picking.address_id.id == sale_order.partner_shipping_id.id,"Shipping Address is not correspond with sale order."
55       assert picking.note == sale_order.note,"Note is not correspond with sale order."
56       assert picking.invoice_state == (sale_order.order_policy=='picking' and '2binvoiced') or 'none',"Invoice policy is not correspond with sale order."
57       assert len(picking.move_lines) == len(sale_order.order_line), "Total move of delivery order are not corresposning with total sale order lines."
58       location_id = sale_order.shop_id.warehouse_id.lot_stock_id.id
59       output_id = sale_order.shop_id.warehouse_id.lot_output_id.id
60       for move in picking.move_lines:
61          order_line = move.sale_line_id
62          date_planned = datetime.strptime(sale_order.date_order, DEFAULT_SERVER_DATE_FORMAT) + relativedelta(days=order_line.delay or 0.0)
63          date_planned = (date_planned - timedelta(days=sale_order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
64          assert datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) == datetime.strptime(date_planned, DEFAULT_SERVER_DATETIME_FORMAT), "Excepted Date is not correspond with Planned Date."
65          assert move.product_id.id == order_line.product_id.id,"Product is not correspond."
66          assert move.product_qty == order_line.product_uom_qty,"Product Quantity is not correspond."
67          assert move.product_uom.id == order_line.product_uom.id,"Product UOM is not correspond."
68          assert move.product_uos_qty == (order_line.product_uos and order_line.product_uos_qty) or order_line.product_uom_qty,"Product UOS Quantity is not correspond."
69          assert move.product_uos == (order_line.product_uos and order_line.product_uos.id) or order_line.product_uom.id,"Product UOS is not correspond"
70          assert move.product_packaging.id == order_line.product_packaging.id,"Product packaging is not correspond."
71          assert move.address_id.id == order_line.address_allotment_id.id or sale_order.partner_shipping_id.id,"Address is not correspond"
72          #assert move.location_id.id == location_id,"Source Location is not correspond."
73          #assert move.location_dest_id == output_id,"Destination Location is not correspond."
74          assert move.note == order_line.notes,"Note is not correspond"
75          assert move.price_unit == order_line.product_id.standard_price or 0.0,"Price Unit is not correspond"
76 -
77   Now, I dispatch delivery order.
78 -
79   !python {model: stock.partial.picking}: |
80     order = self.pool.get('sale.order').browse(cr, uid, ref("order"))
81     for pick in order.picking_ids:
82         data = pick.force_assign()
83         if data == True:
84           partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [pick.id]})
85           self.do_partial(cr, uid, [partial_id])
86 -
87   I check sale order to verify shipment.
88 -
89   !python {model: sale.order}: |
90     order = self.pool.get('sale.order').browse(cr, uid, ref("order"))
91     assert order.shipped == True, "Sale order is not Delivered."
92     assert order.picked_rate == 100, "Shipment progress is not 100%."
93     assert len(order.invoice_ids) == False, "Invoice should not created on dispatch delivery order."
94 -
95   I create Invoice from Delivery Order.
96 -
97   !python {model: stock.invoice.onshipping}: |
98     sale = self.pool.get('sale.order')
99     sale_order = sale.browse(cr, uid, ref("order"))
100     ship_ids = [x.id for x in sale_order.picking_ids]
101     wiz_id = self.create(cr, uid, {'journal_id': ref('account.sales_journal')},
102       {'active_ids': ship_ids, 'active_model': 'stock.picking'})
103     self.create_invoice(cr, uid, [wiz_id], {"active_ids": ship_ids, "active_id": ship_ids[0]})
104 -
105   I check the invoice details after dispatched delivery.
106 -
107   !python {model: sale.order}: |
108     order = self.browse(cr, uid, ref("order"))
109     assert order.invoice_ids, "Invoice is not created."
110     ac = order.partner_id.property_account_receivable.id
111     journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'sale'), ('company_id', '=', order.company_id.id)], limit=1)
112
113     for invoice in order.invoice_ids:
114       assert invoice.type == 'out_invoice',"Invoice should be Customer Invoice."
115       assert invoice.account_id.id == ac,"Invoice account is not correspond."
116       assert invoice.reference == order.client_order_ref or order.name,"Reference is not correspond."
117       assert invoice.partner_id.id == order.partner_id.id,"Customer is not correspond."
118       assert invoice.address_invoice_id.id == order.partner_invoice_id.id,"Invoice Address is not correspond."
119       assert invoice.currency_id.id == order.pricelist_id.currency_id.id, "Currency is not correspond."
120       assert invoice.comment == order.note or '',"Note is not correspond."
121       assert invoice.journal_id.id == journal_ids[0],"Sales Journal is not link on Invoice."
122       assert invoice.payment_term.id == order.payment_term.id, "Payment term is not correspond."
123       for so_line in order.order_line:
124         inv_line = so_line.invoice_lines[0]
125         ac = so_line.product_id.product_tmpl_id.property_account_income.id or so_line.product_id.categ_id.property_account_income_categ.id
126         assert inv_line.product_id.id == so_line.product_id.id or False,"Product is not correspond"
127         assert inv_line.account_id.id == ac,"Account of Invoice line is not corresponding."
128         assert inv_line.uos_id.id == (so_line.product_uos and so_line.product_uos.id) or so_line.product_uom.id, "Product UOS is not correspond."
129         assert inv_line.price_unit == so_line.price_unit , "Price Unit is not correspond."
130         assert inv_line.quantity == (so_line.product_uos and so_line.product_uos_qty) or so_line.product_uom_qty , "Product qty is not correspond."
131         assert inv_line.price_subtotal == so_line.price_subtotal, "Price sub total is not correspond."
132 -
133   Now I confirm the Quotation with "Invoice on order after delivery" policy.
134 -
135   !workflow {model: sale.order, action: order_confirm, ref: order2}
136 -
137   I check that related delivery order after confirmed.
138 -
139   !python {model: sale.order}: |
140     sale_order = self.browse(cr, uid, ref("order2"))
141     assert sale_order.picking_ids, "Delivery Order should be created."
142     assert len(sale_order.invoice_ids) == False, "Invoice should be not created."
143 -
144   Now, I dispatch delivery order.
145 -
146   !python {model: stock.partial.picking}: |
147     order = self.pool.get('sale.order').browse(cr, uid, ref("order2"))
148     for pick in order.picking_ids:
149         data = pick.force_assign()
150         if data == True:
151           partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [pick.id]})
152           self.do_partial(cr, uid, [partial_id])
153 -
154   I check that an invoice has been created.
155 -
156   !python {model: sale.order}: |
157     order = self.browse(cr, uid, ref("order2"))
158     #assert order.invoice_ids, "Invoice should be created after dispatch delivery order."
159 -
160   Now I confirm the Quotation with "Pay before delivery" policy.
161 -
162   !workflow {model: sale.order, action: order_confirm, ref: order3}
163 -
164   I check that delivery order should not created before invoice is paid.
165 -
166   !python {model: sale.order}: |
167     sale_order = self.browse(cr, uid, ref("order3"))
168     assert len(sale_order.picking_ids) == False, "Delivery order should not created before invoice."
169     assert sale_order.invoice_ids, "Invoice should be created."
170 -
171   I confirm the Quotation with "Deliver & invoice on demand".
172 -
173   !workflow {model: sale.order, action: order_confirm, ref: order4}
174 -
175   I check that Invoice should not created.
176 -
177   !python {model: sale.order}: |
178     sale_order = self.browse(cr, uid, ref("order4"))
179     assert len(sale_order.invoice_ids) == False, "Invoice should not created."
180     assert sale_order.picking_ids, "Delivery order should be created."
181 -
182   I create advance invoice.
183 -
184   !python {model: sale.advance.payment.inv}: |
185     ctx = context.copy()
186     ctx.update({"active_model": 'sale.order', "active_ids": [ref("order4")], "active_id":ref("order4")})
187     order_line = self.pool.get('sale.order.line').browse(cr, uid, ref("line7"), context=context)
188     pay_id = self.create(cr, uid, {'product_id': order_line.product_id.id, 'amount': order_line.price_subtotal, 'qtty': order_line.product_uom_qty})
189     self.create_invoices(cr, uid, [pay_id], context=ctx)
190 -
191   I check Invoice which made advance
192 -
193   !python {model: sale.order}: |
194     order = self.browse(cr, uid, ref('order4'))
195     assert order.invoice_ids, "Invoice should be created after make advance invoice."
196 -
197   I create Invoice from sale order line.
198 -
199   !python {model: sale.order.line.make.invoice}: |
200     ctx = context.copy()
201     ctx.update({"active_model": 'sale.order.line', "active_ids": [ref("line8")], "active_id":ref("line8")})
202     self.make_invoices(cr, uid, [], context=ctx)
203 -
204   I check Invoice which made from sale order line.
205 -
206   !python {model: sale.order.line}: |
207     line = self.browse(cr, uid, ref('line8'))
208     assert line.invoice_lines, "Invoice line should be created."
209 -
210   I create manual Invoice for order.
211 -
212   !record {model: sale.make.invoice, id: sale_make_invoice_1}:
213     invoice_date: !eval time.strftime('%Y-%m-%d')
214 -
215   !python {model: sale.make.invoice}: |
216     ctx = context.copy()
217     ctx = ctx.update({"active_model": 'sale.order', "active_ids": [ref("order4")], "active_id":ref("order4")})
218     self.make_invoices(cr, uid, [ref("sale_make_invoice_1")], context)
219 -
220   I check Invoice after do manual.
221 -
222   !python {model: sale.order}: |
223     sale_order = self.browse(cr, uid, ref("order4"))
224     assert sale_order.invoice_ids, "Invoice should be created."
225 -
226   I open the Invoice.
227 -
228   !python {model: sale.order}: |
229     import netsvc
230     wf_service = netsvc.LocalService("workflow")
231     so = self.browse(cr, uid, ref("order4"))
232     for invoice in so.invoice_ids:
233       wf_service.trg_validate(uid, 'account.invoice', invoice.id, 'invoice_open', cr)
234     assert so.invoiced_rate == 100, "Invoiced Progress is not 100%."
235
236 -
237   I set order policy "Deliver & invoice on demand" as default policy.
238 -
239   !record {model: sale.config.picking_policy, id: sale.config.picking_policy_0}:
240     order_policy: 'manual'
241 -
242   !python {model: sale.config.picking_policy}: |
243     self.execute(cr, uid, [ref("sale.config.picking_policy_0")])
244 -
245   I print a sale order report.
246 -
247   !python {model: sale.order}: |
248     import netsvc, tools, os
249     (data, format) = netsvc.LocalService('report.sale.order').create(cr, uid, [ref('order')], {}, {})
250     if tools.config['test_report_directory']:
251         file(os.path.join(tools.config['test_report_directory'], 'sale-sale_order.'+format), 'wb+').write(data)
252