[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>
This commit is contained in:
committed by
Arnold Moyaux
parent
2d4b026625
commit
b5cea7e2b6
@@ -19,21 +19,21 @@
|
|||||||
'price_unit': 79.80,
|
'price_unit': 79.80,
|
||||||
'product_qty': 15.0,
|
'product_qty': 15.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today() + relativedelta(days=3)}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_product_25'),
|
'product_id': ref('product.product_product_25'),
|
||||||
'name': obj().env.ref('product.product_product_25').partner_ref,
|
'name': obj().env.ref('product.product_product_25').partner_ref,
|
||||||
'price_unit': 2868.70,
|
'price_unit': 2868.70,
|
||||||
'product_qty': 5.0,
|
'product_qty': 5.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today() + relativedelta(days=3)}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_product_27'),
|
'product_id': ref('product.product_product_27'),
|
||||||
'name': obj().env.ref('product.product_product_27').partner_ref,
|
'name': obj().env.ref('product.product_product_27').partner_ref,
|
||||||
'price_unit': 3297.20,
|
'price_unit': 3297.20,
|
||||||
'product_qty': 4.0,
|
'product_qty': 4.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')})
|
'date_planned': DateTime.today() + relativedelta(days=3)})
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -48,14 +48,14 @@
|
|||||||
'price_unit': 132.50,
|
'price_unit': 132.50,
|
||||||
'product_qty': 20.0,
|
'product_qty': 20.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today() + relativedelta(days=1)}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_delivery_01'),
|
'product_id': ref('product.product_delivery_01'),
|
||||||
'name': obj().env.ref('product.product_delivery_01').partner_ref,
|
'name': obj().env.ref('product.product_delivery_01').partner_ref,
|
||||||
'price_unit': 89.0,
|
'price_unit': 89.0,
|
||||||
'product_qty': 5.0,
|
'product_qty': 5.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today() + relativedelta(days=1)}),
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
'price_unit': 25.50,
|
'price_unit': 25.50,
|
||||||
'product_qty': 10.0,
|
'product_qty': 10.0,
|
||||||
'product_uom': ref('uom.product_uom_hour'),
|
'product_uom': ref('uom.product_uom_hour'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today() + relativedelta(days=1)}),
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -85,21 +85,21 @@
|
|||||||
'price_unit': 85.50,
|
'price_unit': 85.50,
|
||||||
'product_qty': 6.0,
|
'product_qty': 6.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today() + relativedelta(days=5)}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_product_20'),
|
'product_id': ref('product.product_product_20'),
|
||||||
'name': obj().env.ref('product.product_product_20').partner_ref,
|
'name': obj().env.ref('product.product_product_20').partner_ref,
|
||||||
'price_unit': 1690.0,
|
'price_unit': 1690.0,
|
||||||
'product_qty': 5.0,
|
'product_qty': 5.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today() + relativedelta(days=5)}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_product_6'),
|
'product_id': ref('product.product_product_6'),
|
||||||
'name': obj().env.ref('product.product_product_6').partner_ref,
|
'name': obj().env.ref('product.product_product_6').partner_ref,
|
||||||
'price_unit': 800.0,
|
'price_unit': 800.0,
|
||||||
'product_qty': 7.0,
|
'product_qty': 7.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')})
|
'date_planned': DateTime.today() + relativedelta(days=5)})
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -114,14 +114,14 @@
|
|||||||
'price_unit': 2010.0,
|
'price_unit': 2010.0,
|
||||||
'product_qty': 3.0,
|
'product_qty': 3.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today()}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_product_24'),
|
'product_id': ref('product.product_product_24'),
|
||||||
'name': obj().env.ref('product.product_product_24').partner_ref,
|
'name': obj().env.ref('product.product_product_24').partner_ref,
|
||||||
'price_unit': 876.0,
|
'price_unit': 876.0,
|
||||||
'product_qty': 3.0,
|
'product_qty': 3.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today()}),
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -136,21 +136,21 @@
|
|||||||
'price_unit': 58.0,
|
'price_unit': 58.0,
|
||||||
'product_qty': 9.0,
|
'product_qty': 9.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today()}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_delivery_01'),
|
'product_id': ref('product.product_delivery_01'),
|
||||||
'name': obj().env.ref('product.product_delivery_01').partner_ref,
|
'name': obj().env.ref('product.product_delivery_01').partner_ref,
|
||||||
'price_unit': 65.0,
|
'price_unit': 65.0,
|
||||||
'product_qty': 3.0,
|
'product_qty': 3.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today()}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.consu_delivery_01'),
|
'product_id': ref('product.consu_delivery_01'),
|
||||||
'name': obj().env.ref('product.consu_delivery_01').partner_ref,
|
'name': obj().env.ref('product.consu_delivery_01').partner_ref,
|
||||||
'price_unit': 154.5,
|
'price_unit': 154.5,
|
||||||
'product_qty': 4.0,
|
'product_qty': 4.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today()}),
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -165,14 +165,14 @@
|
|||||||
'price_unit': 13.5,
|
'price_unit': 13.5,
|
||||||
'product_qty': 5.0,
|
'product_qty': 5.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today()}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'product_id': ref('product.product_delivery_02'),
|
'product_id': ref('product.product_delivery_02'),
|
||||||
'name': obj().env.ref('product.product_delivery_02').partner_ref,
|
'name': obj().env.ref('product.product_delivery_02').partner_ref,
|
||||||
'price_unit': 38.0,
|
'price_unit': 38.0,
|
||||||
'product_qty': 15.0,
|
'product_qty': 15.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_unit'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': DateTime.today()}),
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class PurchaseOrder(models.Model):
|
|||||||
"delivery order sent by your vendor.")
|
"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,\
|
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.")
|
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.")
|
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,
|
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. "
|
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)
|
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)
|
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)
|
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):
|
def _compute_access_url(self):
|
||||||
super(PurchaseOrder, self)._compute_access_url()
|
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)
|
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()
|
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.multi
|
||||||
@api.depends('name', 'partner_ref')
|
@api.depends('name', 'partner_ref')
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
|
|||||||
@@ -25,18 +25,15 @@ class PurchaseReport(models.Model):
|
|||||||
], 'Order Status', readonly=True)
|
], 'Order Status', readonly=True)
|
||||||
product_id = fields.Many2one('product.product', 'Product', readonly=True)
|
product_id = fields.Many2one('product.product', 'Product', readonly=True)
|
||||||
partner_id = fields.Many2one('res.partner', 'Vendor', 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)
|
product_uom = fields.Many2one('uom.uom', 'Reference Unit of Measure', required=True)
|
||||||
company_id = fields.Many2one('res.company', 'Company', readonly=True)
|
company_id = fields.Many2one('res.company', 'Company', readonly=True)
|
||||||
currency_id = fields.Many2one('res.currency', 'Currency', readonly=True)
|
currency_id = fields.Many2one('res.currency', 'Currency', readonly=True)
|
||||||
user_id = fields.Many2one('res.users', 'Purchase Representative', readonly=True)
|
user_id = fields.Many2one('res.users', 'Purchase Representative', readonly=True)
|
||||||
delay = fields.Float('Days to Validate', digits=(16, 2), readonly=True)
|
delay = fields.Float('Days to Confirm', digits=(16, 2), readonly=True)
|
||||||
delay_pass = fields.Float('Days to Deliver', digits=(16, 2), readonly=True)
|
delay_pass = fields.Float('Days to Receive', digits=(16, 2), readonly=True)
|
||||||
unit_quantity = fields.Float('Product Quantity', readonly=True, oldname='quantity')
|
price_total = fields.Float('Total', readonly=True)
|
||||||
price_total = fields.Float('Total Price', readonly=True)
|
price_average = fields.Float('Average Cost', readonly=True, group_operator="avg")
|
||||||
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")
|
|
||||||
nbr_lines = fields.Integer('# of Lines', readonly=True, oldname='nbr')
|
nbr_lines = fields.Integer('# of Lines', readonly=True, oldname='nbr')
|
||||||
category_id = fields.Many2one('product.category', 'Product Category', readonly=True)
|
category_id = fields.Many2one('product.category', 'Product Category', readonly=True)
|
||||||
product_tmpl_id = fields.Many2one('product.template', 'Product Template', 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)
|
commercial_partner_id = fields.Many2one('res.partner', 'Commercial Entity', readonly=True)
|
||||||
weight = fields.Float('Gross Weight', readonly=True)
|
weight = fields.Float('Gross Weight', readonly=True)
|
||||||
volume = fields.Float('Volume', 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
|
@api.model_cr
|
||||||
def init(self):
|
def init(self):
|
||||||
@@ -61,80 +64,83 @@ class PurchaseReport(models.Model):
|
|||||||
select_str = """
|
select_str = """
|
||||||
WITH currency_rate as (%s)
|
WITH currency_rate as (%s)
|
||||||
SELECT
|
SELECT
|
||||||
|
po.id as order_id,
|
||||||
min(l.id) as id,
|
min(l.id) as id,
|
||||||
s.date_order as date_order,
|
po.date_order as date_order,
|
||||||
s.state,
|
po.state,
|
||||||
s.date_approve,
|
po.date_approve,
|
||||||
s.dest_address_id,
|
po.dest_address_id,
|
||||||
s.partner_id as partner_id,
|
po.partner_id as partner_id,
|
||||||
s.user_id as user_id,
|
po.user_id as user_id,
|
||||||
s.company_id as company_id,
|
po.company_id as company_id,
|
||||||
s.fiscal_position_id as fiscal_position_id,
|
po.fiscal_position_id as fiscal_position_id,
|
||||||
l.product_id,
|
l.product_id,
|
||||||
p.product_tmpl_id,
|
p.product_tmpl_id,
|
||||||
t.categ_id as category_id,
|
t.categ_id as category_id,
|
||||||
s.currency_id,
|
po.currency_id,
|
||||||
t.uom_id as product_uom,
|
t.uom_id as product_uom,
|
||||||
sum(l.product_qty/u.factor*u2.factor) as unit_quantity,
|
extract(epoch from age(po.date_approve,po.date_order))/(24*60*60)::decimal(16,2) as delay,
|
||||||
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,po.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
|
||||||
extract(epoch from age(l.date_planned,s.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
|
|
||||||
count(*) as nbr_lines,
|
count(*) as nbr_lines,
|
||||||
sum(l.price_unit / COALESCE(NULLIF(cr.rate, 0), 1.0) * l.product_qty)::decimal(16,2) as price_total,
|
sum(l.price_total / COALESCE(po.currency_rate, 1.0))::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(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,
|
||||||
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,
|
|
||||||
partner.country_id as country_id,
|
partner.country_id as country_id,
|
||||||
partner.commercial_partner_id as commercial_partner_id,
|
partner.commercial_partner_id as commercial_partner_id,
|
||||||
analytic_account.id as account_analytic_id,
|
analytic_account.id as account_analytic_id,
|
||||||
sum(p.weight * l.product_qty/u.factor*u2.factor) as weight,
|
sum(p.weight * l.product_qty/line_uom.factor*product_uom.factor) as weight,
|
||||||
sum(p.volume * l.product_qty/u.factor*u2.factor) as volume
|
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()
|
""" % self.env['res.currency']._select_companies_rates()
|
||||||
return select_str
|
return select_str
|
||||||
|
|
||||||
def _from(self):
|
def _from(self):
|
||||||
from_str = """
|
from_str = """
|
||||||
purchase_order_line l
|
purchase_order_line l
|
||||||
join purchase_order s on (l.order_id=s.id)
|
join purchase_order po on (l.order_id=po.id)
|
||||||
join res_partner partner on s.partner_id = partner.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_product p on (l.product_id=p.id)
|
||||||
left join product_template t on (p.product_tmpl_id=t.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 line_uom on (line_uom.id=l.product_uom)
|
||||||
left join uom_uom u on (u.id=l.product_uom)
|
left join uom_uom product_uom on (product_uom.id=t.uom_id)
|
||||||
left join uom_uom u2 on (u2.id=t.uom_id)
|
|
||||||
left join account_analytic_account analytic_account on (l.account_analytic_id = analytic_account.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
|
left join currency_rate cr on (cr.currency_id = po.currency_id and
|
||||||
cr.company_id = s.company_id and
|
cr.company_id = po.company_id and
|
||||||
cr.date_start <= coalesce(s.date_order, now()) and
|
cr.date_start <= coalesce(po.date_order, now()) and
|
||||||
(cr.date_end is null or cr.date_end > coalesce(s.date_order, now())))
|
(cr.date_end is null or cr.date_end > coalesce(po.date_order, now())))
|
||||||
"""
|
"""
|
||||||
return from_str
|
return from_str
|
||||||
|
|
||||||
def _group_by(self):
|
def _group_by(self):
|
||||||
group_by_str = """
|
group_by_str = """
|
||||||
GROUP BY
|
GROUP BY
|
||||||
s.company_id,
|
po.company_id,
|
||||||
s.user_id,
|
po.user_id,
|
||||||
s.partner_id,
|
po.partner_id,
|
||||||
u.factor,
|
line_uom.factor,
|
||||||
s.currency_id,
|
po.currency_id,
|
||||||
l.price_unit,
|
l.price_unit,
|
||||||
s.date_approve,
|
po.date_approve,
|
||||||
l.date_planned,
|
l.date_planned,
|
||||||
l.product_uom,
|
l.product_uom,
|
||||||
s.dest_address_id,
|
po.dest_address_id,
|
||||||
s.fiscal_position_id,
|
po.fiscal_position_id,
|
||||||
l.product_id,
|
l.product_id,
|
||||||
p.product_tmpl_id,
|
p.product_tmpl_id,
|
||||||
t.categ_id,
|
t.categ_id,
|
||||||
s.date_order,
|
po.date_order,
|
||||||
s.state,
|
po.state,
|
||||||
u.uom_type,
|
line_uom.uom_type,
|
||||||
u.category_id,
|
line_uom.category_id,
|
||||||
t.uom_id,
|
t.uom_id,
|
||||||
u.id,
|
line_uom.id,
|
||||||
u2.factor,
|
product_uom.factor,
|
||||||
partner.country_id,
|
partner.country_id,
|
||||||
partner.commercial_partner_id,
|
partner.commercial_partner_id,
|
||||||
analytic_account.id
|
analytic_account.id,
|
||||||
|
po.id
|
||||||
"""
|
"""
|
||||||
return group_by_str
|
return group_by_str
|
||||||
|
|||||||
@@ -4,12 +4,11 @@
|
|||||||
<field name="name">product.month.pivot</field>
|
<field name="name">product.month.pivot</field>
|
||||||
<field name="model">purchase.report</field>
|
<field name="model">purchase.report</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<pivot string="Purchase Orders Statistics" disable_linking="True">
|
<pivot string="Purchase Analysis" disable_linking="True" display_quantity="true">
|
||||||
<field name="partner_id" type="row"/>
|
<field name="category_id" type="row"/>
|
||||||
<field name="date_order" interval="month" type="col"/>
|
<field name="order_id" type="measure"/>
|
||||||
|
<field name="untaxed_total" type="measure"/>
|
||||||
<field name="price_total" type="measure"/>
|
<field name="price_total" type="measure"/>
|
||||||
<field name="unit_quantity" type="measure"/>
|
|
||||||
<field name="price_average" type="measure"/>
|
|
||||||
</pivot>
|
</pivot>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -17,10 +16,9 @@
|
|||||||
<field name="name">product.month.graph</field>
|
<field name="name">product.month.graph</field>
|
||||||
<field name="model">purchase.report</field>
|
<field name="model">purchase.report</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<graph string="Purchase Orders Statistics">
|
<graph string="Purchase Orders Statistics" type="line">
|
||||||
<field name="partner_id" type="row"/>
|
<field name="date_approve" interval="day" type="col"/>
|
||||||
<field name="date_order" interval="month" type="col"/>
|
<field name="untaxed_total" type="measure"/>
|
||||||
<field name="price_average" type="measure"/>
|
|
||||||
</graph>
|
</graph>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -31,7 +29,6 @@
|
|||||||
<field name="model_id">purchase.report</field>
|
<field name="model_id">purchase.report</field>
|
||||||
<field name="domain">[('state','!=','cancel')]</field>
|
<field name="domain">[('state','!=','cancel')]</field>
|
||||||
<field name="user_id" eval="False"/>
|
<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>
|
||||||
<record id="filter_purchase_order_price_per_supplier" model="ir.filters">
|
<record id="filter_purchase_order_price_per_supplier" model="ir.filters">
|
||||||
<field name="name">Price Per Vendor</field>
|
<field name="name">Price Per Vendor</field>
|
||||||
@@ -54,8 +51,8 @@
|
|||||||
<field name="model">purchase.report</field>
|
<field name="model">purchase.report</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search string="Purchase Orders">
|
<search string="Purchase Orders">
|
||||||
<filter string="Quotations" name="quotes" domain="[('state','=','draft')]"/>
|
<filter string="Requests for Quotation" name="quotes" domain="[('state','=','draft')]"/>
|
||||||
<filter string="Orders" name="orders" domain="[('state','!=','draft'),('state','!=','cancel')]"/>
|
<filter string="Purchase Orders" name="orders" domain="[('state','!=','draft'),('state','!=','cancel')]"/>
|
||||||
<field name="partner_id"/>
|
<field name="partner_id"/>
|
||||||
<field name="product_id"/>
|
<field name="product_id"/>
|
||||||
<group expand="0" string="Extended Filters">
|
<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" name="group_partner_id" context="{'group_by':'partner_id'}"/>
|
||||||
<filter string="Vendor Country" name="country_id" context="{'group_by':'country_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="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="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="Status" name="status" context="{'group_by':'state'}"/>
|
||||||
<filter string="Company" name="company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
<filter string="Company" name="company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="Order Date" name="order_month" context="{'group_by': 'date_order:month'}"/>
|
<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>
|
</group>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
@@ -90,7 +88,8 @@
|
|||||||
<field name="target">current</field>
|
<field name="target">current</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem id="purchase_report" name="Reporting" parent="purchase.menu_purchase_root" sequence="99"
|
<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="menu_report_purchase" name="Purchase" action="action_purchase_order_report_all" parent="purchase_report" sequence="1" groups="purchase.group_purchase_manager"/>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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')
|
||||||
@@ -175,7 +175,8 @@
|
|||||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
<field name="currency_id" groups="base.group_multi_currency"/>
|
||||||
</group>
|
</group>
|
||||||
<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="origin" attrs="{'invisible': [('origin','=',False)]}"/>
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||||
</group>
|
</group>
|
||||||
@@ -374,7 +375,8 @@
|
|||||||
<tree decoration-bf="message_unread==True" decoration-muted="state=='cancel'" decoration-info="state in ('wait','confirmed')" string="Purchase Order">
|
<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="message_unread" invisible="1"/>
|
||||||
<field name="name" string="Reference"/>
|
<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="partner_id"/>
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||||
<field name="date_planned" invisible="context.get('quotation_only', False)"/>
|
<field name="date_planned" invisible="context.get('quotation_only', False)"/>
|
||||||
@@ -420,6 +422,7 @@
|
|||||||
<field name="res_model">purchase.order</field>
|
<field name="res_model">purchase.order</field>
|
||||||
<field name="view_mode">tree,kanban,form,pivot,graph,calendar,activity</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="search_view_id" ref="view_purchase_order_filter"/>
|
||||||
|
<field name="context">{'quotation_only': True}</field>
|
||||||
<field name="help" type="html">
|
<field name="help" type="html">
|
||||||
<p class="o_view_nocontent_smiling_face">
|
<p class="o_view_nocontent_smiling_face">
|
||||||
Create a request for quotation
|
Create a request for quotation
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class PurchaseReport(models.Model):
|
|||||||
return super(PurchaseReport, self)._select() + ", spt.warehouse_id as picking_type_id"
|
return super(PurchaseReport, self)._select() + ", spt.warehouse_id as picking_type_id"
|
||||||
|
|
||||||
def _from(self):
|
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):
|
def _group_by(self):
|
||||||
return super(PurchaseReport, self)._group_by() + ", spt.warehouse_id"
|
return super(PurchaseReport, self)._group_by() + ", spt.warehouse_id"
|
||||||
|
|||||||
Reference in New Issue
Block a user