diff --git a/sale_report_advanced/README.rst b/sale_report_advanced/README.rst new file mode 100644 index 000000000..26c79986f --- /dev/null +++ b/sale_report_advanced/README.rst @@ -0,0 +1,41 @@ +Advanced Sales Reports +======================= +* Advanced Sales Reports for Odoo 15 + +Installation +============ + - www.odoo.com/documentation/15.0/setup/install.html + - Install our custom addon + +License +------- +General Public License, Version 3 (LGPL v3). +(https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html) + +Company +------- +* 'Cybrosys Techno Solutions `__ + +Credits +------- +* Developer: +Athul @ Cybrosys + +Contacts +-------- +* Mail Contact : odoo@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 +========== +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com + +Further information +=================== +HTML Description: ``__ + diff --git a/sale_report_advanced/__init__.py b/sale_report_advanced/__init__.py new file mode 100644 index 000000000..ee8eaa85d --- /dev/null +++ b/sale_report_advanced/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from . import wizard +from . import controllers diff --git a/sale_report_advanced/__manifest__.py b/sale_report_advanced/__manifest__.py new file mode 100644 index 000000000..98b8b834a --- /dev/null +++ b/sale_report_advanced/__manifest__.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +{ + 'name': 'Advanced Sales Reports', + 'version': '15.0.1.0.0', + 'summary': 'Advanced sales reports for Odoo 15', + 'description': """module helps you to print reports like Sales Analysis, Sales By Category, + Sales Indent, Sales Invoice ,Product Profit ,Hourly Sales in PDF and XLSX format.""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'category': 'Sales', + 'website': 'https://www.cybrosys.com', + 'depends': ['sale_management', 'base','account'], + 'data': [ + 'security/ir.model.access.csv', + 'wizard/sale_report.xml', + 'wizard/sale_invoice.xml', + 'wizard/sale_analysis.xml', + 'wizard/weekly_wise.xml', + 'wizard/sale_category.xml', + 'wizard/sale_indent.xml', + 'views/report_view.xml', + 'report/sale_reports.xml', + 'report/invoice_analysis_template.xml', + 'report/sales_indent_template.xml', + 'report/sale_profit_template.xml', + 'report/sales_category_template.xml', + 'report/sales_analysis_template.xml', + 'report/sales_weekly_template.xml', + ], + 'images': ['static/description/banner.png'], + 'installable': True, + 'application': True, + 'license': 'LGPL-3', + 'assets': { + 'web.assets_backend': [ + 'sale_report_advanced/static/src/js/action_manager.js', + ], + }, +} diff --git a/sale_report_advanced/controllers/__init__.py b/sale_report_advanced/controllers/__init__.py new file mode 100644 index 000000000..507637791 --- /dev/null +++ b/sale_report_advanced/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import profit diff --git a/sale_report_advanced/controllers/profit.py b/sale_report_advanced/controllers/profit.py new file mode 100644 index 000000000..bc53af30a --- /dev/null +++ b/sale_report_advanced/controllers/profit.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + + +import json +from odoo import http +from odoo.http import content_disposition, request +from odoo.addons.web.controllers.main import _serialize_exception +from odoo.tools import html_escape + +class XLSXReportController(http.Controller): + @http.route('/xlsx_reports', type='http', auth='user', methods=['POST'], csrf=False) + def get_report_xlsx(self, model, options, output_format, report_name, **kw): + uid = request.session.uid + options = json.loads(options) + report_obj = request.env[model].sudo(uid) + token = 'dummy-because-api-expects-one' + try: + if output_format == 'xlsx': + response = request.make_response( + None, + headers=[('Content-Type', 'application/vnd.ms-excel'), + ('Content-Disposition', content_disposition(report_name + '.xlsx')) + ] + ) + report_obj.get_xlsx_report(options, response) + response.set_cookie('fileToken', token) + return response + except Exception as e: + se = _serialize_exception(e) + error = { + 'code': 200, + 'message': 'Odoo Server Error', + 'data': se + } + return request.make_response(html_escape(json.dumps(error))) diff --git a/sale_report_advanced/doc/RELEASE_NOTES.md b/sale_report_advanced/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..88707175a --- /dev/null +++ b/sale_report_advanced/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 8.4.2022 +#### Version 15.0.1.0.0 +##### ADD +- Initial Commit for sale_report_advanced diff --git a/sale_report_advanced/report/invoice_analysis_template.xml b/sale_report_advanced/report/invoice_analysis_template.xml new file mode 100644 index 000000000..a321d4663 --- /dev/null +++ b/sale_report_advanced/report/invoice_analysis_template.xml @@ -0,0 +1,95 @@ + + + + \ No newline at end of file diff --git a/sale_report_advanced/report/sale_profit_template.xml b/sale_report_advanced/report/sale_profit_template.xml new file mode 100644 index 000000000..9e8ca02a3 --- /dev/null +++ b/sale_report_advanced/report/sale_profit_template.xml @@ -0,0 +1,345 @@ + + + + \ No newline at end of file diff --git a/sale_report_advanced/report/sale_reports.xml b/sale_report_advanced/report/sale_reports.xml new file mode 100644 index 000000000..a2ea7a0b4 --- /dev/null +++ b/sale_report_advanced/report/sale_reports.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/sale_report_advanced/report/sales_analysis_template.xml b/sale_report_advanced/report/sales_analysis_template.xml new file mode 100644 index 000000000..77d442f42 --- /dev/null +++ b/sale_report_advanced/report/sales_analysis_template.xml @@ -0,0 +1,167 @@ + + + + \ No newline at end of file diff --git a/sale_report_advanced/report/sales_category_template.xml b/sale_report_advanced/report/sales_category_template.xml new file mode 100644 index 000000000..f7719e8a5 --- /dev/null +++ b/sale_report_advanced/report/sales_category_template.xml @@ -0,0 +1,111 @@ + + + + \ No newline at end of file diff --git a/sale_report_advanced/report/sales_indent_template.xml b/sale_report_advanced/report/sales_indent_template.xml new file mode 100644 index 000000000..e1d1e5b75 --- /dev/null +++ b/sale_report_advanced/report/sales_indent_template.xml @@ -0,0 +1,59 @@ + + + + \ No newline at end of file diff --git a/sale_report_advanced/report/sales_weekly_template.xml b/sale_report_advanced/report/sales_weekly_template.xml new file mode 100644 index 000000000..7f22bcafd --- /dev/null +++ b/sale_report_advanced/report/sales_weekly_template.xml @@ -0,0 +1,66 @@ + + + + \ No newline at end of file diff --git a/sale_report_advanced/security/ir.model.access.csv b/sale_report_advanced/security/ir.model.access.csv new file mode 100644 index 000000000..28e71bf3e --- /dev/null +++ b/sale_report_advanced/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sale_report_advance,access.sale.report.advance,model_sale_report_advance,,1,1,1,1 +access_sale_report_invoice,access.sale.report.invoice,model_sale_report_invoice,,1,1,1,1 +access_sale_report_category,access.sale.report.category,model_sale_report_category,,1,1,1,1 +access_sale_report_indent,access.sale.report.indent,model_sale_report_indent,,1,1,1,1 +access_sale_report_analysis,access.sale.report.analysis,model_sale_report_analysis,,1,1,1,1 +access_sale_report_weekly,access.sale.report.weekly,model_sale_report_weekly,,1,1,1,1 diff --git a/sale_report_advanced/static/description/assets/icons/check.png b/sale_report_advanced/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/check.png differ diff --git a/sale_report_advanced/static/description/assets/icons/chevron.png b/sale_report_advanced/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/chevron.png differ diff --git a/sale_report_advanced/static/description/assets/icons/cogs.png b/sale_report_advanced/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/cogs.png differ diff --git a/sale_report_advanced/static/description/assets/icons/consultation.png b/sale_report_advanced/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/consultation.png differ diff --git a/sale_report_advanced/static/description/assets/icons/ecom-black.png b/sale_report_advanced/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/ecom-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/education-black.png b/sale_report_advanced/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/education-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/hotel-black.png b/sale_report_advanced/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/hotel-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/license.png b/sale_report_advanced/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/license.png differ diff --git a/sale_report_advanced/static/description/assets/icons/lifebuoy.png b/sale_report_advanced/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/lifebuoy.png differ diff --git a/sale_report_advanced/static/description/assets/icons/logo.png b/sale_report_advanced/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/logo.png differ diff --git a/sale_report_advanced/static/description/assets/icons/manufacturing-black.png b/sale_report_advanced/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/manufacturing-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/pos-black.png b/sale_report_advanced/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/pos-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/puzzle.png b/sale_report_advanced/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/puzzle.png differ diff --git a/sale_report_advanced/static/description/assets/icons/restaurant-black.png b/sale_report_advanced/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/restaurant-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/service-black.png b/sale_report_advanced/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/service-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/trading-black.png b/sale_report_advanced/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/trading-black.png differ diff --git a/sale_report_advanced/static/description/assets/icons/training.png b/sale_report_advanced/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/training.png differ diff --git a/sale_report_advanced/static/description/assets/icons/update.png b/sale_report_advanced/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/update.png differ diff --git a/sale_report_advanced/static/description/assets/icons/user.png b/sale_report_advanced/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/user.png differ diff --git a/sale_report_advanced/static/description/assets/icons/wrench.png b/sale_report_advanced/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/sale_report_advanced/static/description/assets/icons/wrench.png differ diff --git a/sale_report_advanced/static/description/assets/modules/budget_image.png b/sale_report_advanced/static/description/assets/modules/budget_image.png new file mode 100644 index 000000000..b50130c7d Binary files /dev/null and b/sale_report_advanced/static/description/assets/modules/budget_image.png differ diff --git a/sale_report_advanced/static/description/assets/modules/credit_image.png b/sale_report_advanced/static/description/assets/modules/credit_image.png new file mode 100644 index 000000000..3ad04ecfd Binary files /dev/null and b/sale_report_advanced/static/description/assets/modules/credit_image.png differ diff --git a/sale_report_advanced/static/description/assets/modules/employee_image.png b/sale_report_advanced/static/description/assets/modules/employee_image.png new file mode 100644 index 000000000..30ad58232 Binary files /dev/null and b/sale_report_advanced/static/description/assets/modules/employee_image.png differ diff --git a/sale_report_advanced/static/description/assets/modules/export_image.png b/sale_report_advanced/static/description/assets/modules/export_image.png new file mode 100644 index 000000000..492980ad0 Binary files /dev/null and b/sale_report_advanced/static/description/assets/modules/export_image.png differ diff --git a/sale_report_advanced/static/description/assets/modules/gantt_image.png b/sale_report_advanced/static/description/assets/modules/gantt_image.png new file mode 100644 index 000000000..1ae7cfe3b Binary files /dev/null and b/sale_report_advanced/static/description/assets/modules/gantt_image.png differ diff --git a/sale_report_advanced/static/description/assets/modules/quotation_image.png b/sale_report_advanced/static/description/assets/modules/quotation_image.png new file mode 100644 index 000000000..499b1a72f Binary files /dev/null and b/sale_report_advanced/static/description/assets/modules/quotation_image.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/1.png b/sale_report_advanced/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..12ae68a2f Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/1.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/10.png b/sale_report_advanced/static/description/assets/screenshots/10.png new file mode 100644 index 000000000..bc1370f68 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/10.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/11.png b/sale_report_advanced/static/description/assets/screenshots/11.png new file mode 100644 index 000000000..cb33edb0e Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/11.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/12.png b/sale_report_advanced/static/description/assets/screenshots/12.png new file mode 100644 index 000000000..7bf94ce05 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/12.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/13.png b/sale_report_advanced/static/description/assets/screenshots/13.png new file mode 100644 index 000000000..2a9a364b2 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/13.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/14.png b/sale_report_advanced/static/description/assets/screenshots/14.png new file mode 100644 index 000000000..a339ec6f6 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/14.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/15.png b/sale_report_advanced/static/description/assets/screenshots/15.png new file mode 100644 index 000000000..33dc11077 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/15.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/16.png b/sale_report_advanced/static/description/assets/screenshots/16.png new file mode 100644 index 000000000..20aa9554a Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/16.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/17.png b/sale_report_advanced/static/description/assets/screenshots/17.png new file mode 100644 index 000000000..a1c152a89 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/17.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/18.png b/sale_report_advanced/static/description/assets/screenshots/18.png new file mode 100644 index 000000000..4f21f77fb Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/18.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/2.png b/sale_report_advanced/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..44f0fbe11 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/2.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/3.png b/sale_report_advanced/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..4e69a7919 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/3.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/4.png b/sale_report_advanced/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..1890ad8be Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/4.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/5.png b/sale_report_advanced/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..a89816f5a Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/5.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/6.png b/sale_report_advanced/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..eec31e637 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/6.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/7.png b/sale_report_advanced/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..90dcc36c9 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/7.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/8.png b/sale_report_advanced/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..30f9962b1 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/8.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/9.png b/sale_report_advanced/static/description/assets/screenshots/9.png new file mode 100644 index 000000000..8b4aa2888 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/9.png differ diff --git a/sale_report_advanced/static/description/assets/screenshots/hero.gif b/sale_report_advanced/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..e088d61c2 Binary files /dev/null and b/sale_report_advanced/static/description/assets/screenshots/hero.gif differ diff --git a/sale_report_advanced/static/description/banner.png b/sale_report_advanced/static/description/banner.png new file mode 100644 index 000000000..1c019bdd8 Binary files /dev/null and b/sale_report_advanced/static/description/banner.png differ diff --git a/sale_report_advanced/static/description/icon.png b/sale_report_advanced/static/description/icon.png new file mode 100644 index 000000000..3c009154c Binary files /dev/null and b/sale_report_advanced/static/description/icon.png differ diff --git a/sale_report_advanced/static/description/images/checked.png b/sale_report_advanced/static/description/images/checked.png new file mode 100644 index 000000000..578cedb80 Binary files /dev/null and b/sale_report_advanced/static/description/images/checked.png differ diff --git a/sale_report_advanced/static/description/images/cybrosys.png b/sale_report_advanced/static/description/images/cybrosys.png new file mode 100644 index 000000000..d76b5bafb Binary files /dev/null and b/sale_report_advanced/static/description/images/cybrosys.png differ diff --git a/sale_report_advanced/static/description/index.html b/sale_report_advanced/static/description/index.html new file mode 100644 index 000000000..b0a1fdee5 --- /dev/null +++ b/sale_report_advanced/static/description/index.html @@ -0,0 +1,707 @@ +
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+ +
+
+
+
+ +
+
+
+

+ Advanced Sales Reports

+

+ +

+ +
+
+ +
+
+

+ Explore this module +

+
+ + + +
+
+

+ Overview +

+
+ +
+

+ The module helps you to print reports like Sales Analysis, Sales By Category, Sales Indent, Sales + Invoice ,Product Profit ,Hourly Sales in PDF and XLSX format. +

+ +
+
+ + +
+
+

+ Features +

+
+ +
+
+ +
+
+

+ Sales Analysis Report

+

+

+
+
+
+
+ +
+
+

+ Sales Category Report

+
+
+ +
+
+ +
+
+

+ Sales Indent Report

+
+
+
+
+ +
+
+

+ Sales Invoice Analysis Report

+
+
+
+
+ +
+
+

+ Product Profit Report

+
+
+
+
+ +
+
+

+ Hourly Sales Report

+
+
+
+
+
+

+ Screenshots +

+
+
+

+ Product Profit Report +

+

+ + PDF report + + XLSX report + +

+
+

+ Sales Invoice Analysis Report +

+

+ + PDF report + + XLSX report + +

+
+

+ Sales Category Report +

+

+ + PDF report + + XLSX report + +

+
+

+ Sales Indent Report +

+

+ + PDF report + + XLSX report + +

+
+

+ Sales Analysis Report +

+

+ + PDF report + + XLSX report + +

+
+

+ Hourly Sales Report +

+

+ + PDF report + + XLSX report + +

+
+ +
+
+

Suggested Products

+
+ + +
+
\ No newline at end of file diff --git a/sale_report_advanced/static/src/js/action_manager.js b/sale_report_advanced/static/src/js/action_manager.js new file mode 100644 index 000000000..65d0360e5 --- /dev/null +++ b/sale_report_advanced/static/src/js/action_manager.js @@ -0,0 +1,22 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { download } from "@web/core/network/download"; +import framework from 'web.framework'; +import session from 'web.session'; + +registry.category("ir.actions.report handlers").add("xlsx", async (action) => { + if (action.report_type === 'xlsx') { + framework.blockUI(); + var def = $.Deferred(); + session.get_file({ + url: '/xlsx_reports', + data: action.data, + success: def.resolve.bind(def), + error: (error) => this.call('crash_manager', 'rpc_error', error), + complete: framework.unblockUI, + }); + return def; + } +}); + diff --git a/sale_report_advanced/views/report_view.xml b/sale_report_advanced/views/report_view.xml new file mode 100644 index 000000000..fe468b7e1 --- /dev/null +++ b/sale_report_advanced/views/report_view.xml @@ -0,0 +1,32 @@ + + + + + + + + \ No newline at end of file diff --git a/sale_report_advanced/wizard/__init__.py b/sale_report_advanced/wizard/__init__.py new file mode 100644 index 000000000..554344ef2 --- /dev/null +++ b/sale_report_advanced/wizard/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from . import sale_report +from . import sale_invoice +from . import sale_category +from . import sale_indent +from . import sale_analysis +from . import weekly_wise \ No newline at end of file diff --git a/sale_report_advanced/wizard/sale_analysis.py b/sale_report_advanced/wizard/sale_analysis.py new file mode 100644 index 000000000..f6f7b949e --- /dev/null +++ b/sale_report_advanced/wizard/sale_analysis.py @@ -0,0 +1,367 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +import json +import io +from xlsxwriter import workbook + +from odoo.tools import date_utils +from odoo import fields, models +from odoo.exceptions import UserError, ValidationError + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class SaleReportAdvance(models.TransientModel): + _name = "sale.report.analysis" + + customer_ids = fields.Many2many('res.partner', string="Customers", required=True) + product_ids = fields.Many2many('product.product', string='Products') + from_date = fields.Date(string="Start Date") + to_date = fields.Date(string="End Date") + status = fields.Selection( + [('all', 'All'), ('draft', 'Draft'), ('sent', 'Quotation Sent'), ('sale', 'Sale Order'), ('done', 'Locked')], + string='Status', default='all', reqired=True) + print_type = fields.Selection( + [('sale', 'Sale Order'), ('product', 'Products')], + string='Print By', default='sale', reqired=True) + today_date = fields.Date(default=fields.Date.today()) + + def get_analysis_report(self): + datas = self._get_data() + return self.env.ref('sale_report_advanced.action_sales_analysis').report_action([], data=datas) + + def _get_data(self): + + result = [] + if self.print_type == 'sale': + if not self.status == 'all': + sale_order = self.env['sale.order'].sudo().search([('state', '=', self.status),('state','!=','cancel')]) + filtered = self._get_filtered(sale_order) + + else: + sale_order = self.env['sale.order'].search([('state','!=','cancel')]) + filtered = self._get_filtered(sale_order) + + for rec in filtered: + paid = self._get_total_paid_amount(rec.invoice_ids) + res = { + 'so': rec.name, + 'date': rec.date_order, + 'sales_person': rec.user_id.name, + 's_amt': rec.amount_total, + 'p_amt': paid, + 'balance': rec.amount_total - paid, + 'partner_id': rec.partner_id, + } + result.append(res) + else: + if not self.status == 'all': + sale_order_line = self.env['sale.order.line'].search([('order_id.state', '=', self.status),('order_id.state','!=','cancel')]) + filtered = self._get_filtered_order_line(sale_order_line) + + else: + sale_order_line = self.env['sale.order.line'].search([('order_id.state','!=','cancel')]) + filtered = self._get_filtered_order_line(sale_order_line) + + for rec in filtered: + res = { + 'so': rec.order_id.name, + 'date': rec.order_id.date_order, + 'product_id': rec.product_id.name, + 'price': rec.product_id.list_price, + 'quantity': rec.product_uom_qty, + 'discount': rec.discount, + 'tax': rec.product_id.taxes_id.amount, + 'total': rec.price_subtotal, + 'partner_id': rec.order_id.partner_id, + } + result.append(res) + datas = { + 'ids': self, + 'model': 'sale.report.analysis', + 'form': result, + 'partner_id': self._get_customers(), + 'start_date': self.from_date, + 'end_date': self.to_date, + 'type': self.print_type + + } + return datas + + def _get_total_paid_amount(self, invoices): + total = 0 + for inv in invoices: + if inv.payment_state == 'paid': + total += inv.amount_total + return total + + def _get_filtered_order_line(self, sale_order_line): + if self.from_date and self.to_date: + filtered = list(filter(lambda + x: x.order_id.date_order.date() >= self.from_date and x.order_id.date_order.date() <= self.to_date and x.order_id.partner_id in self.customer_ids and x.product_id in self.product_ids, + sale_order_line)) + elif not self.from_date and self.to_date: + filtered = list(filter(lambda + x: x.order_id.date_order.date() <= self.to_date and x.order_id.partner_id in self.customer_ids and x.product_id in self.product_ids, + sale_order_line)) + elif self.from_date and not self.to_date: + filtered = list(filter(lambda + x: x.order_id.date_order.date() >= self.from_date and x.order_id.partner_id in self.customer_ids and x.product_id in self.product_ids, + sale_order_line)) + else: + filtered = list(filter(lambda + x: x.order_id.partner_id in self.customer_ids and x.product_id in self.product_ids, + sale_order_line)) + return filtered + + def _get_filtered(self, sale_order): + + if self.from_date and self.to_date: + filtered = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.date_order.date() <= self.to_date and x.partner_id in self.customer_ids, + sale_order)) + elif not self.from_date and self.to_date: + filtered = list(filter(lambda + x: x.date_order.date() <= self.to_date and x.partner_id in self.customer_ids, + sale_order)) + elif self.from_date and not self.to_date: + filtered = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.partner_id in self.customer_ids, + sale_order)) + else: + filtered = list(filter(lambda + x: x.partner_id in self.customer_ids, + sale_order)) + return filtered + + def _get_customers(self): + customers = [] + for rec in self.customer_ids: + a = { + 'id': rec, + 'name': rec.name + } + customers.append(a) + return customers + + def get_excel_analysis_report(self): + datas = self._get_data() + return { + 'type': 'ir.actions.report', + 'report_type': 'xlsx', + 'data': {'model': 'sale.report.analysis', + 'output_format': 'xlsx', + 'options': json.dumps(datas, default=date_utils.json_default), + 'report_name': 'Excel Report Name', + }, + } + + def get_xlsx_report(self, data, response): + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + record = [] + cell_format = workbook.add_format({'font_size': '12px', }) + head = workbook.add_format({'align': 'center', 'bold': True, 'font_size': '20px'}) + txt = workbook.add_format({'font_size': '10px', 'align': 'center'}) + + if data['type'] == 'sale': + sheet.merge_range('G2:L3', 'Sales Analysis Report', head) + if data['start_date'] and data['end_date']: + sheet.write('G6', 'From:', cell_format) + sheet.merge_range('H6:I6', data['start_date'], txt) + sheet.write('J6', 'To:', cell_format) + sheet.merge_range('K6:L6', data['end_date'], txt) + h_col = 9 + else: + sheet.merge_range('G2:N3', 'Sales Analysis Report', head) + if data['start_date'] and data['end_date']: + sheet.write('G6', 'From:', cell_format) + sheet.merge_range('H6:I6', data['start_date'], txt) + sheet.write('K6', 'To:', cell_format) + sheet.merge_range('L6:N6', data['end_date'], txt) + h_col = 10 + + format1 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bg_color': '#f5f9ff', 'border': 1}) + format2 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, + 'bg_color': '#6BA6FE', 'border': 1}) + format3 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, 'bg_color': '#95ff63', 'border': 1}) + format4 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True}) + if data['partner_id']: + record = data['partner_id'] + h_row = 7 + count = 0 + row = 5 + row_number = 6 + t_row = 6 + for rec in record: + if data['type'] == 'sale': + sheet.merge_range(h_row, h_col - 3, h_row, h_col + 2, rec['name'], format1) + row = row + count + 3 + col = 6 + sheet.write(row, col, 'Order', format2) + col += 1 + sheet.write(row, col, 'Date', format2) + sheet.set_column('H:H', 17) + col += 1 + sheet.write(row, col, 'Sales Person', format2) + sheet.set_column('I:I', 15) + col += 1 + sheet.write(row, col, 'Sales Amount', format2) + sheet.set_column('J:J', 13) + col += 1 + sheet.write(row, col, 'Amount Paid', format2) + sheet.set_column('K:K', 12) + col += 1 + sheet.write(row, col, 'Balance', format2) + sheet.set_column('L:L', 10) + # col = 6 + count = 0 + row_number = row_number + count + 3 + t_samt = 0 + t_pamt = 0 + t_bal = 0 + t_col = 8 + for val in data['form']: + if val['partner_id'] == rec['id']: + count += 1 + column_number = 6 + sheet.write(row_number, column_number, val['so'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column('H:H', 17) + column_number += 1 + sheet.write(row_number, column_number, val['sales_person'], format1) + sheet.set_column('I:I', 15) + column_number += 1 + sheet.write(row_number, column_number, val['s_amt'], format1) + sheet.set_column('J:J', 13) + t_samt += val['s_amt'] + column_number += 1 + sheet.write(row_number, column_number, val['p_amt'], format1) + sheet.set_column('K:K', 12) + t_pamt += val['p_amt'] + column_number += 1 + sheet.write(row_number, column_number, val['balance'], format1) + sheet.set_column('L:L', 10) + t_bal += val['balance'] + column_number += 1 + row_number += 1 + t_row = t_row + count + 3 + sheet.write(t_row, t_col, 'Total', format4) + t_col += 1 + sheet.write(t_row, t_col, t_samt, format4) + t_col += 1 + sheet.write(t_row, t_col, t_pamt, format4) + t_col += 1 + sheet.write(t_row, t_col, t_bal, format4) + h_row = h_row + count + 3 + + if data['type'] == 'product': + sheet.merge_range(h_row, h_col - 4, h_row, h_col + 3, rec['name'], format1) + row = row + count + 3 + col = 6 + sheet.write(row, col, 'Order', format2) + col += 1 + sheet.write(row, col, 'Date', format2) + sheet.set_column('H:H', 17) + col += 1 + sheet.write(row, col, 'Product', format2) + sheet.set_column('I:I', 17) + col += 1 + sheet.write(row, col, 'Quantity', format2) + sheet.set_column('J:J', 7) + col += 1 + sheet.write(row, col, 'Price', format2) + sheet.set_column('K:K', 12) + col += 1 + sheet.write(row, col, 'Discount(%)', format2) + sheet.set_column('L:L', 12) + col += 1 + sheet.write(row, col, 'Tax(%)', format2) + sheet.set_column('M:M', 10) + col += 1 + sheet.write(row, col, 'Subtotal', format2) + sheet.set_column('N:N', 10) + col += 1 + count = 0 + row_number = row_number + count + 3 + t_qty = 0 + t_price = 0 + t_tax = 0 + t_total = 0 + t_col = 8 + for val in data['form']: + if val['partner_id'] == rec['id']: + count += 1 + column_number = 6 + sheet.write(row_number, column_number, val['so'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column('H:H', 17) + column_number += 1 + sheet.write(row_number, column_number, val['product_id'], format1) + sheet.set_column('I:I', 17) + column_number += 1 + sheet.write(row_number, column_number, val['quantity'], format1) + sheet.set_column('J:J', 7) + t_qty += val['quantity'] + column_number += 1 + sheet.write(row_number, column_number, val['price'], format1) + sheet.set_column('K:K', 12) + t_price += val['price'] + column_number += 1 + sheet.write(row_number, column_number, val['discount'], format1) + sheet.set_column('L:L', 12) + column_number += 1 + sheet.write(row_number, column_number, val['tax'], format1) + sheet.set_column('M:M', 10) + t_tax += val['tax'] + column_number += 1 + sheet.write(row_number, column_number, val['total'], format1) + sheet.set_column('N:N', 10) + t_total += val['total'] + column_number += 1 + row_number += 1 + t_row = t_row + count + 3 + sheet.write(t_row, t_col, 'Total', format4) + t_col += 1 + sheet.write(t_row, t_col, t_qty, format4) + t_col += 1 + sheet.write(t_row, t_col, t_price, format4) + t_col += 2 + sheet.write(t_row, t_col, t_tax, format4) + t_col += 1 + sheet.write(t_row, t_col, t_total, format4) + h_row = h_row + count + 3 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() diff --git a/sale_report_advanced/wizard/sale_analysis.xml b/sale_report_advanced/wizard/sale_analysis.xml new file mode 100644 index 000000000..23678697b --- /dev/null +++ b/sale_report_advanced/wizard/sale_analysis.xml @@ -0,0 +1,39 @@ + + + + Sales Analysis report + sale.report.analysis + +
+ + + + + + + + + + + + + + +
+
+
+
+
+ + Sales Analysis Report + ir.actions.act_window + sale.report.analysis + form + + new + +
\ No newline at end of file diff --git a/sale_report_advanced/wizard/sale_category.py b/sale_report_advanced/wizard/sale_category.py new file mode 100644 index 000000000..2c689252c --- /dev/null +++ b/sale_report_advanced/wizard/sale_category.py @@ -0,0 +1,260 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +import json +import io +from xlsxwriter import workbook + +from odoo.tools import date_utils +from odoo import fields, models +from odoo.exceptions import UserError, ValidationError + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class SaleReportAdvance(models.TransientModel): + _name = "sale.report.category" + + category_ids = fields.Many2many('product.category', string="Categories",required=True) + from_date = fields.Date(string="Start Date") + to_date = fields.Date(string="End Date") + company_ids = fields.Many2many('res.company', string='Companies') + today_date = fields.Date(default=fields.Date.today()) + + def get_category_report(self): + datas = self._get_data() + return self.env.ref('sale_report_advanced.action_sale_category').report_action([], data=datas) + + def _get_data(self): + sale_order_line = self.env['sale.order.line'].search([('order_id.state','!=','cancel')]) + if self.from_date and self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: self.from_date >= x.order_id.date_order.date() <= self.to_date and x.order_id.company_id in self.company_ids, + sale_order_line)) + category = self._get_category() + res = self._get_category_wise(order_lines, category) + + elif not self.from_date and self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() <= self.to_date and x.order_id.company_id in self.company_ids, + sale_order_line)) + category = self._get_category() + res = self._get_category_wise(order_lines, category) + elif self.from_date and not self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: self.from_date >= x.order_id.date_order.date() and x.order_id.company_id in self.company_ids, + sale_order_line)) + category = self._get_category() + res = self._get_category_wise(order_lines, category) + elif self.from_date and self.to_date and not self.company_ids: + order_lines = list(filter(lambda + x: self.from_date >= x.order_id.date_order.date() <= self.to_date, + sale_order_line)) + category = self._get_category() + res = self._get_category_wise(order_lines, category) + + elif not self.from_date and not self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.company_id in self.company_ids, + sale_order_line)) + category = self._get_category() + res = self._get_category_wise(order_lines, category) + elif not self.from_date and self.to_date and not self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() <= self.to_date, + sale_order_line)) + category = self._get_category() + res = self._get_category_wise(order_lines, category) + elif self.from_date and not self.to_date and not self.company_ids: + order_lines = list(filter(lambda + x: self.from_date >= x.order_id.date_order.date(), + sale_order_line)) + category = self._get_category() + res = self._get_category_wise(order_lines, category) + else: + category = self._get_category() + res = self._get_category_wise(sale_order_line, category) + + datas = { + 'ids': self, + 'model': 'sale.report.category', + 'form': res, + 'categ_id': category, + 'start_date': self.from_date, + 'end_date': self.to_date, + + } + return datas + + def _get_category_wise(self, order_lines, category): + result = [] + for cat in category: + for lines in order_lines: + if cat['id'] == lines.product_id.categ_id: + total = lines.product_id.taxes_id.amount +lines.price_subtotal + res = { + 'so': lines.order_id.name, + 'date': lines.order_id.date_order, + 'product_id': lines.product_id.name, + 'quantity': lines.product_uom_qty, + 'tax': lines.product_id.taxes_id.amount, + 'uom':lines.product_id.uom_id.name, + 'price': lines.product_id.list_price, + 'subtotal': lines.price_subtotal, + 'total': total, + 'category_id': lines.product_id.categ_id, + } + result.append(res) + return result + + def _get_category(self): + category = [] + for rec in self.category_ids: + a = { + 'id': rec, + 'name': rec.complete_name + } + category.append(a) + return category + + def get_excel_category_report(self): + datas = self._get_data() + return { + 'type': 'ir.actions.report', + 'report_type': 'xlsx', + 'data': {'model': 'sale.report.category', + 'output_format': 'xlsx', + 'options': json.dumps(datas, default=date_utils.json_default), + 'report_name': 'Excel Report Name', + }, + } + def get_xlsx_report(self, data, response): + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + record = [] + cell_format = workbook.add_format({'font_size': '12px', }) + head = workbook.add_format({'align': 'center', 'bold': True, 'font_size': '20px'}) + txt = workbook.add_format({'font_size': '10px', 'align': 'center'}) + sheet.merge_range('G2:O3', 'Sales Category Report', head) + if data['start_date'] and data['end_date']: + sheet.write('G6', 'From:', cell_format) + sheet.merge_range('H6:I6', data['start_date'], txt) + sheet.write('M6', 'To:', cell_format) + sheet.merge_range('N6:O6', data['end_date'], txt) + format1 = workbook.add_format( + {'font_size': 10, 'align': 'center','bg_color':'#bbd5fc','border': 1}) + format2 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, + 'bg_color': '#6BA6FE', 'border': 1}) + format3 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True,'border': 1}) + format4 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True,'bg_color':'#c0dbfa'}) + h_row = 7 + h_col = 10 + count = 0 + row = 5 + col = 6 + row_number = 6 + t_row = 6 + if data['categ_id']: + record = data['categ_id'] + for rec in record: + sheet.merge_range(h_row,h_col-4,h_row,h_col+4,rec['name'], format4) + row = row + count + 3 + sheet.write(row, col, 'Order', format2) + col += 1 + sheet.write(row, col, 'Date', format2) + sheet.set_column('H:H',15) + col += 1 + sheet.write(row, col, 'Product', format2) + sheet.set_column('I:I',20) + col += 1 + sheet.write(row, col, 'UOM', format2) + col += 1 + sheet.write(row, col, 'Quantity', format2) + col += 1 + sheet.write(row, col, 'Price', format2) + col += 1 + sheet.write(row, col, 'Tax(%)', format2) + col += 1 + sheet.write(row, col, 'Subtotal', format2) + col += 1 + sheet.write(row, col, 'Total', format2) + col += 1 + col = 6 + count = 0 + row_number = row_number + count + 3 + t_qty = 0 + t_price = 0 + t_subtotal = 0 + t_total = 0 + t_col = 9 + for val in data['form']: + if val['category_id'] == rec['id']: + count += 1 + column_number = 6 + sheet.write(row_number, column_number, val['so'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column('H:H', 15) + column_number += 1 + sheet.write(row_number, column_number, val['product_id'], format1) + sheet.set_column('I:I', 20) + column_number += 1 + sheet.write(row_number, column_number, val['uom'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['quantity'], format1) + t_qty += val['quantity'] + column_number += 1 + sheet.write(row_number, column_number, val['price'], format1) + t_price += val['price'] + column_number += 1 + sheet.write(row_number, column_number, val['tax'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['subtotal'], format1) + t_subtotal += val['subtotal'] + column_number += 1 + sheet.write(row_number, column_number, val['total'], format1) + t_total += val['total'] + column_number += 1 + row_number += 1 + t_row = t_row + count + 3 + sheet.write(t_row, t_col, 'Total', format3) + t_col += 1 + sheet.write(t_row, t_col, t_qty, format3) + t_col += 1 + sheet.write(t_row, t_col, t_price, format3) + t_col += 2 + sheet.write(t_row, t_col, t_subtotal, format3) + t_col += 1 + sheet.write(t_row, t_col, t_total, format3) + t_col += 1 + h_row = h_row + count + 3 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() \ No newline at end of file diff --git a/sale_report_advanced/wizard/sale_category.xml b/sale_report_advanced/wizard/sale_category.xml new file mode 100644 index 000000000..2efb06e02 --- /dev/null +++ b/sale_report_advanced/wizard/sale_category.xml @@ -0,0 +1,31 @@ + + + + Sales Report Category + sale.report.category + +
+ + + + + + +
+
+
+
+
+ + Sales Category Report + ir.actions.act_window + sale.report.category + form + + new + +
\ No newline at end of file diff --git a/sale_report_advanced/wizard/sale_indent.py b/sale_report_advanced/wizard/sale_indent.py new file mode 100644 index 000000000..a9c849499 --- /dev/null +++ b/sale_report_advanced/wizard/sale_indent.py @@ -0,0 +1,230 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +import json +import io +from xlsxwriter import workbook + +from odoo.tools import date_utils +from odoo import fields, models +from odoo.exceptions import UserError, ValidationError + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class SaleReportAdvance(models.TransientModel): + _name = "sale.report.indent" + + customer_ids = fields.Many2many('res.partner', string="Customers", required=True) + category_ids = fields.Many2many('product.category', string="Categories", required=True) + from_date = fields.Date(string="Start Date") + to_date = fields.Date(string="End Date") + status = fields.Selection( + [('all', 'All'), ('draft', 'Draft'), ('sent', 'Quotation Sent'), ('sale', 'Sale Order'), ('done', 'Locked')], + string='Status', default='all', reqired=True) + company_ids = fields.Many2many('res.company', string='Companies') + today_date = fields.Date(default=fields.Date.today()) + + def get_category_report(self): + datas = self._get_data() + return self.env.ref('sale_report_advanced.action_sale_indent').report_action([], data=datas) + + def _get_data(self): + + sale_order_line = self.env['sale.order.line'].search([('order_id.state','!=','cancel')]) + if self.from_date and self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() >= self.from_date and x.order_id.date_order.date() <= self.to_date and x.order_id.company_id in self.company_ids, + sale_order_line)) + res = self._get_orders(order_lines) + + elif not self.from_date and self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() <= self.to_date and x.order_id.company_id in self.company_ids, + sale_order_line)) + res = self._get_orders(order_lines) + elif self.from_date and not self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() >= self.from_date and x.order_id.company_id in self.company_ids, + sale_order_line)) + res = self._get_orders(order_lines) + elif self.from_date and self.to_date and not self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() >= self.from_date and x.order_id.date_order.date()<= self.to_date, + sale_order_line)) + res = self._get_orders(order_lines) + + elif not self.from_date and not self.to_date and self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.company_id in self.company_ids, + sale_order_line)) + res = self._get_orders(order_lines) + elif not self.from_date and self.to_date and not self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() <= self.to_date, + sale_order_line)) + res = self._get_orders(order_lines) + elif self.from_date and not self.to_date and not self.company_ids: + order_lines = list(filter(lambda + x: x.order_id.date_order.date() >= self.from_date, + sale_order_line)) + res = self._get_orders(order_lines) + else: + res = self._get_orders(sale_order_line) + + datas = { + 'ids': self, + 'model': 'sale.report.indent', + 'form': res, + 'categ_id': self._get_category(), + 'partner_id': self._get_customers(), + 'start_date': self.from_date, + 'end_date': self.to_date, + + } + return datas + + def _get_orders(self, sale_order_line): + if self.status == 'all': + + filtered_order = list(filter(lambda + x: x.order_id.partner_id in self.customer_ids and x.product_id.categ_id in self.category_ids, + sale_order_line)) + else: + filtered_order = list(filter(lambda + x: x.order_id.partner_id in self.customer_ids and x.order_id.state in self.status and x.product_id.categ_id in self.category_ids, + sale_order_line)) + return self._get_customer_wise(filtered_order) + + def _get_customer_wise(self, order): + result = [] + for rec in order: + res = { + 'product_id': rec.product_id.name, + 'quantity': rec.product_uom_qty, + 'partner_id': rec.order_id.partner_id, + 'category_id': rec.product_id.categ_id, + } + result.append(res) + return result + + def _get_category(self): + category = [] + for rec in self.category_ids: + a = { + 'id': rec, + 'name': rec.complete_name + } + category.append(a) + return category + + def _get_customers(self): + customers = [] + for rec in self.customer_ids: + a = { + 'id': rec, + 'name': rec.name + } + customers.append(a) + return customers + + def get_excel_category_report(self): + datas = self._get_data() + return { + 'type': 'ir.actions.report', + 'report_type': 'xlsx', + 'data': {'model': 'sale.report.indent', + 'output_format': 'xlsx', + 'options': json.dumps(datas, default=date_utils.json_default), + 'report_name': 'Excel Report Name', + }, + } + + def get_xlsx_report(self, data, response): + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + cell_format = workbook.add_format({'font_size': '12px', }) + head = workbook.add_format({'align': 'center', 'bold': True, 'font_size': '20px'}) + txt = workbook.add_format({'font_size': '10px', 'align': 'center'}) + sheet.merge_range('G2:N3', 'Product Sales Indent Report', head) + if data['start_date'] and data['end_date']: + sheet.write('G6', 'From:', cell_format) + sheet.merge_range('H6:I6', data['start_date'], txt) + sheet.write('L6', 'To:', cell_format) + sheet.merge_range('M6:N6', data['end_date'], txt) + format1 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bg_color': '#f5f9ff', 'border': 1}) + format3 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, 'bg_color': '#6BA6FE', 'border': 1}) + format4 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, 'bg_color': '#b6d0fa', 'border': 1}) + if data['categ_id']: + categ = data['categ_id'] + if data['partner_id']: + partner = data['partner_id'] + h_row = 6 + h_col = 10 + c_row = 6 + row = 7 + row_number = 6 + for rec in partner: + count = 0 + h_row += 1 + sheet.merge_range(h_row, h_col - 1, h_row, h_col, rec['name'], format3) + c_row = c_row + 2 + row += 2 + row_number += 2 + for cat in categ: + count += 2 + c_col = 10 + col = 9 + sheet.merge_range(c_row, c_col - 1, c_row, c_col, cat['name'], format1) + sheet.write(row, col, 'Product', format4) + sheet.set_column('J:J', 17) + col += 1 + sheet.write(row, col, 'Quantity', format4) + sheet.set_column('K:K', 17) + row_number += 2 + c_count = 0 + for val in data['form']: + if val['category_id'] == cat['id'] and val['partner_id'] == rec['id']: + c_count += 1 + count += 1 + column_number = 9 + sheet.write(row_number, column_number, val['product_id'], format1) + sheet.set_column('J:J', 17) + column_number += 1 + sheet.write(row_number, column_number, val['quantity'], format1) + sheet.set_column('K:K', 17) + row_number += 1 + + row = row + c_count + 2 + c_row = c_row + c_count + 2 + h_row = h_row + count + 1 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() diff --git a/sale_report_advanced/wizard/sale_indent.xml b/sale_report_advanced/wizard/sale_indent.xml new file mode 100644 index 000000000..72084bc3d --- /dev/null +++ b/sale_report_advanced/wizard/sale_indent.xml @@ -0,0 +1,37 @@ + + + + Product Sales Indent + sale.report.indent + +
+ + + + + + + + + + + + +
+
+
+
+
+ + Product Sales Indent Report + ir.actions.act_window + sale.report.indent + form + + new + +
\ No newline at end of file diff --git a/sale_report_advanced/wizard/sale_invoice.py b/sale_report_advanced/wizard/sale_invoice.py new file mode 100644 index 000000000..9df4c8746 --- /dev/null +++ b/sale_report_advanced/wizard/sale_invoice.py @@ -0,0 +1,271 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +import json +import io +from xlsxwriter import workbook + +from odoo.tools import date_utils +from odoo import fields, models + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class SaleReportAdvance(models.TransientModel): + _name = "sale.report.invoice" + + customer_ids = fields.Many2many('res.partner', string="Customers",required=True) + from_date = fields.Date(string="Start Date") + to_date = fields.Date(string="End Date") + status = fields.Selection([('open', 'Open'), ('paid', 'Paid'), ('both', 'Both')], + string='Status', default='open', reqired=True) + company_ids = fields.Many2many('res.company', string='Companies') + today_date = fields.Date(default=fields.Date.today()) + + def get_invoice_report(self): + datas = self._get_data() + return self.env.ref('sale_report_advanced.action_invoice_analysis').report_action([], data=datas) + + def _get_data(self): + + sale = self.env['sale.order'].search([('state','!=','cancel')]) + + if self.from_date and self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.date_order.date() <= self.to_date and x.company_id in self.company_ids, + sale)) + elif not self.from_date and self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() <= self.to_date and x.company_id in self.company_ids, + sale)) + elif self.from_date and not self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.company_id in self.company_ids, + sale)) + elif self.from_date and self.to_date and not self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.date_order.date() <= self.to_date, + sale)) + elif not self.from_date and not self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.company_id in self.company_ids, + sale)) + elif not self.from_date and self.to_date and not self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() <= self.to_date, + sale)) + elif self.from_date and not self.to_date and not self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date, + sale)) + else: + sales_order = sale + + result = [] + customers = [] + for rec in self.customer_ids: + a = { + 'id': rec, + 'name': rec.name + } + customers.append(a) + for so in sales_order: + for cust in customers: + if cust['id'] == so['partner_id']: + if so.invoice_ids: + if self.status == 'open': + for inv in so.invoice_ids: + if inv.payment_state != 'paid': + res = { + 'so': so.name, + 'partner_id': so.partner_id, + 'order_date': so.date_order, + 'invoice': inv.name, + 'date': inv.invoice_date, + 'invoiced': inv.amount_total, + 'paid': inv.amount_total-inv.amount_residual, + 'due': inv.amount_residual, + } + result.append(res) + elif self.status == 'paid': + for inv in so.invoice_ids: + if inv.payment_state == 'paid': + res = { + 'so': so.name, + 'partner_id': so.partner_id, + 'order_date': so.date_order, + 'invoice': inv.name, + 'date': inv.invoice_date, + 'invoiced': inv.amount_total, + 'paid': inv.amount_total-inv.amount_residual, + 'due': inv.amount_residual, + } + result.append(res) + else: + for inv in so.invoice_ids: + res = { + 'so': so.name, + 'partner_id': so.partner_id, + 'order_date': so.date_order, + 'invoice': inv.name, + 'date': inv.invoice_date, + 'invoiced': inv.amount_total, + 'paid': inv.amount_total-inv.amount_residual, + 'due': inv.amount_residual, + } + result.append(res) + datas = { + 'ids': self, + 'model': 'sale.report.invoice', + 'form': result, + 'partner_id': customers, + 'start_date': self.from_date, + 'end_date': self.to_date, + 'status': self.status, + } + + return datas + + def get_excel_invoice_report(self): + datas = self._get_data() + return { + 'type': 'ir.actions.report', + 'report_type': 'xlsx', + 'data': {'model': 'sale.report.invoice', + 'output_format': 'xlsx', + 'options': json.dumps(datas, default=date_utils.json_default), + 'report_name': 'Excel Report Name', + }, + } + + def get_xlsx_report(self, data, response): + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + record =[] + cell_format = workbook.add_format({'font_size': '12px',}) + head = workbook.add_format({'align': 'center', 'bold': True, 'font_size': '20px'}) + txt = workbook.add_format({'font_size': '10px','align': 'center'}) + sheet.merge_range('G2:M3', 'Invoice Analysis Report', head) + if data['start_date'] and data['end_date']: + sheet.write('G6', 'From:', cell_format) + sheet.merge_range('H6:I6', data['start_date'], txt) + sheet.write('K6', 'To:', cell_format) + sheet.merge_range('L6:M6', data['end_date'], txt) + + format1 = workbook.add_format( + {'font_size': 10, 'align': 'left','bg_color':'#bbd5fc','border': 1}) + format4 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bg_color': '#bbd5fc', 'border': 1}) + format2 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, + 'bg_color': '#6BA6FE', 'border': 1}) + format3 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True}) + record = data['partner_id'] + h_row = 7 + h_col = 9 + count = 0 + row = 5 + col = 6 + row_number = 6 + t_row = 6 + if data['partner_id']: + for rec in record: + sheet.merge_range(h_row, h_col-3,h_row,h_col+3, rec['name'], format4) + row= row + count + 3 + sheet.write(row, col, 'Order Number', format2) + sheet.set_column('G:G', 12) + col += 1 + sheet.write(row, col, 'Order Date', format2) + sheet.set_column('H:H', 15) + col += 1 + sheet.write(row, col, 'Invoice Number', format2) + sheet.set_column('I:I', 13) + col += 1 + sheet.write(row, col, 'Invoice Date', format2) + sheet.set_column('J:J', 15) + col += 1 + sheet.write(row, col, 'Amount Invoiced', format2) + sheet.set_column('K:K', 11) + col += 1 + sheet.write(row, col, 'Amount Paid', format2) + sheet.set_column('L:L', 11) + col += 1 + sheet.write(row, col, 'Amount Due', format2) + sheet.set_column('M:M', 11) + col += 1 + col =6 + count=0 + t_invoiced = 0 + t_paid = 0 + t_due = 0 + row_number=row_number + count + 3 + t_col = 9 + for val in data['form']: + if val['partner_id'] == rec['id']: + count +=1 + column_number = 6 + sheet.write(row_number, column_number, val['so'],format1) + sheet.set_column('G:G', 12) + column_number += 1 + sheet.write(row_number, column_number, val['order_date'], format1) + sheet.set_column('H:H', 15) + column_number += 1 + sheet.write(row_number, column_number, val['invoice'], format1) + sheet.set_column('I:I', 13) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column('J:J', 15) + column_number += 1 + sheet.write(row_number, column_number, val['invoiced'], format1) + sheet.set_column('K:K', 14) + t_invoiced += val['invoiced'] + column_number += 1 + sheet.write(row_number, column_number, val['paid'], format1) + sheet.set_column('L:L', 11) + t_paid += val['paid'] + column_number += 1 + sheet.write(row_number, column_number, val['due'], format1) + sheet.set_column('M:M', 11) + t_due += val['due'] + row_number += 1 + t_row = t_row + count + 3 + sheet.write(t_row, t_col, 'Total', format3) + sheet.set_column('J:J', 15) + t_col += 1 + sheet.write(t_row, t_col, t_invoiced, format3) + sheet.set_column('K:K', 14) + t_col += 1 + sheet.write(t_row, t_col, t_paid, format3) + sheet.set_column('L:L', 11) + t_col += 1 + sheet.write(t_row, t_col, t_due, format3) + sheet.set_column('M:M', 11) + h_row = h_row + count + 3 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() diff --git a/sale_report_advanced/wizard/sale_invoice.xml b/sale_report_advanced/wizard/sale_invoice.xml new file mode 100644 index 000000000..779e883d4 --- /dev/null +++ b/sale_report_advanced/wizard/sale_invoice.xml @@ -0,0 +1,35 @@ + + + + Sales Invoice Analysis + sale.report.invoice + +
+ + + + + + + + + +
+
+
+
+
+ + Sale Invoice Report + ir.actions.act_window + sale.report.invoice + form + + new + +
\ No newline at end of file diff --git a/sale_report_advanced/wizard/sale_report.py b/sale_report_advanced/wizard/sale_report.py new file mode 100644 index 000000000..909979ca6 --- /dev/null +++ b/sale_report_advanced/wizard/sale_report.py @@ -0,0 +1,428 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +import json +import io +from datetime import datetime +from xlsxwriter import workbook + +from odoo.tools import date_utils +from odoo import fields, models +from odoo.exceptions import UserError, ValidationError + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class SaleReportAdvance(models.TransientModel): + _name = "sale.report.advance" + + customer_ids = fields.Many2many('res.partner', string="Customers") + product_ids = fields.Many2many('product.product', string='Products') + from_date = fields.Date(string="Start Date") + to_date = fields.Date(string="End Date") + type = fields.Selection([('customer', 'Customers'), ('product', 'Products'), ('both', 'Both')], + string='Report Print By', default='customer', reqired=True) + company_ids = fields.Many2many('res.company', string='Companies') + today_date = fields.Date(default=fields.Date.today()) + + def _get_data(self): + sale = self.env['sale.order'].search([('state','!=','cancel')]) + sales_order_line = self.env['sale.order.line'].search([('order_id.state','!=','cancel')]) + + if self.from_date and self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.date_order.date() <= self.to_date and x.company_id in self.company_ids, + sale)) + elif not self.from_date and self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() <= self.to_date and x.company_id in self.company_ids, + sale)) + elif self.from_date and not self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.company_id in self.company_ids, + sale)) + elif self.from_date and self.to_date and not self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date and x.date_order.date() <= self.to_date, + sale)) + elif not self.from_date and not self.to_date and self.company_ids: + sales_order = list(filter(lambda + x: x.company_id in self.company_ids, + sale)) + elif not self.from_date and self.to_date and not self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() <= self.to_date, + sale)) + elif self.from_date and not self.to_date and not self.company_ids: + sales_order = list(filter(lambda + x: x.date_order.date() >= self.from_date, + sale)) + else: + sales_order = sale + result = [] + customers = [] + products = [] + for rec in self.customer_ids: + a = { + 'id': rec, + 'name': rec.name + } + customers.append(a) + for rec in self.product_ids: + a = { + 'id': rec, + 'name': rec.name + } + products.append(a) + + if self.type == 'product': + for rec in products: + for lines in sales_order_line: + if lines.product_id == rec['id']: + profit = round(lines.product_id.list_price - lines.product_id.standard_price, 2) + if lines.product_id.standard_price != 0: + margin = round((profit * 100) / lines.product_id.standard_price, 2) + res = { + 'sequence': lines.order_id.name, + 'date': lines.order_id.date_order, + 'product_id': lines.product_id, + 'quantity': lines.product_uom_qty, + 'cost': lines.product_id.standard_price, + 'price': lines.product_id.list_price, + 'profit': profit, + 'margin': margin, + 'partner': lines.order_id.partner_id.name, + } + result.append(res) + if self.type == 'customer': + for rec in customers: + for so in sales_order: + if so.partner_id == rec['id']: + for lines in so.order_line: + profit = round(lines.product_id.list_price - lines.product_id.standard_price, 2) + if lines.product_id.standard_price != 0: + margin = round((profit * 100) / lines.product_id.standard_price, 2) + res = { + 'sequence': so.name, + 'date': so.date_order, + 'product': lines.product_id.name, + 'quantity': lines.product_uom_qty, + 'cost': lines.product_id.standard_price, + 'price': lines.product_id.list_price, + 'profit': profit, + 'margin': margin, + 'partner_id': so.partner_id, + } + result.append(res) + if self.type == 'both': + for rec in customers: + for p in products: + for so in sales_order: + if so.partner_id == rec['id']: + for lines in so.order_line: + if lines.product_id == p['id']: + profit = round(lines.product_id.list_price - lines.product_id.standard_price, 2) + if lines.product_id.standard_price != 0: + margin = round((profit * 100) / lines.product_id.standard_price, 2) + res = { + 'sequence': so.name, + 'date': so.date_order, + 'product': lines.product_id.name, + 'quantity': lines.product_uom_qty, + 'cost': lines.product_id.standard_price, + 'price': lines.product_id.list_price, + 'profit': profit, + 'margin': margin, + 'partner': so.partner_id.name, + } + result.append(res) + if self.from_date and self.to_date and not self.customer_ids and not self.product_ids: + for so in sales_order: + for lines in so.order_line: + profit = round(lines.product_id.list_price - lines.product_id.standard_price, 2) + if lines.product_id.standard_price != 0: + margin = round((profit * 100) / lines.product_id.standard_price, 2) + res = { + 'sequence': so.name, + 'date': so.date_order, + 'product': lines.product_id.name, + 'quantity': lines.product_uom_qty, + 'cost': lines.product_id.standard_price, + 'price': lines.product_id.list_price, + 'profit': profit, + 'margin': margin, + 'partner': so.partner_id.name, + } + result.append(res) + + datas = { + 'ids': self, + 'model': 'sale.report.advance', + 'form': result, + 'partner_id': customers, + 'product_id': products, + 'start_date': self.from_date, + 'end_date': self.to_date, + 'type': self.type, + 'no_value': False, + + } + if self.from_date and self.to_date and not self.customer_ids and not self.product_ids: + datas['no_value']=True + return datas + + def get_report(self): + datas = self._get_data() + return self.env.ref('sale_report_advanced.action_sale_report').report_action([], data=datas) + + def get_excel_report(self): + datas = self._get_data() + return { + 'type': 'ir.actions.report', + 'report_type': 'xlsx', + 'data': {'model': 'sale.report.advance', + 'output_format': 'xlsx', + 'options': json.dumps(datas, default=date_utils.json_default), + 'report_name': 'Excel Report Name', + }, + } + + def get_xlsx_report(self, data, response): + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + record = [] + cell_format = workbook.add_format({'font_size': '12px', }) + head = workbook.add_format({'align': 'center', 'bold': True, 'font_size': '20px'}) + txt = workbook.add_format({'font_size': '10px', 'align': 'center'}) + sheet.merge_range('G2:N3', 'Sales Profit Report', head) + if data['start_date'] and data['end_date']: + sheet.write('G6', 'From:', cell_format) + sheet.merge_range('H6:I6', data['start_date'], txt) + sheet.write('L6', 'To:', cell_format) + sheet.merge_range('M6:N6', data['end_date'], txt) + format1 = workbook.add_format( + {'font_size': 10, 'align': 'center','bg_color':'#bbd5fc','border': 1}) + format2 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, + 'bg_color': '#6BA6FE', 'border': 1}) + format4 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True,'border': 1}) + format3 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, 'bg_color': '#c0dbfa', 'border': 1}) + if data['type'] == 'product': + record = data['product_id'] + if data['type'] == 'customer': + record = data['partner_id'] + h_row = 7 + h_col = 9 + count = 0 + row = 5 + col = 6 + row_number = 6 + t_row = 6 + if data['type'] == 'product' or data['type'] == 'customer': + for rec in record: + sheet.merge_range(h_row, h_col-3,h_row,h_col+4,rec['name'], format3) + row = row + count + 3 + sheet.write(row, col, 'Order', format2) + col += 1 + sheet.write(row, col, 'Date', format2) + sheet.set_column('H:H', 15) + col += 1 + if data['type'] == 'product': + sheet.write(row, col, 'Customer', format2) + sheet.set_column('I:I', 20) + col += 1 + elif data['type'] == 'customer': + sheet.write(row, col, 'Product', format2) + sheet.set_column('I:I', 20) + col += 1 + sheet.write(row, col, 'Quantity', format2) + col += 1 + sheet.write(row, col, 'Cost', format2) + col += 1 + sheet.write(row, col, 'Price', format2) + col += 1 + sheet.write(row, col, 'Profit', format2) + col += 1 + sheet.write(row, col, 'Margin(%)', format2) + col += 1 + col = 6 + count = 0 + row_number = row_number + count + 3 + t_qty = 0 + t_cost = 0 + t_price = 0 + t_profit = 0 + t_margin = 0 + t_col = 8 + for val in data['form']: + if data['type'] == 'customer': + if val['partner_id'] == rec['id']: + count += 1 + column_number = 6 + sheet.write(row_number, column_number, val['sequence'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column('H:H', 15) + column_number += 1 + sheet.write(row_number, column_number, val['product'], format1) + sheet.set_column('I:I', 20) + column_number += 1 + sheet.write(row_number, column_number, val['quantity'], format1) + t_qty += val['quantity'] + column_number += 1 + sheet.write(row_number, column_number, val['cost'], format1) + t_cost += val['cost'] + column_number += 1 + sheet.write(row_number, column_number, val['price'], format1) + t_price += val['price'] + column_number += 1 + sheet.write(row_number, column_number, val['profit'], format1) + t_profit += val['profit'] + column_number += 1 + sheet.write(row_number, column_number, val['margin'], format1) + t_margin += val['margin'] + column_number += 1 + row_number += 1 + if data['type'] == 'product': + if val['product_id'] == rec['id']: + count += 1 + column_number = 6 + sheet.write(row_number, column_number, val['sequence'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column('H:H', 15) + column_number += 1 + sheet.write(row_number, column_number, val['partner'], format1) + sheet.set_column('I:I', 20) + column_number += 1 + sheet.write(row_number, column_number, val['quantity'], format1) + t_qty += val['quantity'] + column_number += 1 + sheet.write(row_number, column_number, val['cost'], format1) + t_cost += val['cost'] + column_number += 1 + sheet.write(row_number, column_number, val['price'], format1) + t_price += val['price'] + column_number += 1 + sheet.write(row_number, column_number, val['profit'], format1) + t_profit += val['profit'] + column_number += 1 + sheet.write(row_number, column_number, val['margin'], format1) + t_margin += val['margin'] + column_number += 1 + row_number += 1 + t_row = t_row + count + 3 + sheet.write(t_row, t_col, 'Total', format4) + t_col += 1 + sheet.write(t_row, t_col, t_qty, format4) + t_col += 1 + sheet.write(t_row, t_col, t_cost, format4) + t_col += 1 + sheet.write(t_row, t_col, t_price, format4) + t_col += 1 + sheet.write(t_row, t_col, t_profit, format4) + t_col += 1 + sheet.write(t_row, t_col, t_margin, format4) + t_col += 1 + h_row = h_row + count + 3 + if data['type'] == 'both' or data['no_value'] == True: + row += 3 + row_number += 2 + t_qty = 0 + t_cost = 0 + t_price = 0 + t_profit = 0 + t_margin = 0 + t_col = 9 + sheet.write(row, col, 'Order', format2) + col += 1 + sheet.write(row, col, 'Date', format2) + sheet.set_column('H:H', 15) + col += 1 + sheet.write(row, col, 'Customer', format2) + sheet.set_column('I:I', 20) + col += 1 + sheet.write(row, col, 'Product', format2) + sheet.set_column('J:J', 20) + col += 1 + sheet.write(row, col, 'Quantity', format2) + col += 1 + sheet.write(row, col, 'Cost', format2) + col += 1 + sheet.write(row, col, 'Price', format2) + col += 1 + sheet.write(row, col, 'Profit', format2) + col += 1 + sheet.write(row, col, 'Margin', format2) + col += 1 + row_number+=1 + for val in data['form']: + column_number = 6 + sheet.write(row_number, column_number, val['sequence'], format1) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column('H:H', 15) + column_number += 1 + sheet.write(row_number, column_number, val['partner'], format1) + sheet.set_column('I:I', 20) + column_number += 1 + sheet.write(row_number, column_number, val['product'], format1) + sheet.set_column('J:J', 20) + column_number += 1 + sheet.write(row_number, column_number, val['quantity'], format1) + t_qty += val['quantity'] + column_number += 1 + sheet.write(row_number, column_number, val['cost'], format1) + t_cost += val['cost'] + column_number += 1 + sheet.write(row_number, column_number, val['price'], format1) + t_price += val['price'] + column_number += 1 + sheet.write(row_number, column_number, val['profit'], format1) + t_profit += val['profit'] + column_number += 1 + sheet.write(row_number, column_number, val['margin'], format1) + t_margin += val['margin'] + column_number += 1 + row_number += 1 + sheet.write(row_number, t_col, 'Total', format4) + t_col += 1 + sheet.write(row_number, t_col, t_qty, format4) + t_col += 1 + sheet.write(row_number, t_col, t_cost, format4) + t_col += 1 + sheet.write(row_number, t_col, t_price, format4) + t_col += 1 + sheet.write(row_number, t_col, t_profit, format4) + t_col += 1 + sheet.write(row_number, t_col, t_margin, format4) + t_col += 1 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() diff --git a/sale_report_advanced/wizard/sale_report.xml b/sale_report_advanced/wizard/sale_report.xml new file mode 100644 index 000000000..1fe927039 --- /dev/null +++ b/sale_report_advanced/wizard/sale_report.xml @@ -0,0 +1,35 @@ + + + + Sales Product Profit + sale.report.advance + +
+ + + + + + + + + + +
+
+
+
+
+ + Sale Report + ir.actions.act_window + sale.report.advance + form + + new + +
\ No newline at end of file diff --git a/sale_report_advanced/wizard/weekly_wise.py b/sale_report_advanced/wizard/weekly_wise.py new file mode 100644 index 000000000..922ddbddf --- /dev/null +++ b/sale_report_advanced/wizard/weekly_wise.py @@ -0,0 +1,219 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + + +import json +import io +import calendar +from datetime import timedelta, datetime +from dateutil import rrule + +from reportlab.platypus.tableofcontents import delta +from xlsxwriter import workbook + +from odoo.tools import date_utils +from odoo import fields, models,_ +from calendar import monthrange +from odoo.exceptions import UserError, ValidationError + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class SaleReportAdvance(models.TransientModel): + _name = "sale.report.weekly" + + date = fields.Date(string='Date', required=True) + invoice_status = fields.Selection( + [('invoiced', 'Fully Invoiced'), + ('to invoice', 'To Invoice'), + ('no', 'Nothing to Invoice')], + string='Invoice Status', default='no', required=True) + amount_type = fields.Selection( + [('total', 'Total Amount'), ('untax', 'Untaxed Amount')], + string='Total Amount', default='total') + today_date = fields.Date(default=fields.Date.today()) + + def get_weekly_report(self): + datas = self._get_data() + return self.env.ref('sale_report_advanced.action_sales_weekly').report_action([], data=datas) + + def _get_data(self): + result = [] + times=[{'id':'morning','name':'Morning (5:00-12:00)'}, {'id':'noon','name':'Noon (1:00-17:00)'},{'id':'evening','name':'Evening (18:00-23:00)'}] + if self.invoice_status == 'invoiced': + sale_order = self.env['sale.order'].sudo().search([('invoice_status', '=', self.invoice_status),('date_order','>',self.date),('state','!=','cancel')]) + elif self.invoice_status == 'to invoice': + sale_order = self.env['sale.order'].sudo().search([('invoice_status', '=', self.invoice_status),('date_order','>',self.date),('state','!=','cancel')]) + else: + sale_order = self.env['sale.order'].sudo().search([('invoice_status', '=', self.invoice_status),('date_order','>',self.date),('state','!=','cancel')]) + for rec in sale_order: + if self.amount_type=='total': + if rec.date_order.hour > 5 and rec.date_order.hour <=12: + res = { + 'order': rec.name, + 'amount':rec.amount_total , + 'time':'morning', + 'date':rec.date_order.date() + } + result.append(res) + + if rec.date_order.hour > 12 and rec.date_order.hour <=17: + res = { + 'order': rec.name, + 'amount': rec.amount_total, + 'time': 'noon', + 'date': rec.date_order.date() + + } + result.append(res) + + if rec.date_order.hour > 17 and rec.date_order.hour <=23: + res = { + 'order': rec.name, + 'amount': rec.amount_total, + 'time': 'evening', + 'date': rec.date_order.date() + + } + result.append(res) + else: + if rec.date_order.hour > 5 and rec.date_order.hour <= 12: + res = { + 'order':rec.name, + 'amount':rec.amount_untaxed, + 'time':'morning', + 'date': rec.date_order.date() + + } + result.append(res) + + if rec.date_order.hour > 12 and rec.date_order.hour <= 17: + res = { + 'order': rec.name, + 'amount': rec.amount_untaxed, + 'time': 'noon', + 'date': rec.date_order.date() + + } + result.append(res) + + if rec.date_order.hour > 17 and rec.date_order.hour <= 23: + res = { + 'order': rec.name, + 'amount': rec.amount_untaxed, + 'time': 'evening', + 'date': rec.date_order.date() + + } + result.append(res) + datas = { + 'ids': self, + 'model': 'sale.report.weekly', + 'form': result, + 'date': self.date, + 'type':self.amount_type, + 'times':times + + } + return datas + + def get_excel_weekly_report(self): + datas = self._get_data() + return { + 'type': 'ir.actions.report', + 'report_type': 'xlsx', + 'data': {'model': 'sale.report.weekly', + 'output_format': 'xlsx', + 'options': json.dumps(datas, default=date_utils.json_default), + 'report_name': 'Excel Report Name', + }, + } + + def get_xlsx_report(self, data, response): + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + head = workbook.add_format({'align': 'center', 'bold': True, 'font_size': '20px'}) + sheet.merge_range('G2:I3', 'Hourly Sales Report', head) + format1 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bg_color': '#f5f9ff', 'border': 1}) + format2 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, + 'bg_color': '#6BA6FE', 'border': 1}) + format3 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True,'bg_color':'#95ff63','border': 1}) + format4 = workbook.add_format( + {'font_size': 10, 'align': 'center', 'bold': True, 'border': 1}) + h_row = 7 + h_col = 7 + count = 0 + row = 4 + row_number = 5 + for rec in data['times']: + col = 6 + row = row + count + 4 + sheet.merge_range(h_row,h_col-1,h_row,h_col+1,rec['name'] , format3) + sheet.write(row, col, 'Order', format2) + sheet.set_column(row, col, 15) + col += 1 + sheet.write(row, col, 'Date', format2) + sheet.set_column(row, col, 15) + col += 1 + if data['type'] =='total': + sheet.write(row, col, 'Total', format2) + sheet.set_column(row, col, 15) + col += 1 + else: + sheet.write(row, col, 'Untaxed Total', format2) + sheet.set_column(row, col, 15) + col += 1 + t_total = 0 + + row_number = row_number +4 + count=0 + t_col = 7 + for val in data['form']: + if val['time'] == rec['id']: + count += 1 + column_number = 6 + sheet.write(row_number, column_number, val['order'], format1) + sheet.set_column(row_number, column_number, 15) + column_number += 1 + sheet.write(row_number, column_number, val['date'], format1) + sheet.set_column(row_number, column_number, 15) + column_number += 1 + sheet.write(row_number, column_number, val['amount'], format1) + t_total += val['amount'] + sheet.set_column(row_number, column_number, 15) + row_number+=1 + sheet.write(row_number, t_col, 'Total', format4) + sheet.set_column(row_number, t_col, 15) + t_col += 1 + sheet.write(row_number, t_col, t_total, format4) + h_row= h_row+ count+4 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() diff --git a/sale_report_advanced/wizard/weekly_wise.xml b/sale_report_advanced/wizard/weekly_wise.xml new file mode 100644 index 000000000..5836c0576 --- /dev/null +++ b/sale_report_advanced/wizard/weekly_wise.xml @@ -0,0 +1,32 @@ + + + + Sales Hourly Wise report + sale.report.weekly + +
+ + + + + + + +
+
+
+
+
+ + Hourly Sales Report + ir.actions.act_window + sale.report.weekly + form + + new + +
\ No newline at end of file diff --git a/serial_no_from_mo/README.rst b/serial_no_from_mo/README.rst new file mode 100644 index 000000000..e692d6967 --- /dev/null +++ b/serial_no_from_mo/README.rst @@ -0,0 +1,41 @@ +Generate Lot/Serial Number From Manufacturing Order +=================================================== +* Generate Lot/Serial Number From Manufacturing Order for Odoo 15 + +Installation +============ + - www.odoo.com/documentation/15.0/setup/install.html + - Install our custom addon + +License +------- +General Public License, Version 3 (LGPL v3). +(https://www.odoo.com/documentation/user/13.0/legal/licenses/licenses.html) + +Company +------- +* 'Cybrosys Techno Solutions `__ + +Credits +------- +* Developer: +Athul @ Cybrosys + +Contacts +-------- +* Mail Contact : odoo@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 +========== +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com + +Further information +=================== +HTML Description: ``__ + diff --git a/serial_no_from_mo/__init__.py b/serial_no_from_mo/__init__.py new file mode 100644 index 000000000..f2c5a4636 --- /dev/null +++ b/serial_no_from_mo/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2021-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from . import models diff --git a/serial_no_from_mo/__manifest__.py b/serial_no_from_mo/__manifest__.py new file mode 100644 index 000000000..7ffc7440e --- /dev/null +++ b/serial_no_from_mo/__manifest__.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +{ + 'name': 'Generate Lot/Serial Number From Manufacturing Order', + 'version': '15.0.1.0.0', + 'summary': """Auto generate Serial/lot from manufacturing order""", + 'description': """Automatically generates lot/serial number for product while confirming + the manufacturing order.User can set lot/seral number sequence in + product wise and global wise""", + 'category': 'Manufacturing', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'depends': ['base', 'mrp'], + 'website': 'https://www.cybrosys.com', + 'data': [ + 'views/res_settings.xml', + 'views/product_template.xml', + ], + 'images': ['static/description/banner.png'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/serial_no_from_mo/doc/RELEASE_NOTES.md b/serial_no_from_mo/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..03862dffe --- /dev/null +++ b/serial_no_from_mo/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module Generate Lot/Serial Number from Manufacturing order + +#### 29.4.2022 +#### Version 15.0.1.0.0 +##### ADD +- Initial Commit for serial_no_from_mo diff --git a/serial_no_from_mo/models/__init__.py b/serial_no_from_mo/models/__init__.py new file mode 100644 index 000000000..41b6e2e96 --- /dev/null +++ b/serial_no_from_mo/models/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2021-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import res_settings +from . import product_template diff --git a/serial_no_from_mo/models/product_template.py b/serial_no_from_mo/models/product_template.py new file mode 100644 index 000000000..218bdfe37 --- /dev/null +++ b/serial_no_from_mo/models/product_template.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2021-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import models, fields, api + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + digit = fields.Integer(string="Number of Digits") + prefix = fields.Char(string="Prefix") + + +class MrpProduction(models.Model): + _inherit = "mrp.production" + + def action_confirm(self): + parms = self.env['ir.config_parameter'].sudo() + type = parms.get_param('serial_selection') + if self.product_id.tracking == 'serial' or self.product_id.tracking == 'lot': + if type == 'global': + digit = parms.get_param('digit') + prefix = parms.get_param('prefix') + seq = self.env['ir.sequence'].sudo().search([('code', '=', 'mrp.production.sequence')]) + if seq: + seq.write({ + 'prefix': prefix, + 'padding': digit + }) + if not seq: + self.env['ir.sequence'].create({ + 'name': 'Mrp Production', + 'implementation': 'standard', + 'code': 'mrp.production.sequence', + 'prefix': prefix, + 'padding': digit}) + serial_id = self.env['stock.production.lot'].create({ + 'name': self.env['ir.sequence'].sudo().next_by_code('mrp.production.sequence'), + 'product_id': self.product_id.id, + 'company_id': self.company_id.id, + }) + else: + seq = self.env['ir.sequence'].sudo().search([('code', '=', self.product_id.name)]) + if seq: + seq.write({ + 'prefix': self.product_id.product_tmpl_id.prefix, + 'padding': self.product_id.product_tmpl_id.digit, + }) + if not seq: + self.env['ir.sequence'].create({ + 'name': 'Mrp Production', + 'implementation': 'standard', + 'code': self.product_id.name, + 'prefix': self.product_id.product_tmpl_id.prefix, + 'padding': self.product_id.product_tmpl_id.digit}) + serial_id = self.env['stock.production.lot'].create({ + 'name': self.env['ir.sequence'].sudo().next_by_code(self.product_id.name), + 'product_id': self.product_id.id, + 'company_id': self.company_id.id, + }) + self.lot_producing_id = serial_id + return super(MrpProduction, self).action_confirm() diff --git a/serial_no_from_mo/models/res_settings.py b/serial_no_from_mo/models/res_settings.py new file mode 100644 index 000000000..10ebbf3af --- /dev/null +++ b/serial_no_from_mo/models/res_settings.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2021-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import models, fields, api + + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + serial_selection = fields.Selection([('global', 'Global'), ('product_wise', 'Product Wise')], + default='global', string="Serial number Selection Method") + + digit = fields.Integer(string="Number of Digits") + prefix = fields.Char(string="Prefix") + + @api.model + def get_values(self): + res = super(ResConfigSettings, self).get_values() + params = self.env['ir.config_parameter'].sudo() + serial_selection = params.get_param('serial_selection') + digit = params.get_param('digit') + prefix = params.get_param('prefix') + res.update(serial_selection=serial_selection, digit=digit, prefix=prefix) + return res + + def set_values(self): + super(ResConfigSettings, self).set_values() + parms = self.env['ir.config_parameter'].sudo() + parms.set_param("serial_selection", self.serial_selection) + parms.set_param("digit", self.digit) + parms.set_param("prefix", self.prefix) diff --git a/serial_no_from_mo/static/description/assets/icons/check.png b/serial_no_from_mo/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/check.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/chevron.png b/serial_no_from_mo/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/chevron.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/cogs.png b/serial_no_from_mo/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/cogs.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/consultation.png b/serial_no_from_mo/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/consultation.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/ecom-black.png b/serial_no_from_mo/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/ecom-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/education-black.png b/serial_no_from_mo/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/education-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/hotel-black.png b/serial_no_from_mo/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/hotel-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/license.png b/serial_no_from_mo/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/license.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/lifebuoy.png b/serial_no_from_mo/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/lifebuoy.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/logo.png b/serial_no_from_mo/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/logo.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/manufacturing-black.png b/serial_no_from_mo/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/manufacturing-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/pos-black.png b/serial_no_from_mo/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/pos-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/puzzle.png b/serial_no_from_mo/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/puzzle.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/restaurant-black.png b/serial_no_from_mo/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/restaurant-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/service-black.png b/serial_no_from_mo/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/service-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/trading-black.png b/serial_no_from_mo/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/trading-black.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/training.png b/serial_no_from_mo/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/training.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/update.png b/serial_no_from_mo/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/update.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/user.png b/serial_no_from_mo/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/user.png differ diff --git a/serial_no_from_mo/static/description/assets/icons/wrench.png b/serial_no_from_mo/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/serial_no_from_mo/static/description/assets/icons/wrench.png differ diff --git a/serial_no_from_mo/static/description/assets/modules/budget_image.png b/serial_no_from_mo/static/description/assets/modules/budget_image.png new file mode 100644 index 000000000..b50130c7d Binary files /dev/null and b/serial_no_from_mo/static/description/assets/modules/budget_image.png differ diff --git a/serial_no_from_mo/static/description/assets/modules/credit_image.png b/serial_no_from_mo/static/description/assets/modules/credit_image.png new file mode 100644 index 000000000..3ad04ecfd Binary files /dev/null and b/serial_no_from_mo/static/description/assets/modules/credit_image.png differ diff --git a/serial_no_from_mo/static/description/assets/modules/employee_image.png b/serial_no_from_mo/static/description/assets/modules/employee_image.png new file mode 100644 index 000000000..30ad58232 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/modules/employee_image.png differ diff --git a/serial_no_from_mo/static/description/assets/modules/export_image.png b/serial_no_from_mo/static/description/assets/modules/export_image.png new file mode 100644 index 000000000..492980ad0 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/modules/export_image.png differ diff --git a/serial_no_from_mo/static/description/assets/modules/gantt_image.png b/serial_no_from_mo/static/description/assets/modules/gantt_image.png new file mode 100644 index 000000000..1ae7cfe3b Binary files /dev/null and b/serial_no_from_mo/static/description/assets/modules/gantt_image.png differ diff --git a/serial_no_from_mo/static/description/assets/modules/quotation_image.png b/serial_no_from_mo/static/description/assets/modules/quotation_image.png new file mode 100644 index 000000000..499b1a72f Binary files /dev/null and b/serial_no_from_mo/static/description/assets/modules/quotation_image.png differ diff --git a/serial_no_from_mo/static/description/assets/screenshots/1.png b/serial_no_from_mo/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..b190fae6c Binary files /dev/null and b/serial_no_from_mo/static/description/assets/screenshots/1.png differ diff --git a/serial_no_from_mo/static/description/assets/screenshots/2.png b/serial_no_from_mo/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..b67b569f6 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/screenshots/2.png differ diff --git a/serial_no_from_mo/static/description/assets/screenshots/3.png b/serial_no_from_mo/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..649fa78f7 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/screenshots/3.png differ diff --git a/serial_no_from_mo/static/description/assets/screenshots/4.png b/serial_no_from_mo/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..9c64f25a5 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/screenshots/4.png differ diff --git a/serial_no_from_mo/static/description/assets/screenshots/5.png b/serial_no_from_mo/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..b8cfc7efe Binary files /dev/null and b/serial_no_from_mo/static/description/assets/screenshots/5.png differ diff --git a/serial_no_from_mo/static/description/assets/screenshots/hero.gif b/serial_no_from_mo/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..a588e17d5 Binary files /dev/null and b/serial_no_from_mo/static/description/assets/screenshots/hero.gif differ diff --git a/serial_no_from_mo/static/description/banner.png b/serial_no_from_mo/static/description/banner.png new file mode 100644 index 000000000..25507105a Binary files /dev/null and b/serial_no_from_mo/static/description/banner.png differ diff --git a/serial_no_from_mo/static/description/icon.png b/serial_no_from_mo/static/description/icon.png new file mode 100644 index 000000000..ac876abd9 Binary files /dev/null and b/serial_no_from_mo/static/description/icon.png differ diff --git a/serial_no_from_mo/static/description/index.html b/serial_no_from_mo/static/description/index.html new file mode 100644 index 000000000..972b01567 --- /dev/null +++ b/serial_no_from_mo/static/description/index.html @@ -0,0 +1,584 @@ +
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+ +
+
+
+
+ +
+
+
+

+ Generate Lot/Serial Number from Manufacturing order

+

+ Automatically generates lot/serial number from MO +

+ +
+
+ + + +
+
+

+ Overview +

+
+ +
+

+ Automatically generates lot/serial number for product while confirming + the manufacturing order.User can set lot/serial number sequence in + product wise and global wise

+
+

+ +
+ + +
+
+

+ Features +

+
+ +
+
+ +
+
+

+ Auto generate Lot/Serial number

+
+
+ +
+
+ +
+
+

+ Product wise Lot/Serial number Sequence

+
+
+ +
+
+ +
+
+

+ Global wise Lot/Serial number Sequence

+
+
+
+ +
+
+

+ Screenshots +

+
+
+

+ Configuration Settings

+

+ In configuration settings, user can select and configure the serial number selection method. + Using Global wise user can set sequence for all products.Product wise used to set sequence for each product separately +

+ +
+ +
+

+ Auto generated Lot/serial number in Global method

+

+

+ +
+ +
+

+ Product wise method

+ +
+ + +
+

+

User can set sequence for each product +

+ +
+ + +
+

+ Auto generated Lot/serial number in Product wise method

+ +
+
+ +
+
+

Suggested Products

+
+ + +
+
+ + + +
+
+
+

Our Services

+
+
+ +
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + + +
+
+
+

Our Industries

+
+
+ +
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+ +
+
+ + + + + +
+
+
+

Need Help?

+
+
+
+ + +
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ + +
\ No newline at end of file diff --git a/serial_no_from_mo/views/product_template.xml b/serial_no_from_mo/views/product_template.xml new file mode 100644 index 000000000..61f79e20c --- /dev/null +++ b/serial_no_from_mo/views/product_template.xml @@ -0,0 +1,14 @@ + + + + product.template.form.inherit + product.template + + + + + + + + + diff --git a/serial_no_from_mo/views/res_settings.xml b/serial_no_from_mo/views/res_settings.xml new file mode 100644 index 000000000..e9bc22317 --- /dev/null +++ b/serial_no_from_mo/views/res_settings.xml @@ -0,0 +1,33 @@ + + + + res.config.settings.view.form.inherited + res.config.settings + + + +
+
+
+
+
+
+
+