diff --git a/top_selling_product_report/README.rst b/top_selling_product_report/README.rst index 248ac74da..01b76c056 100644 --- a/top_selling_product_report/README.rst +++ b/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 Installation @@ -11,6 +15,15 @@ Configuration ============= No additional configurations needed +Company +------- +* `Cybrosys Techno Solutions `__ + +License +------- +Gnu Affero General Public License, Version 3 (AGPL v3). +(https://www.gnu.org/licenses/agpl-3.0-standalone.html) + Credits ======= Developer: Ajmal JK @ cybrosys, Contact: odoo@cybrosys.com @@ -19,3 +32,24 @@ V14 : Sayooj A O V15 : Irfan @ 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 `__ + +Further information +=================== +HTML Description: ``__ diff --git a/top_selling_product_report/__init__.py b/top_selling_product_report/__init__.py index 0dcfd8b2b..e33fdbf6e 100644 --- a/top_selling_product_report/__init__.py +++ b/top_selling_product_report/__init__.py @@ -19,5 +19,5 @@ # If not, see . # ############################################################################# -from . import wizard from . import report +from . import wizard diff --git a/top_selling_product_report/__manifest__.py b/top_selling_product_report/__manifest__.py index 37eb5a4e2..c5d80380e 100644 --- a/top_selling_product_report/__manifest__.py +++ b/top_selling_product_report/__manifest__.py @@ -21,19 +21,20 @@ ############################################################################# { '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', - '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', - 'maintainer': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', 'website': 'https://www.cybrosys.com', 'depends': ['base', 'sale_management', 'stock', 'sale'], - 'category': 'Sale', - 'data': ['wizard/top_selling_wizard.xml', + 'data': ['security/ir.model.access.csv', 'report/top_selling_report.xml', 'report/top_selling_report_template.xml', - 'security/ir.model.access.csv' + 'wizard/top_selling_wizard.xml', ], 'images': ['static/description/banner.png'], 'license': 'AGPL-3', diff --git a/top_selling_product_report/doc/RELEASE_NOTES.md b/top_selling_product_report/doc/RELEASE_NOTES.md index 4b36b2ef3..daaf09d44 100644 --- a/top_selling_product_report/doc/RELEASE_NOTES.md +++ b/top_selling_product_report/doc/RELEASE_NOTES.md @@ -4,3 +4,8 @@ #### Version 16.0.1.0.0 ##### ADD - 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. diff --git a/top_selling_product_report/report/__init__.py b/top_selling_product_report/report/__init__.py index 36289655c..809d8fce0 100644 --- a/top_selling_product_report/report/__init__.py +++ b/top_selling_product_report/report/__init__.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2022-TODAY Cybrosys Technologies(). +# Copyright (C) 2022-TODAY Cybrosys Technologies() # Author:Cybrosys Techno Solutions(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO diff --git a/top_selling_product_report/report/top_selling_report.py b/top_selling_product_report/report/top_selling_report.py index 5b3acbe2b..c6e0fa785 100644 --- a/top_selling_product_report/report/top_selling_report.py +++ b/top_selling_product_report/report/top_selling_report.py @@ -19,100 +19,112 @@ # If not, see . # ############################################################################# -from datetime import timedelta, date - import dateutil.relativedelta from dateutil.relativedelta import relativedelta - +from datetime import timedelta, date from odoo import models 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" _description = "Top selling products report" 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_selected_from = None date_selected = None date_selected_to = None other_details = {} - company_id = data['company'] 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) if date_option == 'days': - - from_date = date.today() - dateutil.relativedelta.relativedelta(days=11) - to_date = date.today() + dateutil.relativedelta.relativedelta(days=1) + from_date = date.today() - dateutil.relativedelta.relativedelta( + days=11) + to_date = date.today() + dateutil.relativedelta.relativedelta( + days=1) date_selected = "Last 10 Days" elif date_option == 'last_month': - - date_limit = date.today() - dateutil.relativedelta.relativedelta(months=1) + date_limit = date.today() - dateutil.relativedelta.relativedelta( + months=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" elif date_option == 'curr_month': - 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" elif date_option == 'last_year': - - date_limit = date.today() - dateutil.relativedelta.relativedelta(years=1) + date_limit = date.today() - dateutil.relativedelta.relativedelta( + years=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" elif date_option == 'curr_year': - - date_limit = date.today() - dateutil.relativedelta.relativedelta(years=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" elif date_option == 'select_period': - from_date = data['from_date'] to_date = data['to_date'] date_selected_from = from_date date_selected_to = to_date other_details.update({ - 'limit': limit_value, 'least': data['least'], 'range': date_selected, 'date_selected_from': date_selected_from, 'date_selected_to': date_selected_to, }) - - cr = self._cr - order = 'asc' if data['least'] else 'desc' - company_id = str(tuple(company_id)) if len(company_id) > 1 else "(" + str(company_id[0]) + ")" - warehouse_id = str(tuple(warehouse_id)) if len(warehouse_id) > 1 else "(" + str(warehouse_id[0]) + ")" - limit_clause = " limit'%s'" % limit_value if limit_value else "" - - 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 - JOIN uom_uom pu on sl.product_uom = pu.id - where so.date_order::DATE >= '%s'::DATE and - so.date_order::DATE <= '%s'::DATE and - sl.state = 'sale' and so.company_id in %s - and so.warehouse_id in %s - group by sl.name,pu.name order by sum %s""" % ( - from_date, to_date, company_id, warehouse_id, order)) + limit_clause - cr.execute(query) - dat = cr.dictfetchall() - + sale_report_model = self.env['sale.report'] + states = sale_report_model._get_done_states() + data_domain = [('state', 'in', states), ('date', '>=', from_date), + ('date', '<=', to_date), + ('company_id', 'in', company_id)] + if warehouse_id: + data_domain.append(('warehouse_id', 'in', warehouse_id)) + + sale_data = sale_report_model.search(data_domain) + product_dict = {} + for record in sale_data: + product_name = record.product_id.display_name + if product_name in product_dict: + product_dict[product_name][ + 'sold_quantity'] += record.product_uom_qty + else: + product_dict[product_name] = { + '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 { - 'data': dat, + 'data': limit_products, 'other': other_details, } diff --git a/top_selling_product_report/report/top_selling_report.xml b/top_selling_product_report/report/top_selling_report.xml index 066d7c3d0..5efadc188 100644 --- a/top_selling_product_report/report/top_selling_report.xml +++ b/top_selling_product_report/report/top_selling_report.xml @@ -1,5 +1,6 @@ + Top Selling Product Report top.selling diff --git a/top_selling_product_report/report/top_selling_report_template.xml b/top_selling_product_report/report/top_selling_report_template.xml index 144385143..4c96a323d 100644 --- a/top_selling_product_report/report/top_selling_report_template.xml +++ b/top_selling_product_report/report/top_selling_report_template.xml @@ -1,95 +1,133 @@ - - + diff --git a/top_selling_product_report/security/ir.model.access.csv b/top_selling_product_report/security/ir.model.access.csv index a4c6a4946..d6884f481 100644 --- a/top_selling_product_report/security/ir.model.access.csv +++ b/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 access_top_selling_user,access_top_selling_user_id,model_top_selling,sales_team.group_sale_manager,1,1,1,1 - diff --git a/top_selling_product_report/wizard/top_selling_wizard.py b/top_selling_product_report/wizard/top_selling_wizard.py index fe731547e..eb7985ed1 100644 --- a/top_selling_product_report/wizard/top_selling_wizard.py +++ b/top_selling_product_report/wizard/top_selling_wizard.py @@ -23,24 +23,34 @@ from odoo import fields, models 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' _description = 'Top selling Products' - from_date = fields.Date(string='From') - to_date = fields.Date(string='To') - date = fields.Selection([('days', 'Last 10 Days'), ('curr_month', 'Current Month'), ('last_month', 'Last Month'), - ('curr_year', 'Current Year'), ('last_year', 'Last Year'), - ('select_period', 'Select Period')], - string="Top Selling product of", default='days') - period = fields.Char(string="Products Range", help="Enter number of products in report.") - least = fields.Boolean(string="Least Selling Product", default=False) - company = fields.Many2many('res.company', default=lambda self: self.env.user.company_id, string="Company") - warehouse = fields.Many2many('stock.warehouse', string="Warehouse") + from_date = fields.Date(string='From', help="From date") + to_date = fields.Date(string='To', help="To date") + date = fields.Selection( + [('days', 'Last 10 Days'), ('curr_month', 'Current Month'), + ('last_month', 'Last Month'), + ('curr_year', 'Current Year'), ('last_year', 'Last Year'), + ('select_period', 'Select Period')], help="Choose date range", + string="Top Selling product of", default='days') + period = fields.Char(string="Products Range", + help="Enter number of products in report.") + least = fields.Boolean(string="Least Selling Product", default=False, + 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): + """Generate and print the "Top Selling Products" report based on the + selected parameters.""" company_id = [] warehouse_id = [] - if self.company: for val in self.company: company_id.append(val.id) @@ -52,12 +62,11 @@ class TopSellingWizard(models.TransientModel): if self.warehouse: for val in self.warehouse: 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) diff --git a/top_selling_product_report/wizard/top_selling_wizard.xml b/top_selling_product_report/wizard/top_selling_wizard.xml index 275e758c7..6a458abb7 100644 --- a/top_selling_product_report/wizard/top_selling_wizard.xml +++ b/top_selling_product_report/wizard/top_selling_wizard.xml @@ -26,7 +26,6 @@ -