[IMP] purchase: Convert yml files to python and xml
This commit is contained in:
committed by
Yannick Tivisse
parent
2d5aefb72f
commit
aa13ed876e
@@ -15,7 +15,6 @@
|
||||
'security/ir.model.access.csv',
|
||||
'views/account_invoice_views.xml',
|
||||
'data/purchase_data.xml',
|
||||
'data/purchase_data.yml',
|
||||
'report/purchase_reports.xml',
|
||||
'views/purchase_views.xml',
|
||||
'views/stock_views.xml',
|
||||
@@ -28,22 +27,8 @@
|
||||
'report/purchase_order_templates.xml',
|
||||
'report/purchase_quotation_templates.xml',
|
||||
],
|
||||
'test': [
|
||||
'../account/test/account_minimal_test.xml',
|
||||
'test/stock_valuation_account.xml',
|
||||
'test/ui/purchase_users.yml',
|
||||
'test/process/run_scheduler.yml',
|
||||
'test/fifo_price.yml',
|
||||
'test/fifo_returns.yml',
|
||||
'test/process/cancel_order.yml',
|
||||
'test/ui/duplicate_order.yml',
|
||||
'test/ui/delete_order.yml',
|
||||
'test/average_price.yml',
|
||||
],
|
||||
'demo': [
|
||||
'data/purchase_order_demo.yml',
|
||||
'data/purchase_demo.xml',
|
||||
'data/purchase_stock_demo.yml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
|
||||
@@ -36,5 +36,10 @@
|
||||
<field name="padding">5</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
<!-- enable purchase on main warehouse -->
|
||||
<record id="stock.warehouse0" model="stock.warehouse">
|
||||
<field name="buy_to_resupply" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
-
|
||||
!python {model: stock.warehouse, id: stock.warehouse0}: |
|
||||
#enable purchase on main warehouse
|
||||
self.write({'buy_to_resupply': True})
|
||||
|
||||
@@ -22,5 +22,170 @@
|
||||
<field name="route_ids" eval="[(4,ref('route_warehouse0_buy'))]"></field>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<record id="purchase_order_1" model="purchase.order">
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="order_line" model="purchase.order.line" eval="[(5, 0, 0),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_delivery_01'),
|
||||
'name': 'RAM SR3',
|
||||
'price_unit': 79.80,
|
||||
'product_qty': 15.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_25'),
|
||||
'name': 'Laptop E5023',
|
||||
'price_unit': 2868.70,
|
||||
'product_qty': 5.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_27'),
|
||||
'name': 'Laptop Customized',
|
||||
'price_unit': 3297.20,
|
||||
'product_qty': 4.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')})
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_2" model="purchase.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="order_line" model="purchase.order.line" eval="[(5, 0, 0),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_delivery_02'),
|
||||
'name': 'Multimedia Speakers',
|
||||
'price_unit': 132.50,
|
||||
'product_qty': 20.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_delivery_01'),
|
||||
'name': 'Pen drive, SP-2',
|
||||
'price_unit': 89.0,
|
||||
'product_qty': 5.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_3" model="purchase.order">
|
||||
<field name="partner_id" ref="base.res_partner_12"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="order_line" model="purchase.order.line" eval="[(5, 0, 0),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_2'),
|
||||
'name': 'Support Services',
|
||||
'price_unit': 25.50,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_4" model="purchase.order">
|
||||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="order_line" model="purchase.order.line" eval="[(5, 0, 0),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_delivery_02'),
|
||||
'name': 'RAM SR2 (kit)',
|
||||
'price_unit': 85.50,
|
||||
'product_qty': 6.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_20'),
|
||||
'name': 'Motherboard I9P57',
|
||||
'price_unit': 1690.0,
|
||||
'product_qty': 5.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_6'),
|
||||
'name': 'iPad Mini',
|
||||
'price_unit': 800.0,
|
||||
'product_qty': 7.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')})
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_5" model="purchase.order">
|
||||
<field name="partner_id" ref="base.res_partner_2"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="order_line" model="purchase.order.line" eval="[(5, 0, 0),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_22'),
|
||||
'name': 'Processor Core i5 2.70 Ghz',
|
||||
'price_unit': 2010.0,
|
||||
'product_qty': 3.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_24'),
|
||||
'name': 'Graphics Card',
|
||||
'price_unit': 876.0,
|
||||
'product_qty': 3.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_6" model="purchase.order">
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="order_line" model="purchase.order.line" eval="[(5, 0, 0),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_delivery_02'),
|
||||
'name': 'Ink Cartridge',
|
||||
'price_unit': 58.0,
|
||||
'product_qty': 9.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_delivery_01'),
|
||||
'name': 'Toner Cartridge',
|
||||
'price_unit': 65.0,
|
||||
'product_qty': 3.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.consu_delivery_01'),
|
||||
'name': 'GrapWorks Software',
|
||||
'price_unit': 154.5,
|
||||
'product_qty': 4.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_7" model="purchase.order">
|
||||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="order_line" model="purchase.order.line" eval="[(5, 0, 0),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_product_12'),
|
||||
'name': 'Mouse, Wireless',
|
||||
'price_unit': 13.5,
|
||||
'product_qty': 5.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'product_id': ref('product.product_delivery_02'),
|
||||
'name': 'Webcam',
|
||||
'price_unit': 38.0,
|
||||
'product_qty': 15.0,
|
||||
'product_uom': ref('product.product_uom_unit'),
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
<record id="stock.stock_warehouse_shop0" model="stock.warehouse">
|
||||
<field name="buy_to_resupply" eval="True"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
-
|
||||
Give access rights of Purchase user to create purchase order
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_1}:
|
||||
partner_id: base.res_partner_1
|
||||
-
|
||||
!record {model: purchase.order.line, id: purchase_order_line_1}:
|
||||
order_id: purchase.purchase_order_1
|
||||
product_id: product.product_delivery_01
|
||||
name: RAM SR3
|
||||
price_unit: 79.80
|
||||
product_qty: 15.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
!record {model: purchase.order.line, id: purchase_order_line_2}:
|
||||
order_id: purchase_order_1
|
||||
product_id: product.product_product_25
|
||||
name: Laptop E5023
|
||||
price_unit: 2868.70
|
||||
product_qty: 5.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
!record {model: purchase.order.line, id: purchase_order_line_3}:
|
||||
order_id: purchase_order_1
|
||||
product_id: product.product_product_27
|
||||
name: Laptop Customized
|
||||
price_unit: 3297.20
|
||||
product_qty: 4.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
Creating second order
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_2}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product.product_delivery_02
|
||||
name: Multimedia Speakers
|
||||
price_unit: 132.50
|
||||
product_qty: 20.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product.product_delivery_01
|
||||
name: Pen drive, SP-2
|
||||
price_unit: 89
|
||||
product_qty: 5
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_3}:
|
||||
partner_id: base.res_partner_12
|
||||
order_line:
|
||||
- product_id: product.product_product_2
|
||||
name: Support Services
|
||||
price_unit: 25.50
|
||||
product_qty: 10.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_4}:
|
||||
partner_id: base.res_partner_4
|
||||
order_line:
|
||||
- product_id: product.product_delivery_02
|
||||
name: RAM SR2 (kit)
|
||||
price_unit: 85.50
|
||||
product_qty: 6.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product.product_product_20
|
||||
name: Motherboard I9P57
|
||||
price_unit: 1690
|
||||
product_qty: 5.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product.product_product_6
|
||||
name: iPad Mini
|
||||
price_unit: 800
|
||||
product_qty: 7.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_5}:
|
||||
partner_id: base.res_partner_2
|
||||
order_line:
|
||||
- product_id: product.product_product_22
|
||||
name: Processor Core i5 2.70 Ghz
|
||||
product_qty: 3
|
||||
price_unit: 2010
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product.product_product_24
|
||||
name: Graphics Card
|
||||
product_qty: 3
|
||||
price_unit: 876
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_6}:
|
||||
partner_id: base.res_partner_1
|
||||
order_line:
|
||||
- product_id: product.product_delivery_02
|
||||
name: Ink Cartridge
|
||||
price_unit: 58
|
||||
product_qty: 9
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product.product_delivery_01
|
||||
name: Toner Cartridge
|
||||
product_qty: 3
|
||||
price_unit: 65
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product.consu_delivery_01
|
||||
name: GrapWorks Software
|
||||
product_qty: 4
|
||||
price_unit: 154.5
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_7}:
|
||||
partner_id: base.res_partner_4
|
||||
order_line:
|
||||
- product_id: product.product_product_12
|
||||
name: Mouse, Wireless
|
||||
product_qty: 5
|
||||
price_unit: 13.5
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product.product_delivery_02
|
||||
name: Webcam
|
||||
product_qty: 15
|
||||
price_unit: 38.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
@@ -1,8 +0,0 @@
|
||||
-
|
||||
!python {model: stock.warehouse, id: False}: |
|
||||
pull_obj = self.env['procurement.rule']
|
||||
wh_to_assign = ['stock_warehouse_shop0']
|
||||
for wh_ref in wh_to_assign:
|
||||
warehouse = self.browse(ref('stock.' + wh_ref))
|
||||
#Force the rewriting of route and rule
|
||||
warehouse.write({'buy_to_resupply': True})
|
||||
@@ -1,134 +0,0 @@
|
||||
-
|
||||
Set a product as using average price.
|
||||
-
|
||||
!record {model: product.product, id: product_average_icecream}:
|
||||
default_code: AVG
|
||||
name: Average Ice Cream
|
||||
type: product
|
||||
categ_id: product.product_category_1
|
||||
uom_id: product.product_uom_kgm
|
||||
uom_po_id: product.product_uom_kgm
|
||||
valuation: real_time
|
||||
cost_method: average
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description: Average Ice Cream can be mass-produced and thus is widely available in developed parts of the world. Ice cream can be purchased in large cartons (vats and squrounds) from supermarkets and grocery stores, in smaller quantities from ice cream shops, convenience stores, and milk bars, and in individual servings from small carts or vans at public events.
|
||||
-
|
||||
I create a draft Purchase Order for first incoming shipment for 10 pieces at 60€
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_average1}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_average_icecream
|
||||
product_qty: 10.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 60.0
|
||||
name: 'Average Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the first purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_average1}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
I check the "Approved" status of purchase order 1
|
||||
-
|
||||
!assert {model: purchase.order, id: purchase_order_average1}:
|
||||
- state == 'purchase'
|
||||
-
|
||||
Process the reception of purchase order 1
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_average1}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Check the average price of the product (average icecream).
|
||||
-
|
||||
!python {model: product.product, id: product_average_icecream}: |
|
||||
assert self.qty_available == 10.0, 'Wrong quantity in stock after first reception'
|
||||
assert self.standard_price == 60.0, 'Standard price should be the price of the first reception!'
|
||||
-
|
||||
I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_average2}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_average_icecream
|
||||
product_qty: 30.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 80.0
|
||||
name: 'Average Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the second purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_average2}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order 2
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_average2}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Check the standard price
|
||||
-
|
||||
!python {model: product.product, id: product_average_icecream}: |
|
||||
assert self.standard_price == 75.0, 'After second reception, we should have an average price of 75.0 on the product'
|
||||
-
|
||||
Create picking to send some goods
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_average_shipment}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Create move for picking
|
||||
-
|
||||
!record {model: stock.move, id: outgoing_shipment_average_icecream}:
|
||||
picking_id: outgoing_average_shipment
|
||||
product_id: product_average_icecream
|
||||
product_uom: product.product_uom_kgm
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
product_uom_qty: 20.0
|
||||
-
|
||||
I assign this outgoing shipment and process the delivery
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_average_shipment}: |
|
||||
self.action_assign()
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, self.id)]}).process()
|
||||
-
|
||||
Check the standard price (60 * 10 + 30 * 80) / 40 = 75.0 did not change
|
||||
-
|
||||
!python {model: product.product, id: product_average_icecream}: |
|
||||
assert self.standard_price == 75.0, 'Average price should not have changed with outgoing picking!'
|
||||
assert self.qty_available == 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong'
|
||||
-
|
||||
Make a new purchase order with 500 g Average Ice Cream at a price of 0.2€/g
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_average3}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_average_icecream
|
||||
product_qty: 0.5
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 200
|
||||
name: 'Average Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the first purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_average3}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order 3 in grams
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_average3}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Check price is (75.0*20 + 200*0.5) / 20.5 = 78.04878
|
||||
-
|
||||
!python {model: product.product, id: product_average_icecream}: |
|
||||
assert self.qty_available == 20.5, 'Reception of purchase order in grams leads to wrong quantity in stock'
|
||||
assert round(self.standard_price, 2) == 78.05, 'Standard price as average price of third reception with other UoM incorrect! Got %s instead of 78.05' % (round(self.standard_price, 2),)
|
||||
@@ -1,372 +0,0 @@
|
||||
-
|
||||
Set the company currency as EURO for the sake of repeatibility
|
||||
-
|
||||
!python {model: res.company}: |
|
||||
company = self.env.ref('base.main_company')
|
||||
company.currency_id = self.env.ref('base.EUR')
|
||||
-
|
||||
Set a product as using fifo price
|
||||
-
|
||||
!record {model: product.product, id: product_fifo_icecream}:
|
||||
default_code: FIFO
|
||||
name: FIFO Ice Cream
|
||||
type: product
|
||||
categ_id: product.product_category_1
|
||||
list_price: 100.0
|
||||
standard_price: 70.0
|
||||
uom_id: product.product_uom_kgm
|
||||
uom_po_id: product.product_uom_kgm
|
||||
cost_method: fifo
|
||||
valuation: real_time
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description: FIFO Ice Cream can be mass-produced and thus is widely available in developed parts of the world. Ice cream can be purchased in large cartons (vats and squrounds) from supermarkets and grocery stores, in smaller quantities from ice cream shops, convenience stores, and milk bars, and in individual servings from small carts or vans at public events.
|
||||
-
|
||||
I create a draft Purchase Order for first in move for 10 kg at 50 euro
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fifo1}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_fifo_icecream
|
||||
product_qty: 10.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 50.0
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the first purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo1}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
I check the "Purchase" status of purchase order 1
|
||||
-
|
||||
!assert {model: purchase.order, id: purchase_order_fifo1}:
|
||||
- state == 'purchase'
|
||||
-
|
||||
Process the reception of purchase order 1 and set date
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo1}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Check the standard price of the product (fifo icecream), that should have not changed because the standard price is supposed to be updated only when goods are going out of the stock
|
||||
-
|
||||
!python {model: product.product, id: product_fifo_icecream}: |
|
||||
assert self.standard_price == 70.0, 'Standard price should not have changed!'
|
||||
assert self.stock_value == 500.0, 'Wrong stock value'
|
||||
-
|
||||
I create a draft Purchase Order for second shipment for 30 kg at 80 euro
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fifo2}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_fifo_icecream
|
||||
product_qty: 30.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 80.0
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the second purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo2}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order 2
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo2}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Check the standard price of the product, that should have not changed because the standard price is supposed to be updated only when goods are going out of the stock
|
||||
-
|
||||
!python {model: product.product, id: product_fifo_icecream}: |
|
||||
assert self.standard_price == 70.0, 'Standard price as fifo price of second reception incorrect!'
|
||||
assert self.stock_value == 2900.0, 'Stock valuation should be 2900'
|
||||
-
|
||||
Let us send some goods
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Picking needs movement from stock
|
||||
-
|
||||
!record {model: stock.move, id: outgoing_shipment_fifo_icecream}:
|
||||
picking_id: outgoing_fifo_shipment
|
||||
product_id: product_fifo_icecream
|
||||
product_uom: product.product_uom_kgm
|
||||
product_uom_qty: 20.0
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
I assign this outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment}: |
|
||||
self.action_assign()
|
||||
-
|
||||
Process the delivery of the outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment}: |
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, self.id)]}).process()
|
||||
-
|
||||
Check stock valuation is 1600
|
||||
-
|
||||
!python {model: product.product, id: product_fifo_icecream}: |
|
||||
assert self.stock_value == 1600.0, 'Stock valuation should be 1600'
|
||||
-
|
||||
Do a delivery of an extra 500 g (delivery order)
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment_uom}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Picking needs movement from stock
|
||||
-
|
||||
!record {model: stock.move, id: outgoing_shipment_fifo_icecream_gram}:
|
||||
picking_id: outgoing_fifo_shipment_uom
|
||||
product_id: product_fifo_icecream
|
||||
product_uom: product.product_uom_kgm
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
product_uom_qty: 0.5
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
I assign this outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_uom}: |
|
||||
self.action_assign()
|
||||
-
|
||||
Process the delivery of the outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_uom}: |
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, self.id)]}).process()
|
||||
-
|
||||
Check stock valuation and qty in stock
|
||||
-
|
||||
!python {model: product.product, id: product_fifo_icecream}: |
|
||||
assert self.stock_value == 1560.0, 'Stock valuation should be 1560'
|
||||
assert self.qty_available == 19.5, 'Should still have 19.5 in stock'
|
||||
-
|
||||
We will temporarily change the currency rate on the sixth of June to have the same results all year
|
||||
-
|
||||
!record {model: res.currency, id: new_USD}:
|
||||
name: new_usd
|
||||
symbol: "$"
|
||||
rate_ids:
|
||||
- rate: 1.2834
|
||||
name: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I create a draft Purchase Order for 30000 g at 0.150 USD/g and 10 kg at 150 USD/kg
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fifo_usd}:
|
||||
partner_id: base.res_partner_3
|
||||
currency_id: new_USD
|
||||
order_line:
|
||||
- product_id: product_fifo_icecream
|
||||
product_qty: 30
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 0.150
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
- product_id: product_fifo_icecream
|
||||
product_qty: 10.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 150.0
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the purchase order in USD
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo_usd}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order with usd
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo_usd}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
We create delivery order of 49.5 kg
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment_cur}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Picking needs movement from stock
|
||||
-
|
||||
!record {model: stock.move, id: outgoing_shipment_fifo_icecream_cur}:
|
||||
picking_id: outgoing_fifo_shipment_cur
|
||||
product_id: product_fifo_icecream
|
||||
product_uom: product.product_uom_kgm
|
||||
product_uom_qty: 49.5
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
I assign this outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_cur}: |
|
||||
self.action_assign()
|
||||
-
|
||||
Process the delivery of the outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_cur}: |
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, self.id)]}).process()
|
||||
-
|
||||
Do a delivery of an extra 10 kg
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment_ret}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Picking needs movement from stock
|
||||
-
|
||||
!record {model: stock.move, id: outgoing_shipment_fifo_icecream_ret}:
|
||||
picking_id: outgoing_fifo_shipment_ret
|
||||
product_id: product_fifo_icecream
|
||||
product_uom: product.product_uom_kgm
|
||||
product_uom_qty: 10.0
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
I assign this outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_ret}: |
|
||||
self.action_assign()
|
||||
-
|
||||
Process the delivery of the outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_ret}: |
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, self.id)]}).process()
|
||||
-
|
||||
Check rounded price is 150.0 / 1.2834
|
||||
-
|
||||
!python {model: product.product, id: product_fifo_icecream}: |
|
||||
assert self.qty_available == 0.0, 'Wrong quantity in stock after first reception'
|
||||
-
|
||||
Let us create some outs to get negative stock for a new product using the same config
|
||||
-
|
||||
!record {model: product.product, id: product_fifo_negative}:
|
||||
default_code: NEG
|
||||
name: FIFO Negative
|
||||
type: product
|
||||
categ_id: product.product_category_1
|
||||
list_price: 100.0
|
||||
standard_price: 70.0
|
||||
uom_id: product.product_uom_kgm
|
||||
uom_po_id: product.product_uom_kgm
|
||||
cost_method: fifo
|
||||
valuation: real_time
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description:
|
||||
-
|
||||
Create outpicking. We create delivery order of 100 kg.
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment_neg}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Picking needs movement from stock
|
||||
-
|
||||
!record {model: stock.move, id: outgoing_shipment_fifo_icecream_neg}:
|
||||
picking_id: outgoing_fifo_shipment_neg
|
||||
product_id: product_fifo_negative
|
||||
product_uom: product.product_uom_kgm
|
||||
product_uom_qty: 100.0
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Process the delivery of the first outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_neg}: |
|
||||
self.action_confirm()
|
||||
move = self.move_lines[0]
|
||||
move.quantity_done = 100
|
||||
self.action_done()
|
||||
assert move.product_id.qty_available == -100, 'Stock qty should be -100'
|
||||
-
|
||||
The behavior of fifo/lifo is not guaranteed if the quants are created at the same second, so I just wait one second
|
||||
-
|
||||
!python {model: stock.picking, id: False}: |
|
||||
import time
|
||||
time.sleep(1)
|
||||
-
|
||||
Let us create another out of 400 kg
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment_neg2}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Picking needs movement from stock
|
||||
-
|
||||
!record {model: stock.move, id: outgoing_shipment_fifo_icecream_neg2}:
|
||||
picking_id: outgoing_fifo_shipment_neg2
|
||||
product_id: product_fifo_negative
|
||||
product_uom: product.product_uom_kgm
|
||||
product_uom_qty: 400.0
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Process the delivery of the outgoing shipments
|
||||
-
|
||||
!python {model: stock.picking, id: outgoing_fifo_shipment_neg2}: |
|
||||
self.action_confirm()
|
||||
move = self.move_lines[0]
|
||||
move.quantity_done = 400
|
||||
self.action_done()
|
||||
assert move.product_id.qty_available == -500, 'Stock qty should be -500'
|
||||
-
|
||||
Receive purchase order with 50 kg FIFO Ice Cream at 50 euro/kg
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fifo_neg}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_fifo_negative
|
||||
product_qty: 50.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 50.0
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the first purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo_neg}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order 1
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo_neg}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Receive purchase order with 600 kg FIFO Ice Cream at 80 euro/kg
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fifo_neg2}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_fifo_negative
|
||||
product_qty: 600.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 80
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the second negative purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo_neg2}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order 2
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fifo_neg2}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
original_out_move = self.env['stock.picking'].browse(ref('outgoing_fifo_shipment_neg')).move_lines[0]
|
||||
outgoing_shipment_fifo_icecream_neg2 = self.env['stock.picking'].browse(ref('outgoing_fifo_shipment_neg2')).move_lines[0]
|
||||
original_out_move._fifo_vacuum()
|
||||
outgoing_shipment_fifo_icecream_neg2._fifo_vacuum()
|
||||
assert original_out_move.product_id.stock_value == 12000.0, 'Stock Value should be 12000'
|
||||
assert original_out_move.product_id.qty_available == 150.0, 'Qty available should be 150'
|
||||
@@ -1,86 +0,0 @@
|
||||
-
|
||||
Set a product as using fifo price
|
||||
-
|
||||
!record {model: product.product, id: product_fiforet_icecream}:
|
||||
default_code: FIFORET
|
||||
name: FIFO Ice Cream
|
||||
type: product
|
||||
standard_price: 0.0
|
||||
categ_id: product.product_category_1
|
||||
uom_id: product.product_uom_kgm
|
||||
uom_po_id: product.product_uom_kgm
|
||||
cost_method: fifo
|
||||
valuation: real_time
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description: FIFO Ice Cream can be mass-produced and thus is widely available in developed parts of the world. Ice cream can be purchased in large cartons (vats and squrounds) from supermarkets and grocery stores, in smaller quantities from ice cream shops, convenience stores, and milk bars, and in individual servings from small carts or vans at public events.
|
||||
-
|
||||
I create a draft Purchase Order for first in move for 10 kg at 50 euro
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fiforet1}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_fiforet_icecream
|
||||
product_qty: 10.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 50.0
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I create a draft Purchase Order for second shipment for 30 kg at 80 euro
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fiforet2}:
|
||||
partner_id: base.res_partner_3
|
||||
order_line:
|
||||
- product_id: product_fiforet_icecream
|
||||
product_qty: 30.0
|
||||
product_uom: product.product_uom_kgm
|
||||
price_unit: 80.0
|
||||
name: 'FIFO Ice Cream'
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I confirm the first purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fiforet1}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order 1
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fiforet1}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Check the standard price of the product (fifo icecream)
|
||||
-
|
||||
!python {model: product.product, id: product_fiforet_icecream}: |
|
||||
assert self.standard_price == 0.0, 'Standard price should not have changed!'
|
||||
-
|
||||
I confirm the second purchase order
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fiforet2}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
Process the reception of purchase order 2
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fiforet2}: |
|
||||
picking = self.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
-
|
||||
Return the goods of purchase order 2
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_fiforet2}: |
|
||||
picking = self.picking_ids[0]
|
||||
return_id = self.env['stock.return.picking'].with_context(active_model='stock.picking', active_id=picking.id).create({})
|
||||
return_picking_id, dummy = return_id.with_context(active_id=picking.id)._create_returns()
|
||||
# Important to pass through confirmation and assignation
|
||||
return_picking = self.env['stock.picking'].browse(return_picking_id)
|
||||
return_picking.action_confirm()
|
||||
return_picking.move_lines[0].quantity_done = return_picking.move_lines[0].product_uom_qty
|
||||
return_picking.action_done()
|
||||
-
|
||||
After the return only 10 of the second purchase order should still be in stock as it applies fifo on the return too
|
||||
-
|
||||
!python {model: product.product, id: product_fiforet_icecream}: |
|
||||
assert self.qty_available == 10.0, 'Qty available should be 10.0'
|
||||
assert self.stock_value == 800, 'Stock value should be 800'
|
||||
@@ -1,32 +0,0 @@
|
||||
-
|
||||
Purchase user can also cancel order therfore test with that user which have Purchase user rights.
|
||||
-
|
||||
!context
|
||||
uid: 'res_users_purchase_user'
|
||||
-
|
||||
In order to test the cancel flow, I start it from canceling confirmed purchase order.
|
||||
-
|
||||
I confirm the purchase order.
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_5}: |
|
||||
self.button_confirm()
|
||||
-
|
||||
I check the "Approved" status after confirmed RFQ.
|
||||
-
|
||||
!assert {model: purchase.order, id: purchase_order_5}:
|
||||
- state == 'purchase'
|
||||
-
|
||||
First I cancel receptions related to this order if order shipped.
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_5}: |
|
||||
self.env['stock.picking'].browse([picking.id for picking in self.picking_ids]).action_cancel()
|
||||
-
|
||||
Now I am able to cancel purchase order.
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_5}: |
|
||||
self.button_cancel()
|
||||
-
|
||||
I check that order is cancelled.
|
||||
-
|
||||
!assert {model: purchase.order, id: purchase_order_5}:
|
||||
- state == 'cancel'
|
||||
@@ -1,15 +0,0 @@
|
||||
-
|
||||
In order to test the scheduler to generate RFQ, I create a new product
|
||||
-
|
||||
!record {model: product.product, id: scheduler_product, view: False}:
|
||||
name: scheduler prod
|
||||
type: product
|
||||
seller_ids:
|
||||
- delay: 1
|
||||
name: base.res_partner_2
|
||||
min_qty: 5.0
|
||||
-
|
||||
Add Buy route
|
||||
-
|
||||
!python {model: product.product, id: scheduler_product}: |
|
||||
self.write({"route_ids": [(4, ref("purchase.route_warehouse0_buy"))]})
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record forcecreate="True" id="property_stock_valuation_account_id" model="ir.property">
|
||||
<field name="name">property_stock_valuation_account_id</field>
|
||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_valuation_account_id')]"/>
|
||||
<field eval="'account.account,'+str(ref('stk'))" model="account.account" name="value"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
</record>
|
||||
<record forcecreate="True" id="property_stock_journal" model="ir.property">
|
||||
<field name="name">property_stock_journal</field>
|
||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_journal'),('relation', '=', 'account.journal')]"/>
|
||||
<field eval="'account.journal,'+str(ref('miscellaneous_journal'))" model="account.journal" name="value"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,31 +0,0 @@
|
||||
-
|
||||
Give access rights of Purchase user to delete purchase order
|
||||
-
|
||||
!context
|
||||
uid: 'res_users_purchase_user'
|
||||
-
|
||||
In order to test to delete process on purchase order.
|
||||
-
|
||||
I try to delete confirmed order and check Error Message.
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_1}: |
|
||||
try:
|
||||
self.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
-
|
||||
I delete a cancelled order.
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_7}: |
|
||||
from odoo.exceptions import UserError
|
||||
try:
|
||||
self.unlink()
|
||||
except UserError:
|
||||
pass
|
||||
-
|
||||
I delete a draft order.
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_5}: |
|
||||
self.unlink()
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
-
|
||||
In order to test the duplicate order and check duplicate details.
|
||||
-
|
||||
I duplicate order.
|
||||
-
|
||||
!python {model: purchase.order, id: purchase_order_1}: |
|
||||
self.copy()
|
||||
@@ -1,28 +0,0 @@
|
||||
-
|
||||
Create a user as 'Purchase manager'
|
||||
-
|
||||
!record {model: res.users, id: res_users_purchase_manager, view: False}:
|
||||
company_id: base.main_company
|
||||
name: Purchase Manager
|
||||
login: pm
|
||||
email: purchasemanager@yourcompany.com
|
||||
-
|
||||
I added groups for Purchase manager.
|
||||
-
|
||||
!record {model: res.users, id: res_users_purchase_manager}:
|
||||
groups_id:
|
||||
- purchase.group_purchase_manager
|
||||
-
|
||||
Create a user as 'Purchase user'
|
||||
-
|
||||
!record {model: res.users, id: res_users_purchase_user, view: False}:
|
||||
company_id: base.main_company
|
||||
name: Purchase User
|
||||
login: pu
|
||||
email: purchaseuser@yourcompany.com
|
||||
-
|
||||
I added groups for Purchase user.
|
||||
-
|
||||
!record {model: res.users, id: res_users_purchase_user}:
|
||||
groups_id:
|
||||
- purchase.group_purchase_user
|
||||
@@ -1,8 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_onchange_product_id
|
||||
from . import test_purchase_order
|
||||
from . import test_average_price
|
||||
from . import test_create_picking
|
||||
from . import test_fifo_price
|
||||
from . import test_fifo_returns
|
||||
from . import test_onchange_product
|
||||
from . import test_purchase_delete_order
|
||||
from . import test_purchase_lead_time
|
||||
from . import test_purchase_order
|
||||
from . import test_purchase_order_process
|
||||
from . import test_stockvaluation
|
||||
|
||||
@@ -3,6 +3,8 @@ from datetime import timedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.addons.stock.tests.common2 import TestStockCommon
|
||||
from odoo import tools
|
||||
from odoo.modules.module import get_module_resource
|
||||
|
||||
|
||||
class TestPurchase(TestStockCommon):
|
||||
@@ -16,6 +18,11 @@ class TestPurchase(TestStockCommon):
|
||||
}
|
||||
return ProcurementGroup.run(product, product_qty, self.uom_unit, self.warehouse_1.lot_stock_id, product.name, '/', order_values)
|
||||
|
||||
def _load(self, module, *args):
|
||||
tools.convert_file(self.cr, 'purchase',
|
||||
get_module_resource(module, *args),
|
||||
{}, 'init', False, 'test', self.registry._assertion_report)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestPurchase, cls).setUpClass()
|
||||
@@ -34,3 +41,11 @@ class TestPurchase(TestStockCommon):
|
||||
'type': 'product',
|
||||
'route_ids': [(6, 0, [cls.route_buy, cls.route_mto])],
|
||||
'seller_ids': [(0, 0, {'name': cls.partner_1.id, 'delay': 2})]})
|
||||
|
||||
cls.res_users_purchase_user = cls.env['res.users'].create({
|
||||
'company_id': cls.env.ref('base.main_company').id,
|
||||
'name': "Purchase User",
|
||||
'login': "pu",
|
||||
'email': "purchaseuser@yourcompany.com",
|
||||
'groups_id': [(6, 0, [cls.env.ref('purchase.group_purchase_user').id])],
|
||||
})
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import time
|
||||
|
||||
from .common import TestPurchase
|
||||
|
||||
|
||||
class TestAveragePrice(TestPurchase):
|
||||
|
||||
def test_00_average_price(self):
|
||||
""" Testcase for average price computation"""
|
||||
|
||||
self._load('account', 'test', 'account_minimal_test.xml')
|
||||
self._load('stock_account', 'test', 'stock_valuation_account.xml')
|
||||
|
||||
# Set a product as using average price.
|
||||
product_icecream = self.env['product.product'].create({
|
||||
'default_code': 'AVG',
|
||||
'name': 'Average Ice Cream',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_1').id,
|
||||
'list_price': 100.0,
|
||||
'standard_price': 60.0,
|
||||
'uom_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'uom_po_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'cost_method': 'average',
|
||||
'valuation': 'real_time',
|
||||
'property_stock_account_input': self.ref('purchase.o_expense'),
|
||||
'property_stock_account_output': self.ref('purchase.o_income'),
|
||||
'supplier_taxes_id': [],
|
||||
'description': 'FIFO Ice Cream',
|
||||
})
|
||||
|
||||
# I create a draft Purchase Order for first incoming shipment for 10 pieces at 60€
|
||||
purchase_order_1 = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': 'Average Ice Cream',
|
||||
'product_id': product_icecream.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 60.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d'),
|
||||
})]
|
||||
})
|
||||
|
||||
# Confirm the first purchase order
|
||||
purchase_order_1.button_confirm()
|
||||
|
||||
# Check the "Approved" status of purchase order 1
|
||||
self.assertEqual(purchase_order_1.state, 'purchase', "Wrong state of purchase order!")
|
||||
|
||||
# Process the reception of purchase order 1
|
||||
picking = purchase_order_1.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Check the average_price of the product (average icecream).
|
||||
self.assertEqual(product_icecream.qty_available, 10.0, 'Wrong quantity in stock after first reception')
|
||||
self.assertEqual(product_icecream.standard_price, 60.0, 'Standard price should be the price of the first reception!')
|
||||
|
||||
# I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€
|
||||
purchase_order_2 = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_icecream.id,
|
||||
'product_qty': 30.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 80.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d'),
|
||||
})]
|
||||
})
|
||||
|
||||
# Confirm the second purchase order
|
||||
purchase_order_2.button_confirm()
|
||||
# Process the reception of purchase order 2
|
||||
picking = purchase_order_2.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Check the standard price
|
||||
self.assertEqual(product_icecream.standard_price, 75.0, 'After second reception, we should have an average price of 75.0 on the product')
|
||||
|
||||
# Create picking to send some goods
|
||||
outgoing_shipment = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'move_lines': [(0, 0, {
|
||||
'name': 'outgoing_shipment_avg_move',
|
||||
'product_id': product_icecream.id,
|
||||
'product_uom_qty': 20.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id})]
|
||||
})
|
||||
|
||||
# Assign this outgoing shipment and process the delivery
|
||||
outgoing_shipment.action_assign()
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, outgoing_shipment.id)]}).process()
|
||||
|
||||
# Check the average price (60 * 10 + 30 * 80) / 40 = 75.0€ did not change
|
||||
self.assertEqual(product_icecream.standard_price, 75.0, 'Average price should not have changed with outgoing picking!')
|
||||
self.assertEqual(product_icecream.qty_available, 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong')
|
||||
|
||||
# Make a new purchase order with 500 g Average Ice Cream at a price of 0.2€/g
|
||||
purchase_order_3 = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_icecream.id,
|
||||
'product_qty': 500.0,
|
||||
'product_uom': self.ref('product.product_uom_gram'),
|
||||
'price_unit': 0.2,
|
||||
'date_planned': time.strftime('%Y-%m-%d'),
|
||||
})]
|
||||
})
|
||||
|
||||
# Confirm the first purchase order
|
||||
purchase_order_3.button_confirm()
|
||||
# Process the reception of purchase order 3 in grams
|
||||
picking = purchase_order_3.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Check price is (75.0 * 20 + 200*0.5) / 20.5 = 78.04878€
|
||||
self.assertEqual(product_icecream.qty_available, 20.5, 'Reception of purchase order in grams leads to wrong quantity in stock')
|
||||
self.assertEqual(round(product_icecream.standard_price, 2), 78.05,
|
||||
'Standard price as average price of third reception with other UoM incorrect! Got %s instead of 78.05' % (round(product_icecream.standard_price, 2)))
|
||||
@@ -0,0 +1,323 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import time
|
||||
|
||||
from .common import TestPurchase
|
||||
|
||||
|
||||
class TestFifoPrice(TestPurchase):
|
||||
|
||||
def test_00_test_fifo(self):
|
||||
""" Test product cost price with fifo removal strategy."""
|
||||
|
||||
self._load('account', 'test', 'account_minimal_test.xml')
|
||||
self._load('stock_account', 'test', 'stock_valuation_account.xml')
|
||||
|
||||
# Set the company currency as EURO for the sake of repeatibility
|
||||
self.env.ref('base.main_company').currency_id = self.env.ref('base.EUR')
|
||||
|
||||
# Set a product as using fifo price
|
||||
product_icecream = self.env['product.product'].create({
|
||||
'default_code': 'FIFO',
|
||||
'name': 'FIFO Ice Cream',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_1').id,
|
||||
'list_price': 100.0,
|
||||
'standard_price': 70.0,
|
||||
'uom_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'uom_po_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'cost_method': 'fifo',
|
||||
'valuation': 'real_time',
|
||||
'property_stock_account_input': self.ref('purchase.o_expense'),
|
||||
'property_stock_account_output': self.ref('purchase.o_income'),
|
||||
'supplier_taxes_id': '[]',
|
||||
'description': 'FIFO Ice Cream',
|
||||
})
|
||||
|
||||
# I create a draft Purchase Order for first in move for 10 kg at 50 euro
|
||||
purchase_order_1 = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': 'FIFO Ice Cream',
|
||||
'product_id': product_icecream.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 50.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d')})],
|
||||
})
|
||||
|
||||
# Confirm the first purchase order
|
||||
purchase_order_1.button_confirm()
|
||||
|
||||
# Check the "Purchase" status of purchase order 1
|
||||
self.assertEquals(purchase_order_1.state, 'purchase')
|
||||
|
||||
# Process the reception of purchase order 1 and set date
|
||||
picking = purchase_order_1.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Check the standard price of the product (fifo icecream), that should have not changed
|
||||
# because the standard price is supposed to be updated only when goods are going out of the stock
|
||||
self.assertEquals(product_icecream.standard_price, 70.0, 'Standard price should not have changed')
|
||||
self.assertEquals(product_icecream.stock_value, 500.0, 'Wrong stock value')
|
||||
|
||||
# I create a draft Purchase Order for second shipment for 30 kg at 80 euro
|
||||
purchase_order_2 = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': 'FIFO Ice Cream',
|
||||
'product_id': product_icecream.id,
|
||||
'product_qty': 30.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 80.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d')})],
|
||||
})
|
||||
|
||||
# Confirm the second purchase order
|
||||
purchase_order_2.button_confirm()
|
||||
|
||||
# Process the reception of purchase order 2
|
||||
picking = purchase_order_2.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Check the standard price of the product, that should have not changed because the
|
||||
# standard price is supposed to be updated only when goods are going out of the stock
|
||||
self.assertEquals(product_icecream.standard_price, 70.0, 'Standard price as fifo price of second reception incorrect!')
|
||||
self.assertEquals(product_icecream.stock_value, 2900.0, 'Stock valuation should be 2900')
|
||||
|
||||
# Let us send some goods
|
||||
outgoing_shipment = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'move_lines': [(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_icecream.id,
|
||||
'product_uom_qty': 20.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id})]
|
||||
})
|
||||
|
||||
# I assign this outgoing shipment
|
||||
outgoing_shipment.action_assign()
|
||||
|
||||
# Process the delivery of the outgoing shipment
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, outgoing_shipment.id)]}).process()
|
||||
|
||||
# Check stock value became 1600 .
|
||||
self.assertEqual(product_icecream.stock_value, 1600.0, 'Stock valuation should be 1600')
|
||||
|
||||
# Do a delivery of an extra 500 g (delivery order)
|
||||
outgoing_shipment_uom = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'move_lines': [(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_icecream.id,
|
||||
'product_uom_qty': 500.0,
|
||||
'product_uom': self.env.ref('product.product_uom_gram').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id})]
|
||||
})
|
||||
|
||||
# I assign this outgoing shipment
|
||||
outgoing_shipment_uom.action_assign()
|
||||
|
||||
# Process the delivery of the outgoing shipment
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, outgoing_shipment_uom.id)]}).process()
|
||||
|
||||
# Check stock valuation and qty in stock
|
||||
self.assertEqual(product_icecream.stock_value, 1560.0, 'Stock valuation should be 1560')
|
||||
self.assertEqual(product_icecream.qty_available, 19.5, 'Should still have 19.5 in stock')
|
||||
|
||||
# We will temporarily change the currency rate on the sixth of June to have the same results all year
|
||||
NewUSD = self.env['res.currency'].create({
|
||||
'name': 'new_usd',
|
||||
'symbol': '$²',
|
||||
'rate_ids': [(0, 0, {'rate': 1.2834, 'name': time.strftime('%Y-%m-%d')})],
|
||||
})
|
||||
|
||||
# Create PO for 30000 g at 0.150$/g and 10 kg at 150$/kg
|
||||
purchase_order_usd = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'currency_id': NewUSD.id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': 'FIFO Ice Cream',
|
||||
'product_id': product_icecream.id,
|
||||
'product_qty': 30,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 0.150,
|
||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||
(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_icecream.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 150.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d')})]
|
||||
})
|
||||
|
||||
# Confirm the purchase order in USD
|
||||
purchase_order_usd.button_confirm()
|
||||
# Process the reception of purchase order with USD
|
||||
picking = purchase_order_usd.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Create delivery order of 49.5 kg
|
||||
outgoing_shipment_cur = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'move_lines': [(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_icecream.id,
|
||||
'product_uom_qty': 49.5,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id})]
|
||||
})
|
||||
|
||||
# I assign this outgoing shipment
|
||||
outgoing_shipment_cur.action_assign()
|
||||
|
||||
# Process the delivery of the outgoing shipment
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, outgoing_shipment_cur.id)]}).process()
|
||||
|
||||
# Do a delivery of an extra 10 kg
|
||||
outgoing_shipment_ret = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'move_lines': [(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_icecream.id,
|
||||
'product_uom_qty': 10,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id})]
|
||||
})
|
||||
|
||||
# I assign this outgoing shipment
|
||||
outgoing_shipment_ret.action_assign()
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, outgoing_shipment_ret.id)]}).process()
|
||||
|
||||
# Check rounded price is 150.0 / 1.2834
|
||||
self.assertEqual(round(product_icecream.qty_available), 0.0, 'Wrong quantity in stock after first reception.')
|
||||
|
||||
# Let us create some outs to get negative stock for a new product using the same config
|
||||
product_fifo_negative = self.env['product.product'].create({
|
||||
'default_code': 'NEG',
|
||||
'name': 'FIFO Negative',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_1').id,
|
||||
'list_price': 100.0,
|
||||
'standard_price': 70.0,
|
||||
'uom_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'uom_po_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'cost_method': 'fifo',
|
||||
'valuation': 'real_time',
|
||||
'property_stock_account_input': self.ref('purchase.o_expense'),
|
||||
'property_stock_account_output': self.ref('purchase.o_income'),
|
||||
'supplier_taxes_id': '[]',
|
||||
'description': 'FIFO Ice Cream',
|
||||
})
|
||||
|
||||
# Create outpicking.create delivery order of 100 kg.
|
||||
outgoing_shipment_neg = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'move_lines': [(0, 0, {
|
||||
'name': product_fifo_negative.name,
|
||||
'product_id': product_fifo_negative.id,
|
||||
'product_uom_qty': 100,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id})]
|
||||
})
|
||||
|
||||
# Process the delivery of the first outgoing shipment
|
||||
outgoing_shipment_neg.action_confirm()
|
||||
outgoing_shipment_neg.move_lines[0].quantity_done = 100.0
|
||||
outgoing_shipment_neg.action_done()
|
||||
|
||||
# Check qty available = -100
|
||||
self.assertEqual(product_fifo_negative.qty_available, -100, 'Stock qty should be -100')
|
||||
|
||||
# The behavior of fifo/lifo is not garantee if the quants are created at the same second, so just wait one second
|
||||
time.sleep(1)
|
||||
|
||||
# Let create another out shipment of 400 kg
|
||||
outgoing_shipment_neg2 = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'move_lines': [(0, 0, {
|
||||
'name': product_fifo_negative.name,
|
||||
'product_id': product_fifo_negative.id,
|
||||
'product_uom_qty': 400,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'location_id': self.env.ref('stock.stock_location_stock').id,
|
||||
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
|
||||
'picking_type_id': self.env.ref('stock.picking_type_out').id})]
|
||||
})
|
||||
|
||||
# Process the delivery of the outgoing shipments
|
||||
outgoing_shipment_neg2.action_confirm()
|
||||
outgoing_shipment_neg2.move_lines[0].quantity_done = 400.0
|
||||
outgoing_shipment_neg2.action_done()
|
||||
|
||||
# Check qty available = -500
|
||||
self.assertEqual(product_fifo_negative.qty_available, -500, 'Stock qty should be -500')
|
||||
|
||||
# Receive purchase order with 50 kg Ice Cream at 50€/kg
|
||||
purchase_order_neg = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': 'FIFO Ice Cream',
|
||||
'product_id': product_fifo_negative.id,
|
||||
'product_qty': 50.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 50.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d')})],
|
||||
})
|
||||
|
||||
# I confirm the first purchase order
|
||||
purchase_order_neg.button_confirm()
|
||||
|
||||
# Process the reception of purchase order neg
|
||||
picking = purchase_order_neg.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Receive purchase order with 600 kg FIFO Ice Cream at 80 euro/kg
|
||||
purchase_order_neg2 = self.env['purchase.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_3').id,
|
||||
'order_line': [(0, 0, {
|
||||
'name': product_icecream.name,
|
||||
'product_id': product_fifo_negative.id,
|
||||
'product_qty': 600.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 80.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d')})],
|
||||
})
|
||||
|
||||
# I confirm the second negative purchase order
|
||||
purchase_order_neg2.button_confirm()
|
||||
|
||||
# Process the reception of purchase order neg2
|
||||
picking = purchase_order_neg2.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
original_out_move = outgoing_shipment_neg.move_lines[0]
|
||||
outgoing_shipment_fifo_icecream_neg2 = outgoing_shipment_neg2.move_lines[0]
|
||||
original_out_move._fifo_vacuum()
|
||||
outgoing_shipment_fifo_icecream_neg2._fifo_vacuum()
|
||||
self.assertEquals(original_out_move.product_id.stock_value, 12000.0, 'Value of the move should be 2500')
|
||||
self.assertEquals(original_out_move.product_id.qty_available, 150.0, 'Qty available should be 150')
|
||||
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import time
|
||||
|
||||
from .common import TestPurchase
|
||||
|
||||
|
||||
class TestFifoReturns(TestPurchase):
|
||||
|
||||
def test_fifo_returns(self):
|
||||
"""Test to create product and purchase order to test the FIFO returns of the product"""
|
||||
|
||||
self._load('account', 'test', 'account_minimal_test.xml')
|
||||
self._load('stock_account', 'test', 'stock_valuation_account.xml')
|
||||
|
||||
# Set a product as using fifo price
|
||||
product_fiforet_icecream = self.env['product.product'].create({
|
||||
'default_code': 'FIFORET',
|
||||
'name': 'FIFO Ice Cream',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_1').id,
|
||||
'standard_price': 0.0,
|
||||
'uom_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'uom_po_id': self.env.ref('product.product_uom_kgm').id,
|
||||
'cost_method': 'fifo',
|
||||
'valuation': 'real_time',
|
||||
'property_stock_account_input': self.ref('purchase.o_expense'),
|
||||
'property_stock_account_output': self.ref('purchase.o_income'),
|
||||
'description': 'FIFO Ice Cream',
|
||||
})
|
||||
|
||||
# I create a draft Purchase Order for first in move for 10 kg at 50 euro
|
||||
purchase_order_1 = self.env['purchase.order'].create({
|
||||
'partner_id': self.ref('base.res_partner_3'),
|
||||
'order_line': [(0, 0, {
|
||||
'name': 'FIFO Ice Cream',
|
||||
'product_id': product_fiforet_icecream.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 50.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d'),
|
||||
})],
|
||||
})
|
||||
|
||||
# Create a draft Purchase Order for second shipment for 30kg at 80€/kg
|
||||
purchase_order_2 = self.env['purchase.order'].create({
|
||||
'partner_id': self.ref('base.res_partner_3'),
|
||||
'order_line': [(0, 0, {
|
||||
'name': 'FIFO Ice Cream',
|
||||
'product_id': product_fiforet_icecream.id,
|
||||
'product_qty': 30.0,
|
||||
'product_uom': self.env.ref('product.product_uom_kgm').id,
|
||||
'price_unit': 80.0,
|
||||
'date_planned': time.strftime('%Y-%m-%d'),
|
||||
})],
|
||||
})
|
||||
|
||||
# Confirm the first purchase order
|
||||
purchase_order_1.button_confirm()
|
||||
|
||||
# Process the reception of purchase order 1
|
||||
picking = purchase_order_1.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Check the standard price of the product (fifo icecream)
|
||||
self.assertEqual(product_fiforet_icecream.standard_price, 0.0, 'Standard price should not have changed!')
|
||||
|
||||
# Confirm the second purchase order
|
||||
purchase_order_2.button_confirm()
|
||||
picking = purchase_order_2.picking_ids[0]
|
||||
self.env['stock.immediate.transfer'].create({'pick_ids': [(4, picking.id)]}).process()
|
||||
|
||||
# Return the goods of purchase order 2
|
||||
picking = purchase_order_2.picking_ids[0]
|
||||
return_pick_wiz = self.env['stock.return.picking'].with_context(
|
||||
active_model='stock.picking', active_id=picking.id).create({})
|
||||
return_picking_id, dummy = return_pick_wiz.with_context(active_id=picking.id)._create_returns()
|
||||
|
||||
# Important to pass through confirmation and assignation
|
||||
return_picking = self.env['stock.picking'].browse(return_picking_id)
|
||||
return_picking.action_confirm()
|
||||
return_picking.move_lines[0].quantity_done = return_picking.move_lines[0].product_uom_qty
|
||||
return_picking.action_done()
|
||||
|
||||
# After the return only 10 of the second purchase order should still be in stock as it applies fifo on the return too
|
||||
self.assertEqual(product_fiforet_icecream.qty_available, 10.0, 'Qty available should be 10.0')
|
||||
self.assertEqual(product_fiforet_icecream.stock_value, 800.0, 'Stock value should be 800')
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
from .common import TestPurchase
|
||||
|
||||
|
||||
class TestDeleteOrder(TestPurchase):
|
||||
|
||||
def test_00_delete_order(self):
|
||||
''' Testcase for deleting purchase order with purchase user group'''
|
||||
|
||||
# In order to test delete process on purchase order,tried to delete a confirmed order and check Error Message.
|
||||
purchase_order_1 = self.env.ref('purchase.purchase_order_1').sudo(self.res_users_purchase_user.id)
|
||||
with self.assertRaises(UserError):
|
||||
purchase_order_1.unlink()
|
||||
|
||||
# Delete 'cancelled' purchase order with user group
|
||||
purchase_order_7 = self.env.ref('purchase.purchase_order_7').sudo(self.res_users_purchase_user.id)
|
||||
purchase_order_7.button_cancel()
|
||||
self.assertEqual(purchase_order_7.state, 'cancel', 'PO is cancelled!')
|
||||
purchase_order_7.unlink()
|
||||
|
||||
# Delete 'draft' purchase order with user group
|
||||
purchase_order_5 = self.env.ref('purchase.purchase_order_5').sudo(self.res_users_purchase_user.id)
|
||||
self.assertEqual(purchase_order_5.state, 'draft', 'PO in draft state!')
|
||||
purchase_order_5.button_cancel()
|
||||
self.assertEqual(purchase_order_5.state, 'cancel', 'PO is cancelled!')
|
||||
purchase_order_5.unlink()
|
||||
@@ -0,0 +1,25 @@
|
||||
from .common import TestPurchase
|
||||
|
||||
|
||||
class TestPurchaseOrderProcess(TestPurchase):
|
||||
|
||||
def test_00_cancel_purchase_order_flow(self):
|
||||
""" Test cancel purchase order with group user."""
|
||||
|
||||
# In order to test the cancel flow,start it from canceling confirmed purchase order.
|
||||
po_edit_with_user = self.env.ref('purchase.purchase_order_5').sudo(self.res_users_purchase_user.id)
|
||||
|
||||
# Confirm the purchase order.
|
||||
po_edit_with_user.button_confirm()
|
||||
|
||||
# Check the "Approved" status after confirmed RFQ.
|
||||
self.assertEqual(po_edit_with_user.state, 'purchase', 'Purchase: PO state should be "Purchase')
|
||||
|
||||
# First cancel receptions related to this order if order shipped.
|
||||
po_edit_with_user.picking_ids.action_cancel()
|
||||
|
||||
# Able to cancel purchase order.
|
||||
po_edit_with_user.button_cancel()
|
||||
|
||||
# Check that order is cancelled.
|
||||
self.assertEqual(po_edit_with_user.state, 'cancel', 'Purchase: PO state should be "Cancel')
|
||||
Reference in New Issue
Block a user