summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Stukkens (LTU) <ltu@odoo.com>2020-03-17 09:54:51 +0000
committerThibault Delavallée <tde@odoo.com>2020-03-31 08:08:22 +0000
commit38294dbc99a344ea1a3c7e534ddf7d92b17b0be9 (patch)
tree6f805fad72abcfd3c4c08fca201f5c256b1c419c
parent30ab8ac0222514a37d232e63da925ac6fdfe96b1 (diff)
[IMP] purchase, purchase_requisition: improve UX
Several improvements in order to improve user interface are done here. [IMP] purchase: Prevent create PO&RFQ in calendar It was possible to create PO's and RFQ's from the calendar view. The Product Owner wanted to prevent the users from doing so. [IMP] purchase: Add tooltip to Receipt Date [FIX] purchase: Align report & stat button data on product form The use of Last 365 days time_range in the purchase analysis was automatically excluding today's purchases wich was confusing users as the stat button info was taking those into account. Different behaviours were implemented for product template and product product in the filters that were used which makes no sense. Use of context_today() instead of datetime.now() in order to take the user's timezone into account. [IMP] purchase: Use relevant dates for RFQ's and PO's in calendar view The date used in order to display RFQs and POs in the calendar was date_planned which is not mandatory and so not always filled. It has been decided to use the order_date for the RFQ's and date_approve for PO's. [IMP] purchase_requisition: Making Agreement selection type more explicit [IMP] purchase: Show UOM menu only if installed [IMP] purchase: Add product variant in settings [IMP] purchase: Remove Favorites predefined filters [IMP] purchase: Rephrase PO action helper [IMP] purchase: Allow open/edit Agreement Type [IMP] purchase: Rephrase RFQ action helper [IMP] purchase: Remove PO's and RFQ's name from fields in calendar The Product Owner originally wanted to have a link on the PO name field that was shown in the calendat popover. As the Edit button already allows to edit the PO's or RFQ's from the popover it was decided to simply remove the field (as it was already displayed at the top of the popover) [IMP] purchase: Open the right view when click on Reporting top menu Task ID #2196688 Closes #47810 Related: odoo/enterprise#9294 Related: odoo/upgrade#961 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
-rw-r--r--addons/purchase/models/product.py16
-rw-r--r--addons/purchase/models/purchase.py9
-rw-r--r--addons/purchase/report/purchase_report_views.xml28
-rw-r--r--addons/purchase/views/purchase_views.xml35
-rw-r--r--addons/purchase/views/res_config_settings_views.xml17
-rw-r--r--addons/purchase_requisition/models/purchase_requisition.py4
-rw-r--r--addons/purchase_requisition/views/purchase_requisition_views.xml2
7 files changed, 60 insertions, 51 deletions
diff --git a/addons/purchase/models/product.py b/addons/purchase/models/product.py
index b6459638716..9c53328324a 100644
--- a/addons/purchase/models/product.py
+++ b/addons/purchase/models/product.py
@@ -5,6 +5,7 @@ from datetime import timedelta
from odoo import api, fields, models, _
from odoo.addons.base.models.res_partner import WARNING_MESSAGE, WARNING_HELP
from odoo.tools.float_utils import float_round
+from dateutil.relativedelta import relativedelta
class ProductTemplate(models.Model):
@@ -43,8 +44,7 @@ class ProductTemplate(models.Model):
action['domain'] = ['&', ('state', 'in', ['purchase', 'done']), ('product_tmpl_id', 'in', self.ids)]
action['context'] = {
'graph_measure': 'qty_ordered',
- 'search_default_orders': 1,
- 'time_ranges': {'field': 'date_approve', 'range': 'last_365_days'}
+ 'search_default_later_than_a_year_ago': True
}
return action
@@ -56,13 +56,12 @@ class ProductProduct(models.Model):
purchased_product_qty = fields.Float(compute='_compute_purchased_product_qty', string='Purchased')
def _compute_purchased_product_qty(self):
- date_from = fields.Datetime.to_string(fields.datetime.now() - timedelta(days=365))
+ date_from = fields.Datetime.to_string(fields.Date.context_today(self) - relativedelta(years=1))
domain = [
- ('state', 'in', ['purchase', 'done']),
+ ('order_id.state', 'in', ['purchase', 'done']),
('product_id', 'in', self.ids),
- ('date_order', '>', date_from)
+ ('order_id.date_approve', '>=', date_from)
]
- PurchaseOrderLines = self.env['purchase.order.line'].search(domain)
order_lines = self.env['purchase.order.line'].read_group(domain, ['product_id', 'product_uom_qty'], ['product_id'])
purchased_data = dict([(data['product_id'][0], data['product_uom_qty']) for data in order_lines])
for product in self:
@@ -75,9 +74,8 @@ class ProductProduct(models.Model):
action = self.env.ref('purchase.action_purchase_order_report_all').read()[0]
action['domain'] = ['&', ('state', 'in', ['purchase', 'done']), ('product_id', 'in', self.ids)]
action['context'] = {
- 'search_default_last_year_purchase': 1,
- 'search_default_status': 1, 'search_default_order_month': 1,
- 'graph_measure': 'qty_ordered'
+ 'graph_measure': 'qty_ordered',
+ 'search_default_later_than_a_year_ago': True
}
return action
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 868dfe37b26..dc52d85cae7 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -98,7 +98,9 @@ class PurchaseOrder(models.Model):
], string='Billing Status', compute='_get_invoiced', store=True, readonly=True, copy=False, default='no')
# There is no inverse function on purpose since the date may be different on each line
- date_planned = fields.Datetime(string='Receipt Date', index=True)
+ date_planned = fields.Datetime(string='Receipt Date', index=True,
+ help='This is the Receipt Date promised by the supplier. If set, the receipt will be scheduled at this date.')
+ date_calendar_start = fields.Datetime(compute='_compute_date_calendar_start', readonly=True, store=True)
amount_untaxed = fields.Monetary(string='Untaxed Amount', store=True, readonly=True, compute='_amount_all', tracking=True)
amount_tax = fields.Monetary(string='Taxes', store=True, readonly=True, compute='_amount_all')
@@ -128,6 +130,11 @@ class PurchaseOrder(models.Model):
for order in self:
order.access_url = '/my/purchase/%s' % (order.id)
+ @api.depends('state', 'date_order', 'date_approve')
+ def _compute_date_calendar_start(self):
+ for order in self:
+ order.date_calendar_start = order.date_approve if (order.state in ['purchase', 'done']) else order.date_order
+
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
args = args or []
diff --git a/addons/purchase/report/purchase_report_views.xml b/addons/purchase/report/purchase_report_views.xml
index 250443025ff..a9fff659f69 100644
--- a/addons/purchase/report/purchase_report_views.xml
+++ b/addons/purchase/report/purchase_report_views.xml
@@ -23,29 +23,6 @@
</field>
</record>
- <!-- Custom reports (aka filters) -->
- <record id="filter_purchase_order_monthly_purchases" model="ir.filters">
- <field name="name">Monthly Purchases</field>
- <field name="model_id">purchase.report</field>
- <field name="domain">[('state','!=','cancel')]</field>
- <field name="user_id" eval="False"/>
- </record>
- <record id="filter_purchase_order_price_per_supplier" model="ir.filters">
- <field name="name">Price Per Vendor</field>
- <field name="model_id">purchase.report</field>
- <field name="domain">[('state','!=','draft'),('state','!=','cancel')]</field>
- <field name="user_id" eval="False"/>
- <field name="context">{'group_by': ['partner_id'], 'col_group_by': ['product_id'], 'measures': ['price_average']}</field>
- </record>
- <record id="filter_purchase_order_average_delivery_time" model="ir.filters">
- <field name="name">Average Delivery Time</field>
- <field name="model_id">purchase.report</field>
- <field name="domain">[('state','!=','draft'),('state','!=','cancel')]</field>
- <field name="user_id" eval="False"/>
- <field name="context">{'group_by': ['partner_id'], 'measures': ['delay_pass']}</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>
@@ -53,6 +30,7 @@
<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')))]"/>
<field name="partner_id"/>
<field name="product_id"/>
<group expand="0" string="Extended Filters">
@@ -87,8 +65,6 @@
<field name="target">current</field>
</record>
- <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"/>
+ <menuitem id="purchase_report" name="Reporting" parent="purchase.menu_purchase_root" sequence="99" groups="purchase.group_purchase_manager" action="action_purchase_order_report_all"/>
</odoo>
diff --git a/addons/purchase/views/purchase_views.xml b/addons/purchase/views/purchase_views.xml
index de63c1550c4..da5d47989b4 100644
--- a/addons/purchase/views/purchase_views.xml
+++ b/addons/purchase/views/purchase_views.xml
@@ -24,19 +24,31 @@
<menuitem
id="menu_product_in_config_purchase" name="Products"
- parent="menu_purchase_config" sequence="30" groups="base.group_no_one"/>
+ parent="menu_purchase_config" sequence="30"/>
+
+ <record model="ir.ui.menu" id="menu_product_in_config_purchase">
+ <field name="groups_id" eval="False"/>
+ </record>
+
+ <menuitem id="menu_product_attribute_action"
+ action="product.attribute_action" name="Product Attributes"
+ parent="purchase.menu_product_in_config_purchase" groups="product.group_product_variant" sequence="1"/>
<menuitem
action="product.product_category_action_form" id="menu_product_category_config_purchase"
- parent="purchase.menu_product_in_config_purchase" sequence="1" />
+ parent="purchase.menu_product_in_config_purchase" sequence="3" />
- <menuitem
- action="uom.product_uom_categ_form_action" id="menu_purchase_uom_categ_form_action"
- parent="purchase.menu_product_in_config_purchase" sequence="10" groups="uom.group_uom"/>
+ <menuitem
+ id="menu_unit_of_measure_in_config_purchase" name="Units of Measures"
+ parent="menu_purchase_config" sequence="40" groups="uom.group_uom" />
<menuitem
action="uom.product_uom_form_action" id="menu_purchase_uom_form_action"
- parent="purchase.menu_product_in_config_purchase" sequence="5" groups="uom.group_uom"/>
+ parent="purchase.menu_unit_of_measure_in_config_purchase" sequence="5" groups="uom.group_uom"/>
+
+ <menuitem
+ action="uom.product_uom_categ_form_action" id="menu_purchase_uom_categ_form_action"
+ parent="purchase.menu_unit_of_measure_in_config_purchase" sequence="10" groups="uom.group_uom"/>
<!-- Products Control Menu -->
<menuitem id="menu_purchase_products" name="Products" parent="purchase.menu_purchase_root" sequence="5"/>
@@ -87,9 +99,8 @@
<field name="model">purchase.order</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
- <calendar string="Calendar View" date_start="date_planned" color="partner_id" hide_time="true" event_limit="5">
+ <calendar string="Calendar View" date_start="date_calendar_start" color="partner_id" hide_time="true" event_limit="5" create="false">
<field name="currency_id" invisible="1"/>
- <field name="name"/>
<field name="partner_ref"/>
<field name="amount_total" widget="monetary"/>
<field name="partner_id" filters="1"/>
@@ -548,8 +559,8 @@
<p class="o_view_nocontent_smiling_face">
Create a request for quotation
</p><p>
- The quotation contains the history of the discussion
- you had with your vendor.
+ The requests for quotation are documents that will be sent to your suppliers to request prices for different products you consider buying.
+ Once an agreement has been found with the supplier, they will be confirmed and turned into purchase orders.
</p>
</field>
</record>
@@ -568,9 +579,9 @@
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a quotation
+ Create a purchase order
</p><p>
- It will be converted into a purchase order.
+ Once you ordered your products to your supplier, confirm your request for quotation and it will turn into a purchase order.
</p>
</field>
</record>
diff --git a/addons/purchase/views/res_config_settings_views.xml b/addons/purchase/views/res_config_settings_views.xml
index 98ba8144739..352c9cd1eb2 100644
--- a/addons/purchase/views/res_config_settings_views.xml
+++ b/addons/purchase/views/res_config_settings_views.xml
@@ -109,6 +109,23 @@
</div>
<h2>Products</h2>
<div class="row mt16 o_settings_container" name="matrix_setting_container">
+ <div class="col-12 col-lg-6 o_setting_box" id="variant_options">
+ <div class="o_setting_left_pane">
+ <field name="group_product_variant"/>
+ </div>
+ <div class="o_setting_right_pane">
+ <label for="group_product_variant"/>
+ <a href="https://www.odoo.com/documentation/user/13.0/sales/products_prices/products/variants.html" title="Documentation" class="o_doc_link fa fa-lg fa-book" target="_blank"></a>
+ <div class="text-muted">
+ Purchase variants of a product using attributes (size, color, etc.)
+ </div>
+ <div class="content-group" attrs="{'invisible': [('group_product_variant','=',False)]}">
+ <div class="mt8">
+ <button name="%(product.attribute_action)d" icon="fa-arrow-right" type="action" string="Attributes" class="btn-link"/>
+ </div>
+ </div>
+ </div>
+ </div>
<div class="col-12 col-lg-6 o_setting_box"
id="product_matrix"
title="If installed, the product variants will be added to purchase orders through a grid entry.">
diff --git a/addons/purchase_requisition/models/purchase_requisition.py b/addons/purchase_requisition/models/purchase_requisition.py
index 1b863ba2f35..3438498fc41 100644
--- a/addons/purchase_requisition/models/purchase_requisition.py
+++ b/addons/purchase_requisition/models/purchase_requisition.py
@@ -24,10 +24,10 @@ class PurchaseRequisitionType(models.Model):
name = fields.Char(string='Agreement Type', required=True, translate=True)
sequence = fields.Integer(default=1)
exclusive = fields.Selection([
- ('exclusive', 'Select only one RFQ (exclusive)'), ('multiple', 'Select multiple RFQ')],
+ ('exclusive', 'Select only one RFQ (exclusive)'), ('multiple', 'Select multiple RFQ (non-exclusive)')],
string='Agreement Selection Type', required=True, default='multiple',
help="""Select only one RFQ (exclusive): when a purchase order is confirmed, cancel the remaining purchase order.\n
- Select multiple RFQ: allows multiple purchase orders. On confirmation of a purchase order it does not cancel the remaining orders""")
+ Select multiple RFQ (non-exclusive): allows multiple purchase orders. On confirmation of a purchase order it does not cancel the remaining orders""")
quantity_copy = fields.Selection([
('copy', 'Use quantities of agreement'), ('none', 'Set quantities manually')],
string='Quantities', required=True, default='none')
diff --git a/addons/purchase_requisition/views/purchase_requisition_views.xml b/addons/purchase_requisition/views/purchase_requisition_views.xml
index afbbb59fee6..fc82df844df 100644
--- a/addons/purchase_requisition/views/purchase_requisition_views.xml
+++ b/addons/purchase_requisition/views/purchase_requisition_views.xml
@@ -134,7 +134,7 @@
<group>
<field name="is_quantity_copy" invisible='1'/>
<field name="user_id" attrs="{'readonly': [('state','not in',('draft','in_progress','open'))]}" domain="[('share', '=', False)]"/>
- <field name="type_id" attrs="{'readonly': [('state','!=','draft')]}" widget="selection"/>
+ <field name="type_id" attrs="{'readonly': [('state','!=','draft')]}"/>
<field name="vendor_id" context="{'res_partner_search_mode': 'supplier'}" attrs="{'required': [('is_quantity_copy', '=', 'none')], 'readonly': [('state', 'in', ['ongoing','done'])]}"/>
<field name="currency_id" groups="base.group_multi_currency"/>
</group>