From b5cea7e2b6908c5c8ab051f296e5e4c85e64c9fe Mon Sep 17 00:00:00 2001
From: Hetashree Chauhan <hch@odoo.com>
Date: Tue, 30 Oct 2018 06:34:50 +0000
Subject: [PATCH] [IMP] purchase: purchase report improvement

Modify purchase report in order to make it consistent with
sales report.
For the RFQ it will show the Order Date and for the Purchase order
menu it will display the Confirmation Date.

Also rewrite a bit the SQL view in order to compute every purchase
order in the company currency.

Technicaly rewrite the SQL alias in order to have a report more
readable in the future.

Task ID : 1857130.

closes odoo/odoo#28248

Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
---
 addons/purchase/data/purchase_demo.xml        |  32 +++---
 addons/purchase/models/purchase.py            |   8 +-
 addons/purchase/report/purchase_report.py     | 106 +++++++++---------
 .../purchase/report/purchase_report_views.xml |  29 +++--
 addons/purchase/tests/__init__.py             |   4 +
 .../tests/test_purchase_order_report.py       |  79 +++++++++++++
 addons/purchase/views/purchase_views.xml      |   7 +-
 .../purchase_stock/report/purchase_report.py  |   2 +-
 8 files changed, 182 insertions(+), 85 deletions(-)
 create mode 100644 addons/purchase/tests/__init__.py
 create mode 100644 addons/purchase/tests/test_purchase_order_report.py

diff --git a/addons/purchase/data/purchase_demo.xml b/addons/purchase/data/purchase_demo.xml
index 43d840bbaeb5..2283fd287787 100644
--- a/addons/purchase/data/purchase_demo.xml
+++ b/addons/purchase/data/purchase_demo.xml
@@ -19,21 +19,21 @@
                 'price_unit': 79.80,
                 'product_qty': 15.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today() + relativedelta(days=3)}),
             (0, 0, {
                 'product_id': ref('product.product_product_25'),
                 'name': obj().env.ref('product.product_product_25').partner_ref,
                 'price_unit': 2868.70,
                 'product_qty': 5.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today() + relativedelta(days=3)}),
             (0, 0, {
                 'product_id': ref('product.product_product_27'),
                 'name': obj().env.ref('product.product_product_27').partner_ref,
                 'price_unit': 3297.20,
                 'product_qty': 4.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')})
+                'date_planned': DateTime.today() + relativedelta(days=3)})
         ]"/>
     </record>
 
@@ -48,14 +48,14 @@
                 'price_unit': 132.50,
                 'product_qty': 20.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today() + relativedelta(days=1)}),
             (0, 0, {
                 'product_id': ref('product.product_delivery_01'),
                 'name': obj().env.ref('product.product_delivery_01').partner_ref,
                 'price_unit': 89.0,
                 'product_qty': 5.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today() + relativedelta(days=1)}),
         ]"/>
     </record>
 
@@ -70,7 +70,7 @@
                 'price_unit': 25.50,
                 'product_qty': 10.0,
                 'product_uom': ref('uom.product_uom_hour'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today() + relativedelta(days=1)}),
         ]"/>
     </record>
 
@@ -85,21 +85,21 @@
                 'price_unit': 85.50,
                 'product_qty': 6.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today() + relativedelta(days=5)}),
             (0, 0, {
                 'product_id': ref('product.product_product_20'),
                 'name': obj().env.ref('product.product_product_20').partner_ref,
                 'price_unit': 1690.0,
                 'product_qty': 5.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today() + relativedelta(days=5)}),
             (0, 0, {
                 'product_id': ref('product.product_product_6'),
                 'name': obj().env.ref('product.product_product_6').partner_ref,
                 'price_unit': 800.0,
                 'product_qty': 7.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')})
+                'date_planned': DateTime.today() + relativedelta(days=5)})
         ]"/>
     </record>
 
@@ -114,14 +114,14 @@
                 'price_unit': 2010.0,
                 'product_qty': 3.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today()}),
             (0, 0, {
                 'product_id': ref('product.product_product_24'),
                 'name': obj().env.ref('product.product_product_24').partner_ref,
                 'price_unit': 876.0,
                 'product_qty': 3.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today()}),
         ]"/>
     </record>
 
@@ -136,21 +136,21 @@
                 'price_unit': 58.0,
                 'product_qty': 9.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today()}),
             (0, 0, {
                 'product_id': ref('product.product_delivery_01'),
                 'name': obj().env.ref('product.product_delivery_01').partner_ref,
                 'price_unit': 65.0,
                 'product_qty': 3.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today()}),
             (0, 0, {
                 'product_id': ref('product.consu_delivery_01'),
                 'name': obj().env.ref('product.consu_delivery_01').partner_ref,
                 'price_unit': 154.5,
                 'product_qty': 4.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today()}),
         ]"/>
     </record>
 
@@ -165,14 +165,14 @@
                 'price_unit': 13.5,
                 'product_qty': 5.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today()}),
             (0, 0, {
                 'product_id': ref('product.product_delivery_02'),
                 'name': obj().env.ref('product.product_delivery_02').partner_ref,
                 'price_unit': 38.0,
                 'product_qty': 15.0,
                 'product_uom': ref('uom.product_uom_unit'),
-                'date_planned': time.strftime('%Y-%m-%d')}),
+                'date_planned': DateTime.today()}),
         ]"/>
     </record>
 
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index fb68ccdec72d..a0d1386ffc55 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -85,7 +85,7 @@ class PurchaseOrder(models.Model):
              "delivery order sent by your vendor.")
     date_order = fields.Datetime('Order Date', required=True, states=READONLY_STATES, index=True, copy=False, default=fields.Datetime.now,\
         help="Depicts the date where the Quotation should be validated and converted into a purchase order.")
-    date_approve = fields.Date('Confirmation Date', readonly=1, index=True, copy=False)
+    date_approve = fields.Datetime('Confirmation Date', readonly=1, index=True, copy=False)
     partner_id = fields.Many2one('res.partner', string='Vendor', required=True, states=READONLY_STATES, change_default=True, tracking=True, help="You can find a vendor by its Name, TIN, Email or Internal Reference.")
     dest_address_id = fields.Many2one('res.partner', string='Drop Ship Address', states=READONLY_STATES,
         help="Put an address if you want to deliver directly from the vendor to the customer. "
@@ -125,6 +125,7 @@ class PurchaseOrder(models.Model):
     product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product', readonly=False)
     user_id = fields.Many2one('res.users', string='Purchase Representative', index=True, tracking=True, default=lambda self: self.env.user)
     company_id = fields.Many2one('res.company', 'Company', required=True, index=True, states=READONLY_STATES, default=lambda self: self.env.company.id)
+    currency_rate = fields.Float("Currency Rate", compute='_compute_currency_rate', compute_sudo=True, store=True, readonly=True, help='Ratio between the purchase order currency and the company currency')
 
     def _compute_access_url(self):
         super(PurchaseOrder, self)._compute_access_url()
@@ -140,6 +141,11 @@ class PurchaseOrder(models.Model):
         purchase_order_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
         return self.browse(purchase_order_ids).name_get()
 
+    @api.depends('date_order', 'currency_id', 'company_id', 'company_id.currency_id')
+    def _compute_currency_rate(self):
+        for order in self:
+            order.currency_rate = self.env['res.currency']._get_conversion_rate(order.company_id.currency_id, order.currency_id, order.company_id, order.date_order)
+
     @api.multi
     @api.depends('name', 'partner_ref')
     def name_get(self):
diff --git a/addons/purchase/report/purchase_report.py b/addons/purchase/report/purchase_report.py
index 28c25cecacac..d3a04e7d06ef 100644
--- a/addons/purchase/report/purchase_report.py
+++ b/addons/purchase/report/purchase_report.py
@@ -25,18 +25,15 @@ class PurchaseReport(models.Model):
     ], 'Order Status', readonly=True)
     product_id = fields.Many2one('product.product', 'Product', readonly=True)
     partner_id = fields.Many2one('res.partner', 'Vendor', readonly=True)
-    date_approve = fields.Date('Date Approved', readonly=True)
+    date_approve = fields.Datetime('Confirmation Date', readonly=True)
     product_uom = fields.Many2one('uom.uom', 'Reference Unit of Measure', required=True)
     company_id = fields.Many2one('res.company', 'Company', readonly=True)
     currency_id = fields.Many2one('res.currency', 'Currency', readonly=True)
     user_id = fields.Many2one('res.users', 'Purchase Representative', readonly=True)
-    delay = fields.Float('Days to Validate', digits=(16, 2), readonly=True)
-    delay_pass = fields.Float('Days to Deliver', digits=(16, 2), readonly=True)
-    unit_quantity = fields.Float('Product Quantity', readonly=True, oldname='quantity')
-    price_total = fields.Float('Total Price', readonly=True)
-    price_average = fields.Float('Average Price', readonly=True, group_operator="avg")
-    negociation = fields.Float('Purchase-Standard Price', readonly=True, group_operator="avg")
-    price_standard = fields.Float('Products Value', readonly=True, group_operator="sum")
+    delay = fields.Float('Days to Confirm', digits=(16, 2), readonly=True)
+    delay_pass = fields.Float('Days to Receive', digits=(16, 2), readonly=True)
+    price_total = fields.Float('Total', readonly=True)
+    price_average = fields.Float('Average Cost', readonly=True, group_operator="avg")
     nbr_lines = fields.Integer('# of Lines', readonly=True, oldname='nbr')
     category_id = fields.Many2one('product.category', 'Product Category', readonly=True)
     product_tmpl_id = fields.Many2one('product.template', 'Product Template', readonly=True)
@@ -46,6 +43,12 @@ class PurchaseReport(models.Model):
     commercial_partner_id = fields.Many2one('res.partner', 'Commercial Entity', readonly=True)
     weight = fields.Float('Gross Weight', readonly=True)
     volume = fields.Float('Volume', readonly=True)
+    order_id = fields.Many2one('purchase.order', 'Order', readonly=True)
+    untaxed_total = fields.Float('Untaxed Total', readonly=True)
+    qty_ordered = fields.Float('Qty Ordered', readonly=True)
+    qty_received = fields.Float('Qty Received', readonly=True)
+    qty_billed = fields.Float('Qty Billed', readonly=True)
+    qty_to_be_billed = fields.Float('Qty to be Billed', readonly=True)
 
     @api.model_cr
     def init(self):
@@ -61,80 +64,83 @@ class PurchaseReport(models.Model):
         select_str = """
             WITH currency_rate as (%s)
                 SELECT
+                    po.id as order_id,
                     min(l.id) as id,
-                    s.date_order as date_order,
-                    s.state,
-                    s.date_approve,
-                    s.dest_address_id,
-                    s.partner_id as partner_id,
-                    s.user_id as user_id,
-                    s.company_id as company_id,
-                    s.fiscal_position_id as fiscal_position_id,
+                    po.date_order as date_order,
+                    po.state,
+                    po.date_approve,
+                    po.dest_address_id,
+                    po.partner_id as partner_id,
+                    po.user_id as user_id,
+                    po.company_id as company_id,
+                    po.fiscal_position_id as fiscal_position_id,
                     l.product_id,
                     p.product_tmpl_id,
                     t.categ_id as category_id,
-                    s.currency_id,
+                    po.currency_id,
                     t.uom_id as product_uom,
-                    sum(l.product_qty/u.factor*u2.factor) as unit_quantity,
-                    extract(epoch from age(s.date_approve,s.date_order))/(24*60*60)::decimal(16,2) as delay,
-                    extract(epoch from age(l.date_planned,s.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
+                    extract(epoch from age(po.date_approve,po.date_order))/(24*60*60)::decimal(16,2) as delay,
+                    extract(epoch from age(l.date_planned,po.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
                     count(*) as nbr_lines,
-                    sum(l.price_unit / COALESCE(NULLIF(cr.rate, 0), 1.0) * l.product_qty)::decimal(16,2) as price_total,
-                    avg(100.0 * (l.price_unit / COALESCE(NULLIF(cr.rate, 0),1.0) * l.product_qty) / NULLIF(ip.value_float*l.product_qty/u.factor*u2.factor, 0.0))::decimal(16,2) as negociation,
-                    sum(ip.value_float*l.product_qty/u.factor*u2.factor)::decimal(16,2) as price_standard,
-                    (sum(l.product_qty * l.price_unit / COALESCE(NULLIF(cr.rate, 0), 1.0))/NULLIF(sum(l.product_qty/u.factor*u2.factor),0.0))::decimal(16,2) as price_average,
+                    sum(l.price_total / COALESCE(po.currency_rate, 1.0))::decimal(16,2) as price_total,
+                    (sum(l.product_qty * l.price_unit / COALESCE(po.currency_rate, 1.0))/NULLIF(sum(l.product_qty/line_uom.factor*product_uom.factor),0.0))::decimal(16,2) as price_average,
                     partner.country_id as country_id,
                     partner.commercial_partner_id as commercial_partner_id,
                     analytic_account.id as account_analytic_id,
-                    sum(p.weight * l.product_qty/u.factor*u2.factor) as weight,
-                    sum(p.volume * l.product_qty/u.factor*u2.factor) as volume
+                    sum(p.weight * l.product_qty/line_uom.factor*product_uom.factor) as weight,
+                    sum(p.volume * l.product_qty/line_uom.factor*product_uom.factor) as volume,
+                    sum(l.price_subtotal / COALESCE(po.currency_rate, 1.0))::decimal(16,2) as untaxed_total,
+                    sum(l.product_qty / line_uom.factor * product_uom.factor) as qty_ordered,
+                    sum(l.qty_received / line_uom.factor * product_uom.factor) as qty_received,
+                    sum(l.qty_invoiced / line_uom.factor * product_uom.factor) as qty_billed,
+                    sum(l.product_qty / line_uom.factor * product_uom.factor) - sum(l.qty_received / line_uom.factor * product_uom.factor) as qty_to_be_billed
         """ % self.env['res.currency']._select_companies_rates()
         return select_str
 
     def _from(self):
         from_str = """
             purchase_order_line l
-                join purchase_order s on (l.order_id=s.id)
-                join res_partner partner on s.partner_id = partner.id
+                join purchase_order po on (l.order_id=po.id)
+                join res_partner partner on po.partner_id = partner.id
                     left join product_product p on (l.product_id=p.id)
                         left join product_template t on (p.product_tmpl_id=t.id)
-                        LEFT JOIN ir_property ip ON (ip.name='standard_price' AND ip.res_id=CONCAT('product.product,',p.id) AND ip.company_id=s.company_id)
-                left join uom_uom u on (u.id=l.product_uom)
-                left join uom_uom u2 on (u2.id=t.uom_id)
+                left join uom_uom line_uom on (line_uom.id=l.product_uom)
+                left join uom_uom product_uom on (product_uom.id=t.uom_id)
                 left join account_analytic_account analytic_account on (l.account_analytic_id = analytic_account.id)
-                left join currency_rate cr on (cr.currency_id = s.currency_id and
-                    cr.company_id = s.company_id and
-                    cr.date_start <= coalesce(s.date_order, now()) and
-                    (cr.date_end is null or cr.date_end > coalesce(s.date_order, now())))
+                left join currency_rate cr on (cr.currency_id = po.currency_id and
+                    cr.company_id = po.company_id and
+                    cr.date_start <= coalesce(po.date_order, now()) and
+                    (cr.date_end is null or cr.date_end > coalesce(po.date_order, now())))
         """
         return from_str
 
     def _group_by(self):
         group_by_str = """
             GROUP BY
-                s.company_id,
-                s.user_id,
-                s.partner_id,
-                u.factor,
-                s.currency_id,
+                po.company_id,
+                po.user_id,
+                po.partner_id,
+                line_uom.factor,
+                po.currency_id,
                 l.price_unit,
-                s.date_approve,
+                po.date_approve,
                 l.date_planned,
                 l.product_uom,
-                s.dest_address_id,
-                s.fiscal_position_id,
+                po.dest_address_id,
+                po.fiscal_position_id,
                 l.product_id,
                 p.product_tmpl_id,
                 t.categ_id,
-                s.date_order,
-                s.state,
-                u.uom_type,
-                u.category_id,
+                po.date_order,
+                po.state,
+                line_uom.uom_type,
+                line_uom.category_id,
                 t.uom_id,
-                u.id,
-                u2.factor,
+                line_uom.id,
+                product_uom.factor,
                 partner.country_id,
                 partner.commercial_partner_id,
-                analytic_account.id
+                analytic_account.id,
+                po.id
         """
         return group_by_str
diff --git a/addons/purchase/report/purchase_report_views.xml b/addons/purchase/report/purchase_report_views.xml
index f4cc05af27fe..bc15d2c589c2 100644
--- a/addons/purchase/report/purchase_report_views.xml
+++ b/addons/purchase/report/purchase_report_views.xml
@@ -4,12 +4,11 @@
             <field name="name">product.month.pivot</field>
             <field name="model">purchase.report</field>
             <field name="arch" type="xml">
-                <pivot string="Purchase Orders Statistics" disable_linking="True">
-                    <field name="partner_id" type="row"/>
-                    <field name="date_order" interval="month" type="col"/>
+                <pivot string="Purchase Analysis" disable_linking="True" display_quantity="true">
+                    <field name="category_id" type="row"/>
+                    <field name="order_id" type="measure"/>
+                    <field name="untaxed_total" type="measure"/>
                     <field name="price_total" type="measure"/>
-                    <field name="unit_quantity" type="measure"/>
-                    <field name="price_average" type="measure"/>
                 </pivot>
             </field>
         </record>
@@ -17,10 +16,9 @@
             <field name="name">product.month.graph</field>
             <field name="model">purchase.report</field>
             <field name="arch" type="xml">
-                <graph string="Purchase Orders Statistics">
-                    <field name="partner_id" type="row"/>
-                    <field name="date_order" interval="month" type="col"/>
-                    <field name="price_average" type="measure"/>
+                <graph string="Purchase Orders Statistics" type="line">
+                    <field name="date_approve" interval="day" type="col"/>
+                    <field name="untaxed_total" type="measure"/>
                 </graph>
             </field>
         </record>
@@ -31,7 +29,6 @@
             <field name="model_id">purchase.report</field>
             <field name="domain">[('state','!=','cancel')]</field>
             <field name="user_id" eval="False"/>
-            <field name="context">{'group_by': ['category_id'], 'col_group_by': ['date_order:month'], 'measures': ['unit_quantity']}</field>
         </record>
         <record id="filter_purchase_order_price_per_supplier" model="ir.filters">
             <field name="name">Price Per Vendor</field>
@@ -54,8 +51,8 @@
         <field name="model">purchase.report</field>
         <field name="arch" type="xml">
             <search string="Purchase Orders">
-                <filter string="Quotations" name="quotes" domain="[('state','=','draft')]"/>
-                <filter string="Orders" name="orders" domain="[('state','!=','draft'),('state','!=','cancel')]"/>
+                <filter string="Requests for Quotation" name="quotes" domain="[('state','=','draft')]"/>
+                <filter string="Purchase Orders" name="orders" domain="[('state','!=','draft'),('state','!=','cancel')]"/>
                 <field name="partner_id"/>
                 <field name="product_id"/>
                 <group expand="0" string="Extended Filters">
@@ -69,12 +66,13 @@
                     <filter string="Vendor" name="group_partner_id" context="{'group_by':'partner_id'}"/>
                     <filter string="Vendor Country" name="country_id" context="{'group_by':'country_id'}"/>
                     <filter string="Purchase Representative" name="user_id" context="{'group_by':'user_id'}"/>
+                    <filter string="Product" name="group_product_id" context="{'group_by':'product_id'}"/>
                     <filter string="Product Category" name="group_category_id" context="{'group_by':'category_id'}"/>
-                    <filter string="Fiscal Position" name="fiscal_position" context="{'group_by':'fiscal_position_id'}" help="Purchase Order Fiscal Position"/>
                     <filter string="Status" name="status" context="{'group_by':'state'}"/>
                     <filter string="Company" name="company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
                     <separator/>
                     <filter string="Order Date" name="order_month" context="{'group_by': 'date_order:month'}"/>
+                    <filter string="Confirmation Date" name="group_date_approve_month" context="{'group_by': 'date_approve:month'}"/>
                 </group>
             </search>
         </field>
@@ -90,7 +88,8 @@
         <field name="target">current</field>
     </record>
 
-    <menuitem id="purchase_report" name="Reporting" parent="purchase.menu_purchase_root" sequence="99"
-        groups="purchase.group_purchase_manager" action="action_purchase_order_report_all"/>
+    <menuitem id="purchase_report" name="Reporting" parent="purchase.menu_purchase_root" sequence="99"/>
+
+    <menuitem id="menu_report_purchase" name="Purchase"  action="action_purchase_order_report_all" parent="purchase_report" sequence="1" groups="purchase.group_purchase_manager"/>
 
 </odoo>
diff --git a/addons/purchase/tests/__init__.py b/addons/purchase/tests/__init__.py
new file mode 100644
index 000000000000..d8e61f341b9b
--- /dev/null
+++ b/addons/purchase/tests/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import test_purchase_order_report
diff --git a/addons/purchase/tests/test_purchase_order_report.py b/addons/purchase/tests/test_purchase_order_report.py
new file mode 100644
index 000000000000..24750e71d604
--- /dev/null
+++ b/addons/purchase/tests/test_purchase_order_report.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from datetime import datetime
+from odoo.tests import common, Form, tagged
+
+
+@tagged('post_install', '-at_install')
+class TestPurchaseOrderReport(common.TransactionCase):
+    def setUp(self):
+        super(TestPurchaseOrderReport, self).setUp()
+
+        self.partner_id = self.env.ref('base.res_partner_1')
+        self.product1 = self.env.ref('product.product_product_8')
+        self.product2 = self.env.ref('product.product_product_11')
+        self.PurchaseReport = self.env['purchase.report']
+
+        # Create a new company and set CoA
+        self.company_id = self.env['res.company'].create({'name': 'new_company'})
+        self.env.user.company_id = self.company_id
+        self.env.ref('l10n_generic_coa.configurable_chart_template').load_for_current_company(False, False)
+
+    def test_00_purchase_order_report(self):
+        uom_dozen = self.env.ref('uom.product_uom_dozen')
+
+        eur_currency = self.env.ref('base.EUR')
+        self.company_id.currency_id = self.env.ref('base.USD').id
+
+        self.env['res.currency.rate'].search([]).unlink()
+        self.env['res.currency.rate'].create({
+            'name': datetime.today(),
+            'rate': 2.0,
+            'currency_id': eur_currency.id,
+        })
+        po = self.env['purchase.order'].create({
+            'partner_id': self.partner_id.id,
+            'currency_id': eur_currency.id,
+            'order_line': [
+                (0, 0, {
+                    'name': self.product1.name,
+                    'product_id': self.product1.id,
+                    'product_qty': 1.0,
+                    'product_uom': uom_dozen.id,
+                    'price_unit': 100.0,
+                    'date_planned': datetime.today(),
+                }),
+                (0, 0, {
+                    'name': self.product2.name,
+                    'product_id': self.product2.id,
+                    'product_qty': 1.0,
+                    'product_uom': uom_dozen.id,
+                    'price_unit': 200.0,
+                    'date_planned': datetime.today(),
+                }),
+            ],
+        })
+        po.button_confirm()
+
+        f = Form(self.env['account.invoice'])
+        f.partner_id = po.partner_id
+        f.purchase_id = po
+        invoice = f.save()
+        invoice.action_invoice_open()
+
+        res_product1 = self.PurchaseReport.search([
+            ('order_id', '=', po.id), ('product_id', '=', self.product1.id)])
+
+        # check that report will convert dozen to unit or not
+        self.assertEquals(res_product1.qty_ordered, 12.0, 'UoM conversion is not working')
+        # report should show in company currency (amount/rate) = (100/2)
+        self.assertEquals(res_product1.price_total, 50.0, 'Currency conversion is not working')
+
+        res_product2 = self.PurchaseReport.search([
+            ('order_id', '=', po.id), ('product_id', '=', self.product2.id)])
+
+        # Check that repost should show 6 unit of product
+        self.assertEquals(res_product2.qty_ordered, 12.0, 'UoM conversion is not working')
+        # report should show in company currency (amount/rate) = (200/2)
+        self.assertEquals(res_product2.price_total, 100.0, 'Currency conversion is not working')
diff --git a/addons/purchase/views/purchase_views.xml b/addons/purchase/views/purchase_views.xml
index ea23fb1ea0a4..edaa5693f3f1 100644
--- a/addons/purchase/views/purchase_views.xml
+++ b/addons/purchase/views/purchase_views.xml
@@ -175,7 +175,8 @@
                             <field name="currency_id" groups="base.group_multi_currency"/>
                         </group>
                         <group>
-                            <field name="date_order"/>
+                            <field name="date_order" attrs="{'invisible': [('state','=','purchase')]}"/>
+                            <field name="date_approve" attrs="{'invisible': [('state','!=','purchase')]}"/>
                             <field name="origin" attrs="{'invisible': [('origin','=',False)]}"/>
                             <field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
                         </group>
@@ -374,7 +375,8 @@
                 <tree decoration-bf="message_unread==True" decoration-muted="state=='cancel'" decoration-info="state in ('wait','confirmed')" string="Purchase Order">
                     <field name="message_unread" invisible="1"/>
                     <field name="name" string="Reference"/>
-                    <field name="date_order" />
+                    <field name="date_order" invisible="not context.get('quotation_only', False)"/>
+                    <field name="date_approve" invisible="context.get('quotation_only', False)"/>
                     <field name="partner_id"/>
                     <field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
                     <field name="date_planned" invisible="context.get('quotation_only', False)"/>
@@ -420,6 +422,7 @@
             <field name="res_model">purchase.order</field>
             <field name="view_mode">tree,kanban,form,pivot,graph,calendar,activity</field>
             <field name="search_view_id" ref="view_purchase_order_filter"/>
+            <field name="context">{'quotation_only': True}</field>
             <field name="help" type="html">
               <p class="o_view_nocontent_smiling_face">
                 Create a request for quotation
diff --git a/addons/purchase_stock/report/purchase_report.py b/addons/purchase_stock/report/purchase_report.py
index defb1a6c1671..46254cadca97 100644
--- a/addons/purchase_stock/report/purchase_report.py
+++ b/addons/purchase_stock/report/purchase_report.py
@@ -13,7 +13,7 @@ class PurchaseReport(models.Model):
         return super(PurchaseReport, self)._select() + ", spt.warehouse_id as picking_type_id"
 
     def _from(self):
-        return super(PurchaseReport, self)._from() + " left join stock_picking_type spt on (spt.id=s.picking_type_id)"
+        return super(PurchaseReport, self)._from() + " left join stock_picking_type spt on (spt.id=po.picking_type_id)"
 
     def _group_by(self):
         return super(PurchaseReport, self)._group_by() + ", spt.warehouse_id"
-- 
GitLab