Initial commit: Core packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:45 +02:00
commit 12c29a983b
9512 changed files with 8379910 additions and 0 deletions

View file

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import purchase_report
from . import purchase_bill

View file

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, tools
from odoo.tools import formatLang
class PurchaseBillUnion(models.Model):
_name = 'purchase.bill.union'
_auto = False
_description = 'Purchases & Bills Union'
_order = "date desc, name desc"
_rec_names_search = ['name', 'reference']
name = fields.Char(string='Reference', readonly=True)
reference = fields.Char(string='Source', readonly=True)
partner_id = fields.Many2one('res.partner', string='Vendor', readonly=True)
date = fields.Date(string='Date', readonly=True)
amount = fields.Float(string='Amount', readonly=True)
currency_id = fields.Many2one('res.currency', string='Currency', readonly=True)
company_id = fields.Many2one('res.company', 'Company', readonly=True)
vendor_bill_id = fields.Many2one('account.move', string='Vendor Bill', readonly=True)
purchase_order_id = fields.Many2one('purchase.order', string='Purchase Order', readonly=True)
def init(self):
tools.drop_view_if_exists(self.env.cr, 'purchase_bill_union')
self.env.cr.execute("""
CREATE OR REPLACE VIEW purchase_bill_union AS (
SELECT
id, name, ref as reference, partner_id, date, amount_untaxed as amount, currency_id, company_id,
id as vendor_bill_id, NULL as purchase_order_id
FROM account_move
WHERE
move_type='in_invoice' and state = 'posted'
UNION
SELECT
-id, name, partner_ref as reference, partner_id, date_order::date as date, amount_untaxed as amount, currency_id, company_id,
NULL as vendor_bill_id, id as purchase_order_id
FROM purchase_order
WHERE
state in ('purchase', 'done') AND
invoice_status in ('to invoice', 'no')
)""")
def name_get(self):
result = []
for doc in self:
name = doc.name or ''
if doc.reference:
name += ' - ' + doc.reference
amount = doc.amount
if doc.purchase_order_id and doc.purchase_order_id.invoice_status == 'no':
amount = 0.0
name += ': ' + formatLang(self.env, amount, monetary=True, currency_obj=doc.currency_id)
result.append((doc.id, name))
return result

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_purchase_bill_union_filter" model="ir.ui.view">
<field name="name">purchase.bill.union.select</field>
<field name="model">purchase.bill.union</field>
<field name="arch" type="xml">
<search string="Search Reference Document">
<field name="name" string="Reference" filter_domain="['|', ('name','ilike',self), ('reference','=like',self+'%')]"/>
<field name="amount"/>
<separator/>
<field name="partner_id" operator="child_of"/>
<separator/>
<filter name="purchase_orders" string="Purchase Orders" domain="[('purchase_order_id', '!=', False)]"/>
<filter name="vendor_bills" string="Vendor Bills" domain="[('vendor_bill_id', '!=', False)]"/>
</search>
</field>
</record>
<record id="view_purchase_bill_union_tree" model="ir.ui.view">
<field name="name">purchase.bill.union.tree</field>
<field name="model">purchase.bill.union</field>
<field name="arch" type="xml">
<tree string="Reference Document">
<field name="name"/>
<field name="reference"/>
<field name="partner_id"/>
<field name="date"/>
<field name="amount"/>
<field name="currency_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
</tree>
</field>
</record>
</odoo>

View file

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_purchaseorder_document">
<t t-call="web.external_layout">
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)"/>
<t t-set="address">
<div t-field="o.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "vat"], "no_marker": True, "phone_icons": True}'/>
</t>
<t t-if="o.dest_address_id">
<t t-set="information_block">
<strong>Shipping address:</strong>
<div t-if="o.dest_address_id">
<div t-field="o.dest_address_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone"], "no_marker": True, "phone_icons": True}' name="purchase_shipping_address"/>
</div>
</t>
</t>
<div class="page">
<div class="oe_structure"/>
<div class="mt-4">
<h2 t-if="o.state in ['draft', 'sent', 'to approve']">Request for Quotation #<span t-field="o.name"/></h2>
<h2 t-if="o.state in ['purchase', 'done']">Purchase Order #<span t-field="o.name"/></h2>
<h2 t-if="o.state == 'cancel'">Cancelled Purchase Order #<span t-field="o.name"/></h2>
</div>
<div id="informations" class="row mt-4 mb32">
<div t-if="o.user_id" class="col-3 bm-2">
<strong>Purchase Representative:</strong>
<p t-field="o.user_id" class="m-0"/>
</div>
<div t-if="o.partner_ref" class="col-3 bm-2">
<strong>Your Order Reference:</strong>
<p t-field="o.partner_ref" class="m-0"/>
</div>
<div t-if="o.state in ['purchase','done'] and o.date_approve" class="col-3 bm-2">
<strong>Order Date:</strong>
<p t-field="o.date_approve" class="m-0"/>
</div>
<div t-elif="o.date_order" class="col-3 bm-2">
<strong >Order Deadline:</strong>
<p t-field="o.date_order" class="m-0"/>
</div>
</div>
<table class="table table-sm o_main_table table-borderless mt-4">
<thead style="display: table-row-group">
<tr>
<th name="th_description"><strong>Description</strong></th>
<th name="th_taxes"><strong>Taxes</strong></th>
<th name="th_date_req" class="text-center"><strong>Date Req.</strong></th>
<th name="th_quantity" class="text-end"><strong>Qty</strong></th>
<th name="th_price_unit" class="text-end"><strong>Unit Price</strong></th>
<th name="th_amount" class="text-end"><strong>Amount</strong></th>
</tr>
</thead>
<tbody>
<t t-set="current_subtotal" t-value="0"/>
<t t-foreach="o.order_line" t-as="line">
<t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
<t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
<tr t-att-class="'bg-200 fw-bold o_line_section' if line.display_type == 'line_section' else 'fst-italic o_line_note' if line.display_type == 'line_note' else ''">
<t t-if="not line.display_type">
<td id="product">
<span t-field="line.name"/>
</td>
<t t-set="taxes" t-value="', '.join([(tax.description or tax.name) for tax in line.taxes_id])"/>
<td name="td_taxes" t-attf-class="text-end {{ 'text-nowrap' if len(taxes) &lt; 10 else '' }}">
<span t-out="taxes">Tax 15%</span>
</td>
<td class="text-center">
<span t-field="line.date_planned"/>
</td>
<td class="text-end">
<span t-field="line.product_qty"/>
<span t-field="line.product_uom.name" groups="uom.group_uom"/>
</td>
<td class="text-end">
<span t-field="line.price_unit"/>
</td>
<td class="text-end">
<span t-field="line.price_subtotal"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
</t>
<t t-if="line.display_type == 'line_section'">
<td colspan="99" id="section">
<span t-field="line.name"/>
</td>
<t t-set="current_section" t-value="line"/>
<t t-set="current_subtotal" t-value="0"/>
</t>
<t t-if="line.display_type == 'line_note'">
<td colspan="99" id="note">
<span t-field="line.name"/>
</td>
</t>
</tr>
<t t-if="current_section and (line_last or o.order_line[line_index+1].display_type == 'line_section')">
<tr class="is-subtotal text-end">
<td colspan="99" id="subtotal">
<strong class="mr16">Subtotal</strong>
<span
t-esc="current_subtotal"
t-options='{"widget": "monetary", "display_currency": o.currency_id}'
/>
</td>
</tr>
</t>
</t>
</tbody>
</table>
<div id="total" class="row justify-content-end">
<div class="col-4">
<table class="table table-sm table-borderless">
<t t-set="tax_totals" t-value="o.tax_totals"/>
<t t-call="account.document_tax_totals"/>
</table>
</div>
</div>
<p t-field="o.notes" class="mt-4"/>
<div class="oe_structure"/>
</div>
</t>
</template>
<template id="report_purchaseorder">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="purchase.report_purchaseorder_document" t-lang="o.partner_id.lang"/>
</t>
</t>
</template>
</odoo>

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_purchasequotation_document">
<t t-call="web.external_layout">
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)"/>
<t t-set="forced_vat" t-value="o.fiscal_position_id.foreign_vat"/> <!-- So that it appears in the footer of the report instead of the company VAT if it's set -->
<t t-set="address">
<div t-field="o.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "vat"], "no_marker": True, "phone_icons": True}'/>
</t>
<t t-if="o.dest_address_id">
<t t-set="information_block">
<strong>Shipping address:</strong>
<div t-field="o.dest_address_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone"], "no_marker": True, "phone_icons": True}' name="purchase_shipping_address"/>
</t>
</t>
<div class="page">
<div class="oe_structure"/>
<h2 class="mt-4">Request for Quotation <span t-field="o.name"/></h2>
<table class="table table-sm mt-4">
<thead style="display: table-row-group">
<tr>
<th name="th_description"><strong>Description</strong></th>
<th name="th_expected_date" class="text-center"><strong>Expected Date</strong></th>
<th name="th_quantity" class="text-end"><strong>Qty</strong></th>
</tr>
</thead>
<tbody>
<t t-foreach="o.order_line" t-as="order_line">
<tr t-att-class="'bg-200 fw-bold o_line_section' if order_line.display_type == 'line_section' else 'fst-italic o_line_note' if order_line.display_type == 'line_note' else ''">
<t t-if="not order_line.display_type">
<td id="product">
<span t-field="order_line.name"/>
</td>
<td class="text-center">
<span t-field="order_line.date_planned"/>
</td>
<td class="text-end">
<span t-field="order_line.product_qty"/>
<span t-field="order_line.product_uom" groups="uom.group_uom"/>
</td>
</t>
<t t-else="">
<td colspan="99" id="section">
<span t-field="order_line.name"/>
</td>
</t>
</tr>
</t>
</tbody>
</table>
<p t-field="o.notes" class="mt-4"/>
<div class="oe_structure"/>
</div>
</t>
</template>
<template id="report_purchasequotation">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="purchase.report_purchasequotation_document" t-lang="o.partner_id.lang"/>
</t>
</t>
</template>
</odoo>

View file

@ -0,0 +1,214 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
#
# Please note that these reports are not multi-currency !!!
#
import re
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.osv.expression import AND, expression
class PurchaseReport(models.Model):
_name = "purchase.report"
_description = "Purchase Report"
_auto = False
_order = 'date_order desc, price_total desc'
date_order = fields.Datetime('Order Date', readonly=True)
state = fields.Selection([
('draft', 'Draft RFQ'),
('sent', 'RFQ Sent'),
('to approve', 'To Approve'),
('purchase', 'Purchase Order'),
('done', 'Done'),
('cancel', 'Cancelled')
], 'Status', readonly=True)
product_id = fields.Many2one('product.product', 'Product', readonly=True)
partner_id = fields.Many2one('res.partner', 'Vendor', 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 Confirm', digits=(16, 2), readonly=True, group_operator='avg', help="Amount of time between purchase approval and order by date.")
delay_pass = fields.Float('Days to Receive', digits=(16, 2), readonly=True, group_operator='avg',
help="Amount of time between date planned and order by date for each purchase order line.")
avg_days_to_purchase = fields.Float(
'Average Days to Purchase', digits=(16, 2), readonly=True, store=False, # needs store=False to prevent showing up as a 'measure' option
help="Amount of time between purchase approval and document creation date. Due to a hack needed to calculate this, \
every record will show the same average value, therefore only use this as an aggregated value with group_operator=avg")
price_total = fields.Float('Total', readonly=True)
price_average = fields.Float('Average Cost', readonly=True, group_operator="avg", digits='Product Price')
nbr_lines = fields.Integer('# of Lines', readonly=True)
category_id = fields.Many2one('product.category', 'Product Category', readonly=True)
product_tmpl_id = fields.Many2one('product.template', 'Product Template', readonly=True)
country_id = fields.Many2one('res.country', 'Partner Country', readonly=True)
fiscal_position_id = fields.Many2one('account.fiscal.position', string='Fiscal Position', readonly=True)
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)
@property
def _table_query(self):
''' Report needs to be dynamic to take into account multi-company selected + multi-currency rates '''
return '%s %s %s %s' % (self._select(), self._from(), self._where(), self._group_by())
def _select(self):
select_str = """
SELECT
po.id as order_id,
min(l.id) as 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,
c.currency_id,
t.uom_id as product_uom,
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_total / COALESCE(po.currency_rate, 1.0))::decimal(16,2) * currency_table.rate 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) * currency_table.rate as price_average,
partner.country_id as country_id,
partner.commercial_partner_id as commercial_partner_id,
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) * currency_table.rate 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,
case when t.purchase_method = 'purchase'
then sum(l.product_qty / line_uom.factor * product_uom.factor) - sum(l.qty_invoiced / line_uom.factor * product_uom.factor)
else sum(l.qty_received / line_uom.factor * product_uom.factor) - sum(l.qty_invoiced / line_uom.factor * product_uom.factor)
end as qty_to_be_billed
"""
return select_str
def _from(self):
from_str = """
FROM
purchase_order_line l
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 res_company C ON C.id = po.company_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 {currency_table} ON currency_table.company_id = po.company_id
""".format(
currency_table=self.env['res.currency']._get_query_currency_table({'multi_company': True, 'date': {'date_to': fields.Date.today()}}),
)
return from_str
def _where(self):
return """
WHERE
l.display_type IS NULL
"""
def _group_by(self):
group_by_str = """
GROUP BY
po.company_id,
po.user_id,
po.partner_id,
line_uom.factor,
c.currency_id,
l.price_unit,
po.date_approve,
l.date_planned,
l.product_uom,
po.dest_address_id,
po.fiscal_position_id,
l.product_id,
p.product_tmpl_id,
t.categ_id,
po.date_order,
po.state,
line_uom.uom_type,
line_uom.category_id,
t.uom_id,
t.purchase_method,
line_uom.id,
product_uom.factor,
partner.country_id,
partner.commercial_partner_id,
po.id,
currency_table.rate
"""
return group_by_str
@api.model
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
""" This is a hack to allow us to correctly calculate the average of PO specific date values since
the normal report query result will duplicate PO values across its PO lines during joins and
lead to incorrect aggregation values.
Only the AVG operator is supported for avg_days_to_purchase.
"""
avg_days_to_purchase = next((field for field in fields if re.search(r'\bavg_days_to_purchase\b', field)), False)
if avg_days_to_purchase:
fields.remove(avg_days_to_purchase)
if any(field.split(':')[1].split('(')[0] != 'avg' for field in [avg_days_to_purchase] if field):
raise UserError(_("Value: 'avg_days_to_purchase' should only be used to show an average. If you are seeing this message then it is being accessed incorrectly."))
if 'price_average:avg' in fields:
fields.extend(['aggregated_qty_ordered:array_agg(qty_ordered)'])
fields.extend(['aggregated_price_average:array_agg(price_average)'])
res = []
if fields:
res = super(PurchaseReport, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
if 'price_average:avg' in fields:
qties = 'aggregated_qty_ordered'
special_field = 'aggregated_price_average'
for data in res:
if data[special_field] and data[qties]:
total_unit_cost = sum(float(value) * float(qty) for value, qty in zip(data[special_field], data[qties]) if qty and value)
total_qty_ordered = sum(float(qty) for qty in data[qties] if qty)
data['price_average'] = (total_unit_cost / total_qty_ordered) if total_qty_ordered else 0
del data[special_field]
del data[qties]
if not res and avg_days_to_purchase:
res = [{}]
if avg_days_to_purchase:
self.check_access_rights('read')
query = """ SELECT AVG(days_to_purchase.po_days_to_purchase)::decimal(16,2) AS avg_days_to_purchase
FROM (
SELECT extract(epoch from age(po.date_approve,po.create_date))/(24*60*60) AS po_days_to_purchase
FROM purchase_order po
WHERE po.id IN (
SELECT "purchase_report"."order_id" FROM %s WHERE %s)
) AS days_to_purchase
"""
subdomain = AND([domain, [('company_id', '=', self.env.company.id), ('date_approve', '!=', False)]])
subtables, subwhere, subparams = expression(subdomain, self).query.get_sql()
self.env.cr.execute(query % (subtables, subwhere), subparams)
res[0].update({
'__count': 1,
avg_days_to_purchase.split(':')[0]: self.env.cr.fetchall()[0][0],
})
return res

View file

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="view_purchase_order_pivot">
<field name="name">product.month.pivot</field>
<field name="model">purchase.report</field>
<field name="arch" type="xml">
<pivot string="Purchase Analysis" display_quantity="1" sample="1">
<field name="category_id" type="row"/>
<field name="order_id" type="measure"/>
<field name="untaxed_total" type="measure"/>
<field name="price_total" type="measure"/>
</pivot>
</field>
</record>
<record model="ir.ui.view" id="view_purchase_order_graph">
<field name="name">product.month.graph</field>
<field name="model">purchase.report</field>
<field name="arch" type="xml">
<graph string="Purchase Analysis" type="line" sample="1">
<field name="date_approve" interval="day"/>
<field name="untaxed_total" type="measure"/>
</graph>
</field>
</record>
<record id="purchase_report_view_tree" model="ir.ui.view">
<field name="name">purchase.report.view.tree</field>
<field name="model">purchase.report</field>
<field name="arch" type="xml">
<tree string="Purchase Analysis">
<field name="date_order" widget="date"/>
<field name="order_id" optional="show"/>
<field name="partner_id" optional="show"/>
<field name="product_id" optional="show"/>
<field name="category_id" optional="show"/>
<field name="user_id" optional="show" widget="many2one_avatar_user"/>
<field name="company_id" optional="show" groups="base.group_multi_company"/>
<field name="qty_ordered" optional="hide" sum="Sum of Qty Ordered"/>
<field name="qty_received" optional="hide" sum="Sum of Qty Received"/>
<field name="qty_billed" optional="hide" sum="Sum of Qty Billed"/>
<field name="currency_id" optional="show" invisible="1"/>
<field name="untaxed_total" optional="hide" widget="monetary" sum="Sum of Untaxed Total"/>
<field name="price_total" optional="show" widget="monetary" sum="Sum of Total"/>
<field name="state" optional="show"/>
</tree>
</field>
</record>
<record id="view_purchase_order_search" model="ir.ui.view">
<field name="name">report.purchase.order.search</field>
<field name="model">purchase.report</field>
<field name="arch" type="xml">
<search string="Purchase Orders">
<filter string="Requests for Quotation" name="quotes" domain="[('state','in',('draft','sent'))]"/>
<filter string="Purchase Orders" name="orders" domain="[('state','!=','draft'), ('state','!=','sent'), ('state','!=','cancel')]"/>
<filter string="Confirmation Date Last Year" name="later_than_a_year_ago" domain="[('date_approve', '&gt;=', ((context_today()-relativedelta(years=1)).strftime('%Y-%m-%d')))]"/>
<filter name="filter_date_order" date="date_order"/>
<filter name="filter_date_approve" date="date_approve" default_period="this_month"/>
<field name="partner_id"/>
<field name="product_id"/>
<group expand="0" string="Extended Filters">
<field name="user_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="date_order"/>
<field name="date_approve"/>
<field name="category_id" filter_domain="[('category_id', 'child_of', self)]"/>
</group>
<group expand="1" string="Group By">
<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="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>
</record>
<record id="action_purchase_order_report_all" model="ir.actions.act_window">
<field name="name">Purchase Analysis</field>
<field name="res_model">purchase.report</field>
<field name="view_mode">graph,pivot</field>
<field name="view_id"></field> <!-- force empty -->
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No Purchase Analysis
</p><p>
This analysis allows you to easily check and analyse your company purchase history and performance.
You can track your negotiation performance, the delivery performance of your vendors, etc
</p>
</field>
<field name="target">current</field>
</record>
<menuitem id="purchase_report_main" name="Reporting" parent="purchase.menu_purchase_root" sequence="99" groups="purchase.group_purchase_manager"/>
<menuitem id="purchase_report" name="Purchase" parent="purchase.purchase_report_main" sequence="99" groups="purchase.group_purchase_manager" action="action_purchase_order_report_all"/>
</odoo>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="action_report_purchase_order" model="ir.actions.report">
<field name="name">Purchase Order</field>
<field name="model">purchase.order</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">purchase.report_purchaseorder</field>
<field name="report_file">purchase.report_purchaseorder</field>
<field name="print_report_name">
(object.state in ('draft', 'sent') and 'Request for Quotation - %s' % (object.name) or
'Purchase Order - %s' % (object.name))</field>
<field name="binding_model_id" ref="model_purchase_order"/>
<field name="binding_type">report</field>
</record>
<record id="report_purchase_quotation" model="ir.actions.report">
<field name="name">Request for Quotation</field>
<field name="model">purchase.order</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">purchase.report_purchasequotation</field>
<field name="report_file">purchase.report_purchasequotation</field>
<field name="print_report_name">'Request for Quotation - %s' % (object.name)</field>
<field name="binding_model_id" ref="model_purchase_order"/>
<field name="binding_type">report</field>
</record>
</data>
</odoo>