Browse Source

Jul 25 : [UPDT] Updated 'top_selling_product_report'

pull/267/head
AjmalCybro 2 years ago
parent
commit
eb42d1ba45
  1. 38
      top_selling_product_report/README.rst
  2. 2
      top_selling_product_report/__init__.py
  3. 13
      top_selling_product_report/__manifest__.py
  4. 5
      top_selling_product_report/doc/RELEASE_NOTES.md
  5. 2
      top_selling_product_report/report/__init__.py
  6. 96
      top_selling_product_report/report/top_selling_report.py
  7. 1
      top_selling_product_report/report/top_selling_report.xml
  8. 84
      top_selling_product_report/report/top_selling_report_template.xml
  9. 1
      top_selling_product_report/security/ir.model.access.csv
  10. 43
      top_selling_product_report/wizard/top_selling_wizard.py
  11. 12
      top_selling_product_report/wizard/top_selling_wizard.xml

38
top_selling_product_report/README.rst

@ -1,5 +1,9 @@
Top/Least Selling Product Report v16 .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
==================================== :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
Top/Least Selling Product Report
================================
Top Selling and Least Selling Product Reports Top Selling and Least Selling Product Reports
Installation Installation
@ -11,6 +15,15 @@ Configuration
============= =============
No additional configurations needed No additional configurations needed
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
Gnu Affero General Public License, Version 3 (AGPL v3).
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Credits Credits
======= =======
Developer: Ajmal JK @ cybrosys, Contact: odoo@cybrosys.com Developer: Ajmal JK @ cybrosys, Contact: odoo@cybrosys.com
@ -19,3 +32,24 @@ V14 : Sayooj A O
V15 : Irfan @ cybrosys V15 : Irfan @ cybrosys
V16 :Pranav @ cybrosys V16 :Pranav @ cybrosys
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit `Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

2
top_selling_product_report/__init__.py

@ -19,5 +19,5 @@
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################# #############################################################################
from . import wizard
from . import report from . import report
from . import wizard

13
top_selling_product_report/__manifest__.py

@ -21,19 +21,20 @@
############################################################################# #############################################################################
{ {
'name': 'Top/Least Selling Product Report', 'name': 'Top/Least Selling Product Report',
'version': '16.0.1.0.0', 'version': '16.0.1.0.1',
'category': 'Sales',
'summary': 'Top Selling and Least Selling Product Reports', 'summary': 'Top Selling and Least Selling Product Reports',
'description': 'Top Selling Products,Fast Moving Products,Most Selling Products,Top Growing Products,Least Selling Products,', 'description': 'Top Selling Products,Fast Moving Products,Most Selling '
'Products,Top Growing Products,Least Selling Products',
'author': 'Cybrosys Techno solutions', 'author': 'Cybrosys Techno solutions',
'maintainer': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com', 'website': 'https://www.cybrosys.com',
'depends': ['base', 'sale_management', 'stock', 'sale'], 'depends': ['base', 'sale_management', 'stock', 'sale'],
'category': 'Sale', 'data': ['security/ir.model.access.csv',
'data': ['wizard/top_selling_wizard.xml',
'report/top_selling_report.xml', 'report/top_selling_report.xml',
'report/top_selling_report_template.xml', 'report/top_selling_report_template.xml',
'security/ir.model.access.csv' 'wizard/top_selling_wizard.xml',
], ],
'images': ['static/description/banner.png'], 'images': ['static/description/banner.png'],
'license': 'AGPL-3', 'license': 'AGPL-3',

5
top_selling_product_report/doc/RELEASE_NOTES.md

@ -4,3 +4,8 @@
#### Version 16.0.1.0.0 #### Version 16.0.1.0.0
##### ADD ##### ADD
- Initial commit for Top Selling Product Report - Initial commit for Top Selling Product Report
#### 21.07.2023
#### Version 16.0.1.0.1
##### FIX
- Updated the report to include the sold product data from the Point of Sale (POS) module when installed.

2
top_selling_product_report/report/__init__.py

@ -3,7 +3,7 @@
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). # Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author:Cybrosys Techno Solutions(odoo@cybrosys.com) # Author:Cybrosys Techno Solutions(odoo@cybrosys.com)
# #
# You can modify it under the terms of the GNU AFFERO # You can modify it under the terms of the GNU AFFERO

96
top_selling_product_report/report/top_selling_report.py

@ -19,100 +19,112 @@
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################# #############################################################################
from datetime import timedelta, date
import dateutil.relativedelta import dateutil.relativedelta
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from datetime import timedelta, date
from odoo import models from odoo import models
class CustomReport(models.AbstractModel): class CustomReport(models.AbstractModel):
"""The CustomReport abstract Model is used to generate a top-selling
products report based on various date options."""
_name = "report.top_selling_product_report.top_selling_reports" _name = "report.top_selling_product_report.top_selling_reports"
_description = "Top selling products report" _description = "Top selling products report"
def _get_report_values(self, docids, data=None): def _get_report_values(self, docids, data=None):
limit_value = data['period'] if data['period'] else None """Generate the data for the top-selling products report.
Args:
data (dict): A dictionary containing the parameters for the report.
Returns:
dict: A dictionary containing the data and other details of the
top-selling products report."""
limit_value = int(data['period']) if data['period'] else None
date_option = data['date'] date_option = data['date']
date_selected_from = None date_selected_from = None
date_selected = None date_selected = None
date_selected_to = None date_selected_to = None
other_details = {} other_details = {}
company_id = data['company'] company_id = data['company']
warehouse_id = data['warehouse'] warehouse_id = data['warehouse']
from_date = date.today() - dateutil.relativedelta.relativedelta(years=100) from_date = date.today() - dateutil.relativedelta.relativedelta(
years=100)
to_date = date.today() + dateutil.relativedelta.relativedelta(days=1) to_date = date.today() + dateutil.relativedelta.relativedelta(days=1)
if date_option == 'days': if date_option == 'days':
from_date = date.today() - dateutil.relativedelta.relativedelta(
from_date = date.today() - dateutil.relativedelta.relativedelta(days=11) days=11)
to_date = date.today() + dateutil.relativedelta.relativedelta(days=1) to_date = date.today() + dateutil.relativedelta.relativedelta(
days=1)
date_selected = "Last 10 Days" date_selected = "Last 10 Days"
elif date_option == 'last_month': elif date_option == 'last_month':
date_limit = date.today() - dateutil.relativedelta.relativedelta(
date_limit = date.today() - dateutil.relativedelta.relativedelta(months=1) months=1)
from_date = date_limit.replace(day=1) from_date = date_limit.replace(day=1)
to_date = (date_limit + relativedelta(months=1, day=1)) - timedelta(1) to_date = (date_limit + relativedelta(months=1,
day=1)) - timedelta(1)
date_selected = "Last Month" date_selected = "Last Month"
elif date_option == 'curr_month': elif date_option == 'curr_month':
from_date = date.today().replace(day=1) from_date = date.today().replace(day=1)
to_date = date.today() + dateutil.relativedelta.relativedelta(days=1) to_date = date.today() + dateutil.relativedelta.relativedelta(
days=1)
date_selected = "Current Month" date_selected = "Current Month"
elif date_option == 'last_year': elif date_option == 'last_year':
date_limit = date.today() - dateutil.relativedelta.relativedelta(
date_limit = date.today() - dateutil.relativedelta.relativedelta(years=1) years=1)
from_date = date_limit.replace(day=1) from_date = date_limit.replace(day=1)
to_date = (date_limit + relativedelta(months=12, day=1)) - timedelta(1) to_date = (date_limit + relativedelta(months=12,
day=1)) - timedelta(1)
date_selected = "Last Year" date_selected = "Last Year"
elif date_option == 'curr_year': elif date_option == 'curr_year':
date_limit = date.today() - dateutil.relativedelta.relativedelta(years=1)
from_date = date.today().replace(month=1, day=1) from_date = date.today().replace(month=1, day=1)
to_date = date.today() + dateutil.relativedelta.relativedelta(days=1) to_date = date.today() + dateutil.relativedelta.relativedelta(
days=1)
date_selected = "Current Year" date_selected = "Current Year"
elif date_option == 'select_period': elif date_option == 'select_period':
from_date = data['from_date'] from_date = data['from_date']
to_date = data['to_date'] to_date = data['to_date']
date_selected_from = from_date date_selected_from = from_date
date_selected_to = to_date date_selected_to = to_date
other_details.update({ other_details.update({
'limit': limit_value, 'limit': limit_value,
'least': data['least'], 'least': data['least'],
'range': date_selected, 'range': date_selected,
'date_selected_from': date_selected_from, 'date_selected_from': date_selected_from,
'date_selected_to': date_selected_to, 'date_selected_to': date_selected_to,
}) })
sale_report_model = self.env['sale.report']
cr = self._cr states = sale_report_model._get_done_states()
order = 'asc' if data['least'] else 'desc' data_domain = [('state', 'in', states), ('date', '>=', from_date),
company_id = str(tuple(company_id)) if len(company_id) > 1 else "(" + str(company_id[0]) + ")" ('date', '<=', to_date),
warehouse_id = str(tuple(warehouse_id)) if len(warehouse_id) > 1 else "(" + str(warehouse_id[0]) + ")" ('company_id', 'in', company_id)]
limit_clause = " limit'%s'" % limit_value if limit_value else "" if warehouse_id:
data_domain.append(('warehouse_id', 'in', warehouse_id))
query = ("""select sl.name as product_name,sum(product_uom_qty),pu.name from sale_order_line sl
JOIN sale_order so ON sl.order_id = so.id sale_data = sale_report_model.search(data_domain)
JOIN uom_uom pu on sl.product_uom = pu.id product_dict = {}
where so.date_order::DATE >= '%s'::DATE and for record in sale_data:
so.date_order::DATE <= '%s'::DATE and product_name = record.product_id.display_name
sl.state = 'sale' and so.company_id in %s if product_name in product_dict:
and so.warehouse_id in %s product_dict[product_name][
group by sl.name,pu.name order by sum %s""" % ( 'sold_quantity'] += record.product_uom_qty
from_date, to_date, company_id, warehouse_id, order)) + limit_clause else:
cr.execute(query) product_dict[product_name] = {
dat = cr.dictfetchall() 'product_name': product_name,
'sold_quantity': record.product_uom_qty,
'uom': record.product_uom.name,
}
sorted_products = sorted(product_dict.values(),
key=lambda x: x['sold_quantity'],
reverse=not data['least'])
limit_products = sorted_products[:limit_value]
return { return {
'data': dat, 'data': limit_products,
'other': other_details, 'other': other_details,
} }

1
top_selling_product_report/report/top_selling_report.xml

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<!-- Report action for the Top Selling Product Report -->
<record id="top_selling_pdf" model="ir.actions.report"> <record id="top_selling_pdf" model="ir.actions.report">
<field name="name">Top Selling Product Report</field> <field name="name">Top Selling Product Report</field>
<field name="model">top.selling</field> <field name="model">top.selling</field>

84
top_selling_product_report/report/top_selling_report_template.xml

@ -1,33 +1,50 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<!-- Template for Top Selling Products Report -->
<template id="top_selling_reports"> <template id="top_selling_reports">
<t t-call="web.html_container"> <t t-call="web.html_container">
<!-- The "top_selling_product_report.internal_layout" template is used as the main layout for the report -->
<t t-call="top_selling_product_report.internal_layout"> <t t-call="top_selling_product_report.internal_layout">
<div class="page"> <div class="page">
<div class="oe_structure"/> <div class="oe_structure"/>
<center> <center>
<!-- Display report title based on whether it shows top-selling or least selling products -->
<t t-if="other['least']"> <t t-if="other['least']">
<h2 style="font-size:35px;"><b>Least Selling Products</b></h2> <h2 style="font-size:35px;">
<b>Least Selling Products</b>
</h2>
</t> </t>
<t t-if="not other['least']"> <t t-if="not other['least']">
<h2 style="font-size:35px;"><b>Top Selling Products</b></h2> <h2 style="font-size:35px;">
<b>Top Selling Products</b>
</h2>
</t> </t>
</center> </center>
<div class="oe_structure"/> <div class="oe_structure"/>
<br /> <br />
<span> <span>
<!-- Display the date range or selected period for the report -->
<t t-if="other['range']"> <t t-if="other['range']">
<b>Top Product of :</b> <t t-esc="other['range']"/><br /> <b>Top Product of :</b>
<t t-esc="other['range']"/>
<br />
</t> </t>
<t t-if="other['date_selected_from']"> <t t-if="other['date_selected_from']">
<b>Top Product of :</b> <t t-esc="other['date_selected_from']"/> To <t t-esc="other['date_selected_to']"/><br /> <b>Top Product of :</b>
<t t-esc="other['date_selected_from']"/> To
<t t-esc="other['date_selected_to']"/>
<br />
</t> </t>
<!-- Display the number of products to show in the report -->
<t t-if="other['limit']"> <t t-if="other['limit']">
<b>Product Range :</b> <t t-esc="other['limit']"/> Products<br /> <b>Product Range :</b>
<t t-esc="other['limit']"/> Products
<br />
</t> </t>
</span> </span>
</div> </div>
<br /> <br />
<!-- Display the table containing the top-selling products data -->
<table class="table table-bordered" style="border: 1px solid #000;"> <table class="table table-bordered" style="border: 1px solid #000;">
<tbody> <tbody>
<tr> <tr>
@ -35,33 +52,42 @@
<th style="text-align: center;color: #000;text-color: #000;">Sold Quantity</th> <th style="text-align: center;color: #000;text-color: #000;">Sold Quantity</th>
<th style="text-align: center;color: #000;text-color: #000;">UoM</th> <th style="text-align: center;color: #000;text-color: #000;">UoM</th>
</tr> </tr>
<!-- Loop through the data to display product information -->
<tr t-foreach="data" t-as="value"> <tr t-foreach="data" t-as="value">
<td style="height:5px;color: #000;text-color: #000"><t t-esc="value['product_name']"/></td> <td style="height:5px;color: #000;text-color: #000">
<td style="height:5px;text-align: center;color: #000;text-color: #000;"><t t-esc="value['sum']"/></td> <t t-esc="value['product_name']"/>
<td style="height:5x;text-align: center;color: #000;text-color: #000;"><t t-esc="value['name']"/></td> </td>
<td style="height:5px;text-align: center;color: #000;text-color: #000;">
<t t-esc="value['sold_quantity']"/>
</td>
<td style="height:5x;text-align: center;color: #000;text-color: #000;">
<t t-esc="value['uom']"/>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</t> </t>
</t> </t>
</template> </template>
<!-- Template for the Internal Layout of the Report -->
<template id="internal_layout"> <template id="internal_layout">
<t t-if="not o and doc"> <t t-if="not o and doc">
<t t-set="o" t-value="doc"/> <t t-set="o" t-value="doc"/></t>
</t> <!-- Set the company variable based on the document's company_id if available -->
<t t-if="o and 'company_id' in o"> <t t-if="o and 'company_id' in o">
<t t-set="company" t-value="o.company_id.sudo()"/> <t t-set="company" t-value="o.company_id.sudo()"/></t>
</t> <!-- If company_id is not available, use the default company from "res_company" -->
<t t-if="not o or not 'company_id' in o"> <t t-if="not o or not 'company_id' in o">
<t t-set="company" t-value="res_company"/> <t t-set="company" t-value="res_company"/></t>
</t> <!-- Header section of the report layout -->
<div class="header o_boxed_header"> <div class="header o_boxed_header">
<div class="row mb8"> <div class="row mb8">
<div class="col-xs-6"> <div class="col-xs-6">
<!-- Display the company logo if available -->
<img t-if="company.logo" t-att-src="image_data_uri(company.logo)" alt="Logo"/> <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" alt="Logo"/>
</div> </div>
<div class="col-xs-6 text-right mb4"> <div class="col-xs-6 text-right mb4">
<!-- Display the company name and address -->
<h4 class="mt0" t-field="company.report_header"/> <h4 class="mt0" t-field="company.report_header"/>
<div name="company_address" class="mb4"> <div name="company_address" class="mb4">
<span style="color: #000;font-color:#000000;" class="company_address" t-field="company.partner_id" <span style="color: #000;font-color:#000000;" class="company_address" t-field="company.partner_id"
@ -69,27 +95,39 @@
</div> </div>
</div> </div>
</div> </div>
<div style="border-bottom: 1px solid black;"/> <div style="border-bottom: 1px solid black;"/></div>
</div>
<div class="article o_report_layout_background"> <div class="article o_report_layout_background">
<t t-raw="0" /> <t t-raw="0" />
</div> </div>
<div class="footer"> <div class="footer">
<div class="text-center" style="border-top: 1px solid black;"> <div class="text-center" style="border-top: 1px solid black;">
<ul class="list-inline mb4"> <ul class="list-inline mb4">
<li t-if="company.phone">Phone: <span t-field="company.phone"/></li> <!-- Display company contact information -->
<li t-if="company.email">Email: <span t-field="company.email"/></li> <li t-if="company.phone">Phone:
<li t-if="company.website">Web: <span t-field="company.website"/></li> <span t-field="company.phone"/>
<li t-if="company.vat"><t t-esc="company.country_id.vat_label or 'TIN'"/>: <span t-field="company.vat"/></li> </li>
<li t-if="company.email">Email:
<span t-field="company.email"/>
</li>
<li t-if="company.website">Web:
<span t-field="company.website"/>
</li>
<li t-if="company.vat">
<t t-esc="company.country_id.vat_label or 'TIN'"/>:
<span t-field="company.vat"/>
</li>
</ul> </ul>
<div name="financial_infos"> <div name="financial_infos">
<!-- Display additional financial information if available -->
<span t-field="company.report_footer"/> <span t-field="company.report_footer"/>
</div> </div>
<div class="text-muted"> <div class="text-muted">
Page: <span class="page"/> / <span class="topage"/> <!-- Display the current page and total pages of the report -->
Page:
<span class="page"/> /
<span class="topage"/>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
</odoo> </odoo>

1
top_selling_product_report/security/ir.model.access.csv

@ -1,3 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_top_selling_user,access_top_selling_user_id,model_top_selling,sales_team.group_sale_manager,1,1,1,1 access_top_selling_user,access_top_selling_user_id,model_top_selling,sales_team.group_sale_manager,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_top_selling_user access_top_selling_user_id model_top_selling sales_team.group_sale_manager 1 1 1 1

43
top_selling_product_report/wizard/top_selling_wizard.py

@ -23,24 +23,34 @@ from odoo import fields, models
class TopSellingWizard(models.TransientModel): class TopSellingWizard(models.TransientModel):
"""This model serves as a wizard that collects various parameters from
the user to filter the report data."""
_name = 'top.selling' _name = 'top.selling'
_description = 'Top selling Products' _description = 'Top selling Products'
from_date = fields.Date(string='From') from_date = fields.Date(string='From', help="From date")
to_date = fields.Date(string='To') to_date = fields.Date(string='To', help="To date")
date = fields.Selection([('days', 'Last 10 Days'), ('curr_month', 'Current Month'), ('last_month', 'Last Month'), date = fields.Selection(
[('days', 'Last 10 Days'), ('curr_month', 'Current Month'),
('last_month', 'Last Month'),
('curr_year', 'Current Year'), ('last_year', 'Last Year'), ('curr_year', 'Current Year'), ('last_year', 'Last Year'),
('select_period', 'Select Period')], ('select_period', 'Select Period')], help="Choose date range",
string="Top Selling product of", default='days') string="Top Selling product of", default='days')
period = fields.Char(string="Products Range", help="Enter number of products in report.") period = fields.Char(string="Products Range",
least = fields.Boolean(string="Least Selling Product", default=False) help="Enter number of products in report.")
company = fields.Many2many('res.company', default=lambda self: self.env.user.company_id, string="Company") least = fields.Boolean(string="Least Selling Product", default=False,
warehouse = fields.Many2many('stock.warehouse', string="Warehouse") help="Enable to print least selling product report")
company = fields.Many2many('res.company',
default=lambda self: self.env.user.company_id,
string="Company", help="company")
warehouse = fields.Many2many('stock.warehouse', string="Warehouse",
help="Choose warehouse")
def print_report(self): def print_report(self):
"""Generate and print the "Top Selling Products" report based on the
selected parameters."""
company_id = [] company_id = []
warehouse_id = [] warehouse_id = []
if self.company: if self.company:
for val in self.company: for val in self.company:
company_id.append(val.id) company_id.append(val.id)
@ -52,12 +62,11 @@ class TopSellingWizard(models.TransientModel):
if self.warehouse: if self.warehouse:
for val in self.warehouse: for val in self.warehouse:
warehouse_id.append(val.id) warehouse_id.append(val.id)
else:
warehouse = self.env['stock.warehouse'].search([])
for val in warehouse:
warehouse_id.append(val.id)
data = {'date': self.date, 'period': self.period, 'least': self.least, 'from_date': self.from_date,
'to_date': self.to_date, 'company': company_id, 'warehouse': warehouse_id}
return self.env.ref('top_selling_product_report.top_selling_pdf').report_action(self, data=data) data = {'date': self.date, 'period': self.period, 'least': self.least,
'from_date': self.from_date,
'to_date': self.to_date, 'company': company_id,
'warehouse': warehouse_id}
return self.env.ref(
'top_selling_product_report.top_selling_pdf').report_action(self,
data=data)

12
top_selling_product_report/wizard/top_selling_wizard.xml

@ -26,7 +26,6 @@
<group> <group>
<field name="least"/> <field name="least"/>
</group> </group>
<footer> <footer>
<button name="print_report" type="object" string="Print" class="oe_highlight"/> <button name="print_report" type="object" string="Print" class="oe_highlight"/>
<button string="Cancel" class="btn btn-default" special="cancel"/> <button string="Cancel" class="btn btn-default" special="cancel"/>
@ -34,18 +33,21 @@
</form> </form>
</field> </field>
</record> </record>
<record id="top_selling_wizard" model="ir.actions.act_window"> <record id="top_selling_wizard" model="ir.actions.act_window">
<field name="name">Top/Least Selling Products</field> <field name="name">Top/Least Selling Products</field>
<field name="res_model">top.selling</field> <field name="res_model">top.selling</field>
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="target">new</field> <field name="target">new</field>
</record> </record>
<menuitem id="sale_report_menu"
name="Sales"
parent="sale.menu_sale_report"
action="sale.action_order_report_all"
groups="sales_team.group_sale_manager"
sequence="0"/>
<menuitem id="top_selling_report" <menuitem id="top_selling_report"
name="Top/Least Selling Products" name="Top/Least Selling Products"
parent="sale.menu_sale_report" parent="sale.menu_sale_report"
action="top_selling_wizard" action="top_selling_wizard"
groups="sales_team.group_sale_manager" groups="sales_team.group_sale_manager"/>
/>
</odoo> </odoo>
Loading…
Cancel
Save