@ -0,0 +1,46 @@ |
|||||
|
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
||||
|
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
All in One Sales Kit |
||||
|
==================== |
||||
|
This module combines a variety of sales features. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
* No Additional configuration is needed. |
||||
|
|
||||
|
Company |
||||
|
------- |
||||
|
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
||||
|
|
||||
|
License |
||||
|
------- |
||||
|
General Public License, Version 3 (AGPL-3). |
||||
|
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
||||
|
|
||||
|
Credits |
||||
|
------- |
||||
|
Developer: (V16) Swetha Anand, Contact: odoo@cybrosys.com |
||||
|
|
||||
|
Contacts |
||||
|
-------- |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
----------- |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,25 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import controllers |
||||
|
from . import models |
||||
|
from . import report |
||||
|
from . import wizard |
@ -0,0 +1,102 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
{ |
||||
|
'name': 'Odoo16 All in One Sales Kit', |
||||
|
'version': '16.0.1.0.0', |
||||
|
'category': 'Sales', |
||||
|
'summary': 'This module combines a variety of sales features.', |
||||
|
'description': 'Sale Order Line Images, Barcode Scan Support for Sales, ' |
||||
|
'Advanced Sale Reports (Product Profit Report, ' |
||||
|
'Sales Invoice Analysis Report, Sales Category Report, ' |
||||
|
'Sales Indent Report, Sales Analysis Report, ' |
||||
|
'Hourly Sales Report), Product Pack, and ' |
||||
|
'Salesperson Signature for Confirm Order are some of the ' |
||||
|
'features included in this module.' |
||||
|
'Previous Sale Product Rate, Create Various Sale Order ' |
||||
|
'Versions, Create Custom Fields for Sale Orders, ' |
||||
|
'Recognise Previous Sales of Products,' |
||||
|
'A separate quotation number,' |
||||
|
'Multiple warehouses in sale order lines,' |
||||
|
'sales order and quotation line views,' |
||||
|
'approval of the sale order discount,sales restrictions ' |
||||
|
'for out-of-stock items depending on forecast and ' |
||||
|
'stock level,automate the sale process,' |
||||
|
'Sales one-stop report generation,Add more than one ' |
||||
|
'item to the quotation,pivot view for partner sales,' |
||||
|
'sale order archive,Dashboard.', |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'website': 'https://www.cybrosys.com', |
||||
|
'depends': ['sale_management', 'delivery', 'stock','sale'], |
||||
|
'data': [ |
||||
|
'security/all_in_one_sales_kit_groups.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
'data/field_widget_data.xml', |
||||
|
'data/ir_sequence_data.xml', |
||||
|
'wizard/product_sale_order_history_views.xml', |
||||
|
'wizard/sale_order_dynamic_fields_views.xml', |
||||
|
'wizard/sale_report_advance_views.xml', |
||||
|
'wizard/sale_report_analysis_views.xml', |
||||
|
'wizard/sale_report_category_views.xml', |
||||
|
'wizard/sale_report_indent_views.xml', |
||||
|
'wizard/sale_report_invoice_views.xml', |
||||
|
'wizard/sale_report_weekly_views.xml', |
||||
|
'wizard/select_product_pack_views.xml', |
||||
|
'views/res_config_settings_views.xml', |
||||
|
'views/all_in_one_sales_kit_menus.xml', |
||||
|
'views/sale_order_views.xml', |
||||
|
'views/sale_order_line_views.xml', |
||||
|
'views/res_users_views.xml', |
||||
|
'views/sale_report_views.xml', |
||||
|
'views/product_template_views.xml', |
||||
|
'views/ir_fields_search_views.xml', |
||||
|
'views/product_product_views.xml', |
||||
|
'views/dashboard_menu.xml', |
||||
|
'report/invoice_analysis_templates.xml', |
||||
|
'report/sale_order_document_templates.xml', |
||||
|
'report/sale_order_report_templates.xml', |
||||
|
'report/sale_profit_templates.xml', |
||||
|
'report/sale_reports.xml', |
||||
|
'report/sales_analysis_templates.xml', |
||||
|
'report/sales_category_templates.xml', |
||||
|
'report/sales_indent_templates.xml', |
||||
|
'report/sales_weekly_templates.xml' |
||||
|
], |
||||
|
'assets': { |
||||
|
'web.assets_backend': [ |
||||
|
'all_in_one_sales_kit/static/src/css/sale_report.css', |
||||
|
'all_in_one_sales_kit/static/src/scss/dashboard.scss', |
||||
|
'all_in_one_sales_kit/static/src/js/action_manager.js', |
||||
|
'all_in_one_sales_kit/static/src/js/sale_report.js', |
||||
|
'all_in_one_sales_kit/static/src/js/dashboard.js', |
||||
|
'all_in_one_sales_kit/static/src/xml/sale_report_templates.xml', |
||||
|
'all_in_one_sales_kit/static/src/xml/dashboard_templates.xml', |
||||
|
'https://cdn.jsdelivr.net/npm/chart.js', |
||||
|
], |
||||
|
}, |
||||
|
'images': ['static/description/banner.jpg'], |
||||
|
'license': 'AGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import all_in_one_sales_kit |
@ -0,0 +1,55 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
import json |
||||
|
from odoo import http |
||||
|
from odoo.http import content_disposition, request |
||||
|
from odoo.tools import html_escape |
||||
|
|
||||
|
|
||||
|
class XLSXReportController(http.Controller): |
||||
|
"""This class is to add sales xlsx reports.""" |
||||
|
|
||||
|
@http.route('/xlsx_reports', type='http', auth='user', |
||||
|
methods=['POST'], csrf=False) |
||||
|
def get_report_xlsx(self, model, options, output_format, |
||||
|
report_name, **kw): |
||||
|
"""This is to pass data required for the xlsx report.""" |
||||
|
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')) |
||||
|
] |
||||
|
) |
||||
|
request.env[model].sudo().browse( |
||||
|
request.session.uid).get_xlsx_report(json.loads(options), |
||||
|
response) |
||||
|
response.set_cookie('fileToken', token) |
||||
|
return response |
||||
|
except Exception: |
||||
|
error = { |
||||
|
'code': 200, |
||||
|
'message': 'Odoo Server Error', |
||||
|
} |
||||
|
return request.make_response(html_escape(json.dumps(error))) |
@ -0,0 +1,77 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data noupdate="1"> |
||||
|
<!-- Widget 'image' for 'binary' field --> |
||||
|
<record id="field_widget_image_widget" model="field.widget"> |
||||
|
<field name="name">image</field> |
||||
|
<field name="description">Image</field> |
||||
|
</record> |
||||
|
<!-- Widget 'many2many_tags' for 'many2many' field --> |
||||
|
<record id="field_widget_many2many_tag_widget" model="field.widget"> |
||||
|
<field name="name">many2many_tags</field> |
||||
|
<field name="description">Many2many Tags</field> |
||||
|
</record> |
||||
|
<!-- Widget 'binary' for 'many2many' field --> |
||||
|
<record id="field_widget_many2many_binary_widget" |
||||
|
model="field.widget"> |
||||
|
<field name="name">binary</field> |
||||
|
<field name="description">Binary</field> |
||||
|
</record> |
||||
|
<!-- Widget 'radio' for 'selection' field --> |
||||
|
<record id="field_widget_radio_widget" model="field.widget"> |
||||
|
<field name="name">radio</field> |
||||
|
<field name="description">Radio</field> |
||||
|
</record> |
||||
|
<!-- Widget 'priority' for 'selection' field --> |
||||
|
<record id="field_widget_priority_widget" model="field.widget"> |
||||
|
<field name="name">priority</field> |
||||
|
<field name="description">Priority</field> |
||||
|
</record> |
||||
|
<!-- Widget 'monetory' for 'float' field --> |
||||
|
<record id="field_widgets_monetory_widget" model="field.widget"> |
||||
|
<field name="name">monetary</field> |
||||
|
<field name="description">Monetary</field> |
||||
|
</record> |
||||
|
<!-- Widget 'selection' for 'Many2one' field --> |
||||
|
<record id="field_widget_selection_widget" model="field.widget"> |
||||
|
<field name="name">selection</field> |
||||
|
<field name="description">Selection</field> |
||||
|
</record> |
||||
|
<!-- Widget 'image' for 'binary' field --> |
||||
|
<record id="field_widget_image_widget" model="field.widget"> |
||||
|
<field name="name">image</field> |
||||
|
<field name="description">Image</field> |
||||
|
</record> |
||||
|
<!-- Widget 'many2many_tags' for 'many2many' field --> |
||||
|
<record id="field_widget_many2many_tag_widget" model="field.widget"> |
||||
|
<field name="name">many2many_tags</field> |
||||
|
<field name="description">Many2many Tags</field> |
||||
|
</record> |
||||
|
<!-- Widget 'binary' for 'many2many' field --> |
||||
|
<record id="field_widget_many2many_binary_widget" |
||||
|
model="field.widget"> |
||||
|
<field name="name">binary</field> |
||||
|
<field name="description">Binary</field> |
||||
|
</record> |
||||
|
<!-- Widget 'radio' for 'selection' field --> |
||||
|
<record id="field_widget_radio_widget" model="field.widget"> |
||||
|
<field name="name">radio</field> |
||||
|
<field name="description">Radio</field> |
||||
|
</record> |
||||
|
<!-- Widget 'priority' for 'selection' field --> |
||||
|
<record id="field_widget_priority_widget" model="field.widget"> |
||||
|
<field name="name">priority</field> |
||||
|
<field name="description">Priority</field> |
||||
|
</record> |
||||
|
<!-- Widget 'monetory' for 'float' field --> |
||||
|
<record id="field_widget_monetory_widget" model="field.widget"> |
||||
|
<field name="name">monetary</field> |
||||
|
<field name="description">Monetary</field> |
||||
|
</record> |
||||
|
<!-- Widget 'selection' for 'Many2one' field --> |
||||
|
<record id="field_widget_selection_widget" model="field.widget"> |
||||
|
<field name="name">selection</field> |
||||
|
<field name="description">Selection</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,11 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo noupdate="1"> |
||||
|
<!-- Sequence for the quotation --> |
||||
|
<record id="seq_quotation" model="ir.sequence"> |
||||
|
<field name="name">Quotation</field> |
||||
|
<field name="code">sale.order</field> |
||||
|
<field name="prefix">SQ</field> |
||||
|
<field name="padding">5</field> |
||||
|
<field name="company_id" eval="False"/> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,7 @@ |
|||||
|
## Module <all_in_one_sales_kit> |
||||
|
|
||||
|
#### 07.12.2023 |
||||
|
#### Version 16.0.1.0.0 |
||||
|
#### ADD |
||||
|
|
||||
|
- Initial commit for All in One Sales Kit |
@ -0,0 +1,32 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import field_widget |
||||
|
from . import ir_model_fields |
||||
|
from . import pack_product |
||||
|
from . import product_product |
||||
|
from . import product_template |
||||
|
from . import res_config_settings |
||||
|
from . import res_partner |
||||
|
from . import res_users |
||||
|
from . import sale_order |
||||
|
from . import sale_order_line |
||||
|
from . import sales_report |
@ -0,0 +1,39 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class FieldWidget(models.Model): |
||||
|
""" |
||||
|
Need of this model is because we can't filter a selection field dynamically |
||||
|
so when we select a field its widgets also need to change according to |
||||
|
field type, we can't do it by a 'selection' field, |
||||
|
need a 'Many2one' field. |
||||
|
""" |
||||
|
|
||||
|
_name = 'field.widget' |
||||
|
_description = 'Field Widgets' |
||||
|
_rec_name = 'description' |
||||
|
|
||||
|
name = fields.Char(string="Name", help="Name of widget.") |
||||
|
description = fields.Char( |
||||
|
string="Description", help="Description about the widget.") |
@ -0,0 +1,32 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class IrModelFields(models.Model): |
||||
|
"""Adding a new field to understand the dynamically created fields.""" |
||||
|
|
||||
|
_inherit = 'ir.model.fields' |
||||
|
|
||||
|
is_dynamic = fields.Boolean( |
||||
|
string="Dynamic Field", |
||||
|
help="To make sure it is a dynamically created field.") |
@ -0,0 +1,84 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import api, fields, models, _ |
||||
|
from odoo.exceptions import ValidationError |
||||
|
|
||||
|
|
||||
|
class PackProduct(models.Model): |
||||
|
""" A new model is created to store products as pack.""" |
||||
|
|
||||
|
_name = 'pack.product' |
||||
|
_rec_name = 'product_tmpl_id' |
||||
|
_description = 'Select Pack Products' |
||||
|
|
||||
|
product_id = fields.Many2one( |
||||
|
'product.product', string='Product', required=True, |
||||
|
domain=[('is_pack', '=', False)], help="Product") |
||||
|
product_tmpl_id = fields.Many2one( |
||||
|
'product.template', string='Product', help="Product") |
||||
|
price = fields.Float( |
||||
|
string='Price', compute='_compute_price', store=True, |
||||
|
help="Computed price of product according to the quantity.") |
||||
|
quantity = fields.Integer( |
||||
|
string='Quantity', default=1, |
||||
|
help="Quantity of product that should be in the pack.") |
||||
|
qty_available = fields.Float( |
||||
|
string='Quantity Available', compute='_compute_qty_available', |
||||
|
store=True, readonly=False, help="Available quantity of product.") |
||||
|
total_available_quantity = fields.Float( |
||||
|
string='Total Quantity', |
||||
|
help="Total Quantity available of that product") |
||||
|
|
||||
|
@api.depends('product_id', |
||||
|
'total_available_quantity', |
||||
|
'product_id.qty_available') |
||||
|
def _compute_qty_available(self): |
||||
|
"""It is to compute the available quantity.""" |
||||
|
for record in self: |
||||
|
location_id = record.product_tmpl_id.pack_location_id |
||||
|
if location_id: |
||||
|
stock_quant = self.env['stock.quant'].search( |
||||
|
[('product_id', '=', record.product_id.id), |
||||
|
('location_id', '=', location_id.id)]) |
||||
|
if stock_quant: |
||||
|
record.qty_available = stock_quant.quantity |
||||
|
else: |
||||
|
record.qty_available = False |
||||
|
else: |
||||
|
record.qty_available = False |
||||
|
|
||||
|
@api.depends('product_id', 'quantity') |
||||
|
def _compute_price(self): |
||||
|
"""It is to compute price of each product compared to quantity.""" |
||||
|
for record in self: |
||||
|
record.price = record.product_id.lst_price * record.quantity |
||||
|
|
||||
|
@api.onchange('quantity') |
||||
|
def _onchange_quantity(self): |
||||
|
"""It is to set price.""" |
||||
|
self.price = self.product_id.lst_price * self.quantity |
||||
|
|
||||
|
@api.constrains('quantity') |
||||
|
def _check_quantity(self): |
||||
|
"""This function is to ensure product quantity is positive.""" |
||||
|
if any([product.quantity < 0 for product in self]): |
||||
|
raise ValidationError(_('You can not enter negative quantities.')) |
@ -0,0 +1,74 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
from odoo.exceptions import UserError |
||||
|
|
||||
|
|
||||
|
class ProductProduct(models.Model): |
||||
|
"""Inherits product.product.""" |
||||
|
_inherit = "product.product" |
||||
|
|
||||
|
order_partner_id = fields.Many2one( |
||||
|
'res.partner', string="Partner", help="Current Partner") |
||||
|
|
||||
|
def action_sale_product_prices(self): |
||||
|
"""It is to show to product history.""" |
||||
|
rel_view_id = self.env.ref( |
||||
|
'all_in_one_sales_kit.last_sale_product_prices_view') |
||||
|
if self.order_partner_id.id: |
||||
|
sale_lines = self.env['sale.order.line'].search( |
||||
|
[('product_id', '=', self.id), |
||||
|
('order_partner_id', '=', self.order_partner_id.id)], |
||||
|
order='create_date DESC').ids |
||||
|
else: |
||||
|
sale_lines = self.env['sale.order.line'].search( |
||||
|
[('product_id', '=', self.id)], |
||||
|
order='create_date DESC').ids |
||||
|
if not sale_lines: |
||||
|
raise UserError("No sales history found.!") |
||||
|
else: |
||||
|
return { |
||||
|
'domain': [('id', 'in', sale_lines)], |
||||
|
'views': [(rel_view_id.id, 'tree')], |
||||
|
'name': 'Sales History', |
||||
|
'res_model': 'sale.order.line', |
||||
|
'view_id': False, |
||||
|
'type': 'ir.actions.act_window', |
||||
|
} |
||||
|
|
||||
|
def action_add_quotation(self): |
||||
|
"""It is a button function on clicking the product is entered to |
||||
|
the order line.""" |
||||
|
order_id = self.env.context.get('order_id') |
||||
|
list = self.env['sale.order.line'].search( |
||||
|
[('order_id', '=', order_id)]).mapped('product_id') |
||||
|
if self in list: |
||||
|
order_line_id = self.env['sale.order.line'].search( |
||||
|
[('order_id', '=', order_id), ('product_id', '=', self.id)]) |
||||
|
order_line_id.product_uom_qty += 1 |
||||
|
else: |
||||
|
self.env['sale.order.line'].create({ |
||||
|
'product_id': self.id, |
||||
|
'order_id': order_id, |
||||
|
'qty_available': self.qty_available, |
||||
|
'forecast_quantity': self.virtual_available, |
||||
|
}) |
@ -0,0 +1,139 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import api, fields, models, _ |
||||
|
from odoo.exceptions import UserError |
||||
|
|
||||
|
|
||||
|
class ProductTemplate(models.Model): |
||||
|
"""Inherits product.template.""" |
||||
|
_inherit = 'product.template' |
||||
|
|
||||
|
def default_pack_location(self): |
||||
|
"""Sets the default value for the 'location_id' field based |
||||
|
on the current user's warehouse.""" |
||||
|
warehouse = self.env['stock.warehouse'].search( |
||||
|
[('company_id', '=', self.env.company.id)], limit=1) |
||||
|
if warehouse: |
||||
|
return warehouse.lot_stock_id.id |
||||
|
|
||||
|
is_pack = fields.Boolean(string='Is a Pack', help="The product is a pack.") |
||||
|
pack_price = fields.Integer( |
||||
|
string="Pack Price", compute='_compute_pack_price', store=True, |
||||
|
help="Total price of products inside the pack") |
||||
|
pack_products_ids = fields.One2many( |
||||
|
'pack.product', 'product_tmpl_id', |
||||
|
string='Pack Products', copy=True, help="Products inside the pack") |
||||
|
pack_quantity = fields.Integer( |
||||
|
string='Pack Quantity', help="Pack quantity available") |
||||
|
pack_location_id = fields.Many2one( |
||||
|
'stock.location', |
||||
|
domain=[('usage', 'in', ['internal', 'transit'])], |
||||
|
default=default_pack_location, help="Warehouse", string="Warehouse") |
||||
|
|
||||
|
@api.depends('pack_products_ids', 'pack_products_ids.price') |
||||
|
def _compute_pack_price(self): |
||||
|
"""It is to set total price of the pack according to the |
||||
|
products in the pack.""" |
||||
|
price = 0 |
||||
|
for record in self: |
||||
|
for line in record.pack_products_ids: |
||||
|
price = price + line.price |
||||
|
record.pack_price = price |
||||
|
|
||||
|
@api.model |
||||
|
def create(self, values): |
||||
|
"""Here create function is over ride to check whether the product is |
||||
|
a pack or not.""" |
||||
|
if values.get('is_pack', False): |
||||
|
if not values.get('pack_products_ids', []): |
||||
|
raise UserError(_( |
||||
|
'You need to add atleast one product in the Pack...!')) |
||||
|
if values.get('type', False) == 'service': |
||||
|
raise UserError(_( |
||||
|
'You cannot define a pack product as a service..!')) |
||||
|
return super(ProductTemplate, self).create(values) |
||||
|
|
||||
|
def write(self, values): |
||||
|
"""Here, the write function is overridden to determine if |
||||
|
there is at least one product inside the package.""" |
||||
|
super(ProductTemplate, self).write(values) |
||||
|
if self.is_pack: |
||||
|
if not self.pack_products_ids: |
||||
|
raise UserError(_( |
||||
|
'You need to add atleast one product in the Pack...!')) |
||||
|
if self.type == 'service': |
||||
|
raise UserError( |
||||
|
_('You cannot define a pack product as a service..!')) |
||||
|
|
||||
|
def action_update_price_product(self): |
||||
|
"""Updates the 'list_price' field of the current object |
||||
|
based on the value of the 'pack_price' field on button click.""" |
||||
|
self.list_price = self.pack_price |
||||
|
|
||||
|
def action_get_quantity(self): |
||||
|
"""It is to return the pack quantity.""" |
||||
|
total_quantity = 1 |
||||
|
flag = 1 |
||||
|
while flag: |
||||
|
for line in self.pack_products_ids: |
||||
|
if line.qty_available >= line.quantity * total_quantity: |
||||
|
continue |
||||
|
else: |
||||
|
if line.product_id.type != 'product': |
||||
|
continue |
||||
|
flag = 0 |
||||
|
break |
||||
|
if flag: |
||||
|
total_quantity = total_quantity + 1 |
||||
|
self.pack_quantity = total_quantity - 1 |
||||
|
|
||||
|
def action_update_quantity(self): |
||||
|
"""It is to return the updated pack quantity.""" |
||||
|
product_id = len( |
||||
|
self.product_variant_ids) == 1 and self.product_variant_id.id |
||||
|
location_id = self.pack_location_id.id |
||||
|
if not location_id: |
||||
|
warehouse = self.env['stock.warehouse'].search( |
||||
|
[('company_id', '=', self.env.company.id)], limit=1) |
||||
|
location_id = warehouse.lot_stock_id.id |
||||
|
if not location_id: |
||||
|
raise UserError(_( |
||||
|
'You need to select the location to update' |
||||
|
' the pack quantity...!')) |
||||
|
self.env['stock.quant'].with_context(inventory_mode=True).sudo( |
||||
|
).create({ |
||||
|
'product_id': product_id, |
||||
|
'location_id': location_id, |
||||
|
'inventory_quantity': self.pack_quantity, |
||||
|
}) |
||||
|
|
||||
|
@api.onchange('pack_location_id') |
||||
|
def _onchange_pack_location_id(self): |
||||
|
"""It is to change the available quantity based on location.""" |
||||
|
for line in self.pack_products_ids: |
||||
|
stock_quant = self.env['stock.quant'].search( |
||||
|
[('product_id', '=', line.product_id.id), |
||||
|
('location_id', '=', self.pack_location_id.id)]) |
||||
|
if stock_quant: |
||||
|
line.total_available_quantity = stock_quant.quantity |
||||
|
else: |
||||
|
line.total_available_quantity = stock_quant.quantity |
@ -0,0 +1,90 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class ResConfigSettings(models.TransientModel): |
||||
|
""" This is to add new fields to the settings.res.config.settings is |
||||
|
inherited.""" |
||||
|
_inherit = 'res.config.settings' |
||||
|
|
||||
|
show_product_image_in_sale_report = fields.Boolean( |
||||
|
string="Show Product Image", default=False, |
||||
|
help="Enable Show Product Image") |
||||
|
sale_document_approve = fields.Boolean( |
||||
|
config_parameter='all_in_one_sales_kit.sale_document_approve', |
||||
|
string="Sale Document Approval", |
||||
|
help="Sale Approval") |
||||
|
product_restriction = fields.Boolean( |
||||
|
string='Out Of Stock Product Restriction', |
||||
|
help='Enable Out Of Stock Product Restriction') |
||||
|
check_stock = fields.Selection( |
||||
|
[('on_hand_quantity', 'On Hand Quantity'), |
||||
|
('forecast_quantity', 'Forecast Quantity')], string="Based On", |
||||
|
help='Choose the type of restriction') |
||||
|
automate_invoice = fields.Boolean( |
||||
|
string='Create Invoice', default=False, |
||||
|
help="Create invoices for sales order") |
||||
|
automate_validate_invoice = fields.Boolean( |
||||
|
string='Validate Invoice', default=False, |
||||
|
help="Automate validation of invoice") |
||||
|
automate_print_invoices = fields.Boolean( |
||||
|
string='Print Invoices', default=False, |
||||
|
help="Print invoice from corresponding sales order") |
||||
|
|
||||
|
@api.model |
||||
|
def set_values(self): |
||||
|
"""The function set_values() is to store the new fields values.""" |
||||
|
self.env['ir.config_parameter'].sudo().set_param( |
||||
|
'sale_product_image.show_product_image_in_sale_report', |
||||
|
self.show_product_image_in_sale_report) |
||||
|
self.env['ir.config_parameter'].sudo().set_param( |
||||
|
'sale_stock_restrict.product_restriction', |
||||
|
self.product_restriction) |
||||
|
self.env['ir.config_parameter'].sudo().set_param( |
||||
|
'sale_stock_restrict.check_stock', self.check_stock) |
||||
|
self.env['ir.config_parameter'].sudo().set_param( |
||||
|
'automate_print_invoices', self.automate_print_invoices) |
||||
|
self.env['ir.config_parameter'].sudo().set_param( |
||||
|
'automate_invoice', self.automate_invoice) |
||||
|
self.env['ir.config_parameter'].sudo().set_param( |
||||
|
'automate_validate_invoice', self.automate_validate_invoice) |
||||
|
res = super(ResConfigSettings, self).set_values() |
||||
|
return res |
||||
|
|
||||
|
def get_values(self): |
||||
|
"""Show the new field values.""" |
||||
|
res = super(ResConfigSettings, self).get_values() |
||||
|
ir_config_param = self.env['ir.config_parameter'].sudo().get_param |
||||
|
res.update( |
||||
|
show_product_image_in_sale_report=ir_config_param( |
||||
|
'sale_product_image.show_product_image_in_sale_report', |
||||
|
self.show_product_image_in_sale_report), |
||||
|
product_restriction=ir_config_param( |
||||
|
'sale_stock_restrict.product_restriction'), |
||||
|
check_stock=ir_config_param('sale_stock_restrict.check_stock'), |
||||
|
automate_print_invoices=ir_config_param('automate_print_invoices'), |
||||
|
automate_invoice=ir_config_param('automate_invoice'), |
||||
|
automate_validate_invoice=ir_config_param( |
||||
|
'automate_validate_invoice'), |
||||
|
) |
||||
|
return res |
@ -0,0 +1,40 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import models |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
"""res.partner is inherited.""" |
||||
|
_inherit = 'res.partner' |
||||
|
|
||||
|
def action_view_sale_order(self): |
||||
|
"""This is to add a new pivot view to customer to show |
||||
|
their sale orders.""" |
||||
|
action = self.env['ir.actions.act_window']._for_xml_id( |
||||
|
'sale.act_res_partner_2_sale_order') |
||||
|
all_child = self.with_context(active_test=False).search( |
||||
|
[('id', 'child_of', self.ids)]) |
||||
|
action["domain"] = [("partner_id", "in", all_child.ids)] |
||||
|
action["view_mode"] = "tree,kanban,form,graph,pivot" |
||||
|
action["views"] = [(False, 'tree'), (False, 'kanban'), |
||||
|
(False, 'form'), (False, 'graph'), (False, 'pivot')] |
||||
|
return action |
@ -0,0 +1,35 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class ResUsers(models.Model): |
||||
|
"""Here res.users is inherited to add two fields.""" |
||||
|
|
||||
|
_inherit = 'res.users' |
||||
|
|
||||
|
discount_control = fields.Boolean( |
||||
|
string='Discount Control', default=False, |
||||
|
help="Enable to set a discount limit value.") |
||||
|
allow_discount = fields.Float( |
||||
|
string='Allow Discount', |
||||
|
help="Enter the discount limit in percentage here.") |
@ -0,0 +1,492 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
import itertools |
||||
|
from odoo import api, fields, models, _ |
||||
|
from odoo.exceptions import UserError |
||||
|
|
||||
|
|
||||
|
class SaleOrder(models.Model): |
||||
|
"""Inherits Sales""" |
||||
|
_inherit = "sale.order" |
||||
|
|
||||
|
is_version = fields.Boolean(string="Is Version", |
||||
|
help="For checking version or not") |
||||
|
version_count = fields.Integer(string="Sale Version Count", |
||||
|
compute='_compute_version_count', |
||||
|
help="Count of version created") |
||||
|
current_version_id = fields.Many2one("sale.order", |
||||
|
string="Current Version", |
||||
|
help="For creating versions") |
||||
|
version_ids = fields.One2many("sale.order", |
||||
|
string="Version", |
||||
|
inverse_name="current_version_id", |
||||
|
help="Versions created") |
||||
|
quotation_ref = fields.Char(string='Quotation Reference', |
||||
|
copy=False, readonly=True, tracking=True, |
||||
|
help="Quotation Reference") |
||||
|
state = fields.Selection( |
||||
|
selection_add=[('waiting_for_approval', 'Waiting For Approval'), |
||||
|
('sale',)]) |
||||
|
approval_user_id = fields.Many2one('res.users', |
||||
|
string='Discount Approved By', |
||||
|
help="Discount approving person.") |
||||
|
onhand_check = fields.Boolean(string='Enable OnHand', |
||||
|
help='To check whether it is based on' |
||||
|
' on hand quantity') |
||||
|
forecast_check = fields.Boolean(string='Enable Forecast', |
||||
|
help='To check whether it is based on' |
||||
|
' Forecast quantity') |
||||
|
automate_print_invoices = fields.Boolean( |
||||
|
string='Print Invoices', |
||||
|
help="Print invoices for corresponding sale orders") |
||||
|
signature = fields.Binary(string='Signature', |
||||
|
help="Field for adding " |
||||
|
"the signature of the " |
||||
|
"sales person") |
||||
|
check_signature = fields.Boolean(compute='_compute_check_signature', |
||||
|
help="To check signature approval is " |
||||
|
"needed") |
||||
|
settings_approval = fields.Boolean(compute='_compute_settings_approval', |
||||
|
help="To check signature approval is " |
||||
|
"enabled in settings") |
||||
|
active = fields.Boolean(string='Active', help='Active', default=True) |
||||
|
user_salesperson = fields.Boolean(string="User Salesperson", |
||||
|
compute="_compute_user_salesperson", |
||||
|
help="Check if user is salesperson") |
||||
|
|
||||
|
@api.depends('user_salesperson') |
||||
|
def _compute_user_salesperson(self): |
||||
|
"""Computes the user_salesperson field based on login user""" |
||||
|
for rec in self: |
||||
|
if rec.user_id == rec.env.user: |
||||
|
rec.user_salesperson = True |
||||
|
else: |
||||
|
rec.user_salesperson = False |
||||
|
|
||||
|
@api.depends('signature') |
||||
|
def _compute_check_signature(self): |
||||
|
"""In this function computes the value of |
||||
|
the boolean field check signature |
||||
|
which is used to hide/unhide the validate |
||||
|
button in the current document""" |
||||
|
if self.env['ir.config_parameter'].sudo().get_param( |
||||
|
'all_in_one_sales_kit.sale_document_approve'): |
||||
|
if self.signature: |
||||
|
self.check_signature = True |
||||
|
else: |
||||
|
self.check_signature = False |
||||
|
else: |
||||
|
self.check_signature = True |
||||
|
|
||||
|
def action_create_versions(self): |
||||
|
"""For creating the versions of the sale order""" |
||||
|
sale_order_copy_id = self.copy() |
||||
|
sale_order_copy_id.is_version = True |
||||
|
length = len(self.version_ids) |
||||
|
sale_order_copy_id.name = "%s-%s" % (self.name, str(length + 1)) |
||||
|
|
||||
|
self.write({'version_ids': [(4, sale_order_copy_id.id)]}) |
||||
|
|
||||
|
@api.depends('version_ids') |
||||
|
def _compute_version_count(self): |
||||
|
"""For calculating the number of versions created""" |
||||
|
for sale in self: |
||||
|
sale.version_count = len(sale.version_ids) |
||||
|
|
||||
|
@api.depends('partner_id') |
||||
|
def _compute_settings_approval(self): |
||||
|
"""Computes the settings_approval field based on settings field.""" |
||||
|
for rec in self: |
||||
|
if rec.env['ir.config_parameter'].sudo().get_param( |
||||
|
'all_in_one_sales_kit.sale_document_approve'): |
||||
|
rec.settings_approval = True |
||||
|
else: |
||||
|
rec.settings_approval = False |
||||
|
|
||||
|
def action_view_versions(self): |
||||
|
"""Action for viewing versions""" |
||||
|
action = { |
||||
|
"type": "ir.actions.act_window", |
||||
|
"view_mode": "kanban,tree,form", |
||||
|
"name": _("Sale Order Versions"), |
||||
|
"res_model": self._name, |
||||
|
"domain": [('id', 'in', self.version_ids.ids)], |
||||
|
"target": "current", |
||||
|
} |
||||
|
return action |
||||
|
|
||||
|
def action_confirm(self): |
||||
|
"""Override the confirm button of the sale order for cancelling the |
||||
|
other versions and making the current version main,also method for |
||||
|
confirming the sale order discount and sending mail for the approving |
||||
|
person if approval limit crossed.Super the method create to confirm |
||||
|
quotation, create and validate invoice""" |
||||
|
res = super().action_confirm() |
||||
|
automate_invoice = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'automate_invoice') |
||||
|
automate_print_invoices = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'automate_print_invoices') |
||||
|
automate_validate_invoice = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'automate_validate_invoice') |
||||
|
if automate_print_invoices: |
||||
|
self.automate_print_invoices = True |
||||
|
if automate_invoice: |
||||
|
self._create_invoices() |
||||
|
if automate_validate_invoice: |
||||
|
self.invoice_ids.action_post() |
||||
|
if not self.version_ids: |
||||
|
parent_sale = self.current_version_id |
||||
|
versions = parent_sale.mapped('version_ids').ids |
||||
|
if versions: |
||||
|
versions.append(parent_sale.id) |
||||
|
for version in parent_sale.version_ids: |
||||
|
if version.state == 'sale': |
||||
|
# Updating the version name into main version name and |
||||
|
# other versions state into cancel |
||||
|
version.current_version_id.update({'is_version': True, |
||||
|
'state': 'cancel'}) |
||||
|
version.update({'version_ids': versions, |
||||
|
"name": version.current_version_id.name, |
||||
|
'is_version': False}) |
||||
|
if version.state == 'draft': |
||||
|
version.update({'state': 'cancel'}) |
||||
|
else: |
||||
|
if self.state == 'sale': |
||||
|
for sale in self.version_ids: |
||||
|
sale.update({'state': 'cancel'}) |
||||
|
low_qty = ["Can't confirm the sale order due to: \n"] |
||||
|
for rec in self.order_line: |
||||
|
product_restriction = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'sale_stock_restrict.product_restriction') |
||||
|
check_stock = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'sale_stock_restrict.check_stock') |
||||
|
if product_restriction: |
||||
|
if rec.product_id.detailed_type == 'product': |
||||
|
if check_stock == 'on_hand_quantity': |
||||
|
if rec.product_uom_qty > rec.qty_available: |
||||
|
self.onhand_check = True |
||||
|
onhand_qty_list = "You have added %s units of %s" \ |
||||
|
" but you only have %s units" \ |
||||
|
" available.\n" % ( |
||||
|
rec.product_uom_qty, |
||||
|
rec.product_id.name, |
||||
|
rec.qty_available) |
||||
|
low_qty.append(onhand_qty_list) |
||||
|
|
||||
|
if check_stock == 'forecast_quantity': |
||||
|
if rec.product_uom_qty > rec.forecast_quantity: |
||||
|
self.forecast_check = True |
||||
|
forecast_qty_list = "You have added %s" \ |
||||
|
" units of %s but " \ |
||||
|
"you only have" \ |
||||
|
" %s units available.\n" % ( |
||||
|
rec.product_uom_qty, |
||||
|
rec.product_id.name, |
||||
|
rec.forecast_quantity) |
||||
|
low_qty.append(forecast_qty_list) |
||||
|
listToStr = ' '.join(map(str, low_qty)) |
||||
|
if self.onhand_check: |
||||
|
raise UserError(listToStr) |
||||
|
if self.forecast_check: |
||||
|
raise UserError(listToStr) |
||||
|
to_approve = False |
||||
|
discount_vals = self.order_line.mapped('discount') |
||||
|
approval_users = self.env.ref( |
||||
|
'all_in_one_sales_kit.group_approval_manager').users |
||||
|
user_discount = self.env.user.allow_discount |
||||
|
if self.env.user.discount_control == True: |
||||
|
for rec in discount_vals: |
||||
|
if rec > user_discount: |
||||
|
to_approve = True |
||||
|
break |
||||
|
if to_approve: |
||||
|
display_id = self.id |
||||
|
action_id = self.env.ref( |
||||
|
'sale.action_quotations_with_onboarding').id |
||||
|
base_url = self.env['ir.config_parameter'].sudo().get_param( |
||||
|
'web.base.url') |
||||
|
redirect_link = "/web#id=%s&cids=1&menu_id=178&action=%s" \ |
||||
|
"&model" \ |
||||
|
"=sale.order&view_type=form" % ( |
||||
|
display_id, action_id) |
||||
|
url = base_url + redirect_link |
||||
|
for user in approval_users: |
||||
|
mail_body = """ |
||||
|
<p>Hello,</p> |
||||
|
<p>New sale order '%s' |
||||
|
Created with Discount by '%s' |
||||
|
need your approval on it.</p> |
||||
|
<p>To Approve, Cancel Order, |
||||
|
Click on the Following |
||||
|
Link: |
||||
|
<a href='%s' style="display: inline-block; |
||||
|
padding: 10px; text-decoration: none; |
||||
|
font-size: 12px; |
||||
|
background-color: #875A7B; color: #fff; |
||||
|
border-radius: 5px;"> |
||||
|
<strong>Click Me</strong></a> |
||||
|
</p> |
||||
|
<p>Thank You.</p>""" % (self.name, |
||||
|
self.env.user.name, |
||||
|
url) |
||||
|
mail_values = { |
||||
|
'subject': "'%s' Discount Approval Request" % (self.name), |
||||
|
'body_html': mail_body, |
||||
|
'email_to': user.partner_id.email, |
||||
|
'model': 'sale.order', |
||||
|
} |
||||
|
mail_id = self.env['mail.mail'].sudo().create(mail_values) |
||||
|
mail_id.sudo().send() |
||||
|
self.state = 'waiting_for_approval' |
||||
|
for line in self.order_line: |
||||
|
if line.product_id.is_pack: |
||||
|
for record in line.product_id.pack_products_ids: |
||||
|
dest_loc = self.env.ref( |
||||
|
'stock.stock_location_customers').id |
||||
|
self.env['stock.move'].create({ |
||||
|
'name': record.product_id.name, |
||||
|
'product_id': record.product_id.id, |
||||
|
'product_uom_qty': |
||||
|
record.quantity * line.product_uom_qty, |
||||
|
'product_uom': record.product_id.uom_id.id, |
||||
|
'picking_id': self.picking_ids[0].id, |
||||
|
'location_id': |
||||
|
self.picking_ids.picking_type_id.default_location_src_id.id, |
||||
|
'location_dest_id': dest_loc, |
||||
|
}) |
||||
|
return res |
||||
|
|
||||
|
@api.model |
||||
|
def create(self, vals): |
||||
|
"""Method for generating sequence for quotation """ |
||||
|
res = super(SaleOrder, self).create(vals) |
||||
|
seq_val = self.env.ref( |
||||
|
'all_in_one_sales_kit.seq_quotation').id |
||||
|
res.quotation_ref = self.env['ir.sequence'].browse( |
||||
|
seq_val).next_by_id() |
||||
|
return res |
||||
|
|
||||
|
def action_waiting_approval(self): |
||||
|
"""Method for approving the sale order discount""" |
||||
|
self.approval_user_id = self.env.user.id |
||||
|
self.state = 'sale' |
||||
|
|
||||
|
def action_print_invoice(self): |
||||
|
"""Method to print invoice""" |
||||
|
data = self.invoice_ids |
||||
|
return self.env.ref('account.account_invoices').report_action(data) |
||||
|
|
||||
|
@api.model |
||||
|
def get_data(self): |
||||
|
"""To get data to the sales dashboard.""" |
||||
|
domain = [('user_id', '=', self.env.user.id)] |
||||
|
quotation = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'draft')]) |
||||
|
my_sale_order_templates = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sale')]) |
||||
|
quotation_sent = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sent')]) |
||||
|
quotation_cancel = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'cancel')]) |
||||
|
customers = self.env['res.partner'].search([]) |
||||
|
to_invoice = self.env['sale.order'].search( |
||||
|
domain + [('invoice_status', '=', 'to invoice')]) |
||||
|
products = self.env['product.template'].search([]) |
||||
|
return { |
||||
|
'quotation': len(quotation), |
||||
|
'my_sale_order_templates': len(my_sale_order_templates), |
||||
|
'quotation_sent': len(quotation_sent), |
||||
|
'quotation_cancel': len(quotation_cancel), |
||||
|
'customers': len(customers), |
||||
|
'products': len(products), |
||||
|
'to_invoice': len(to_invoice), |
||||
|
} |
||||
|
|
||||
|
@api.model |
||||
|
def get_value(self, start_date, end_date): |
||||
|
"""It is to pass values according to start and end date to the |
||||
|
dashboard.""" |
||||
|
domain = [('user_id', '=', self.env.user.id), |
||||
|
('date_order', '>=', start_date), |
||||
|
('date_order', '<=', end_date)] |
||||
|
if start_date and end_date: |
||||
|
quotation = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'draft')]) |
||||
|
my_sale_order_templates = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sale')]) |
||||
|
quotation_sent = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sent')]) |
||||
|
quotation_cancel = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'cancel')]) |
||||
|
customers = self.env['res.partner'].search([]) |
||||
|
products = self.env['product.template'].search([]) |
||||
|
to_invoice = self.env['sale.order'].search( |
||||
|
domain + [('invoice_status', '=', 'to invoice')]) |
||||
|
elif start_date: |
||||
|
quotation = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'draft')]) |
||||
|
my_sale_order_templates = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sale')]) |
||||
|
quotation_sent = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sent')]) |
||||
|
quotation_cancel = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'cancel')]) |
||||
|
customers = self.env['res.partner'].search([]) |
||||
|
products = self.env['product.template'].search([]) |
||||
|
to_invoice = self.env['sale.order'].search( |
||||
|
domain + [('invoice_status', '=', 'to invoice')]) |
||||
|
elif end_date: |
||||
|
quotation = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'draft')]) |
||||
|
my_sale_order_templates = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sale')]) |
||||
|
quotation_sent = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'sent')]) |
||||
|
quotation_cancel = self.env['sale.order'].search( |
||||
|
domain + [('state', '=', 'cancel')]) |
||||
|
customers = self.env['res.partner'].search([]) |
||||
|
products = self.env['product.template'].search([]) |
||||
|
to_invoice = self.env['sale.order'].search( |
||||
|
domain + [('invoice_status', '=', 'to invoice')]) |
||||
|
return { |
||||
|
'quotation': len(quotation), |
||||
|
'my_sale_order_templates': len(my_sale_order_templates), |
||||
|
'quotation_sent': len(quotation_sent), |
||||
|
'quotation_cancel': len(quotation_cancel), |
||||
|
'customers': len(customers), |
||||
|
'products': len(products), |
||||
|
'to_invoice': len(to_invoice), |
||||
|
} |
||||
|
|
||||
|
@api.model |
||||
|
def get_lead_customer(self): |
||||
|
"""Returns customer data to the graph of dashboard""" |
||||
|
lead_template = {} |
||||
|
sale = {} |
||||
|
partner_id = self.env['res.partner'].sudo().search([]) |
||||
|
vals = self.env['sale.order'].sudo().search([ |
||||
|
]).mapped('partner_id').ids |
||||
|
for record in partner_id: |
||||
|
if record.id in vals: |
||||
|
record.ref = vals.count(record.id) |
||||
|
sale.update({record: vals.count(record.id)}) |
||||
|
sort = dict( |
||||
|
sorted(sale.items(), key=lambda item: item[1], reverse=True)) |
||||
|
out = dict(itertools.islice(sort.items(), 10)) |
||||
|
for count in out: |
||||
|
lead_template[count.name] = out[count] |
||||
|
return { |
||||
|
'lead_templates': lead_template, |
||||
|
} |
||||
|
|
||||
|
@api.model |
||||
|
def get_lead_product(self): |
||||
|
"""Returns product data to the graph of dashboard""" |
||||
|
lead_template = {} |
||||
|
sale = {} |
||||
|
product_id = self.env['product.template'].search([]) |
||||
|
for record in product_id: |
||||
|
sale.update({record: record.sales_count}) |
||||
|
sort = dict( |
||||
|
sorted(sale.items(), key=lambda item: item[1], reverse=True)) |
||||
|
out = dict(itertools.islice(sort.items(), 10)) |
||||
|
for product in out: |
||||
|
lead_template[product.name] = out[product] |
||||
|
return { |
||||
|
'lead_templates': lead_template, |
||||
|
} |
||||
|
|
||||
|
@api.model |
||||
|
def get_lead_order(self): |
||||
|
"""Returns lead sale order data to the graph of dashboard""" |
||||
|
lead_template = {} |
||||
|
sale = {} |
||||
|
order_id = self.env['sale.order'].search([('state', '=', 'sale')]) |
||||
|
for record in order_id: |
||||
|
sale.update({record: record.amount_total}) |
||||
|
sort = dict( |
||||
|
sorted(sale.items(), key=lambda item: item[1], reverse=True)) |
||||
|
out = dict(itertools.islice(sort.items(), 10)) |
||||
|
for order in out: |
||||
|
lead_template[order.name] = out[order] |
||||
|
return { |
||||
|
'lead_templates': lead_template, |
||||
|
} |
||||
|
|
||||
|
@api.model |
||||
|
def get_my_monthly_comparison(self): |
||||
|
"""Returns my monthly sale count data to the graph of dashboard""" |
||||
|
lead_template = {} |
||||
|
sales_order = self.env['sale.order'].search( |
||||
|
[('user_id', '=', self.env.user.id)]) |
||||
|
list = [rec.date_order.month for rec in sales_order] |
||||
|
for i in range(1, 13): |
||||
|
count = list.count(i) |
||||
|
lead_template.update({ |
||||
|
i: count |
||||
|
}) |
||||
|
return { |
||||
|
'lead_templates': lead_template, |
||||
|
} |
||||
|
|
||||
|
@api.model |
||||
|
def get_sales_team(self): |
||||
|
"""Returns sales team data to the graph of dashboard""" |
||||
|
lead_template = {} |
||||
|
sale = {} |
||||
|
sales_team = self.env['crm.team'].search([]) |
||||
|
for record in sales_team: |
||||
|
total = sum(self.env['sale.order'].search( |
||||
|
[('state', '=', 'sale'), |
||||
|
('team_id', '=', record.id)]).mapped('amount_total')) |
||||
|
sale.update({record: total}) |
||||
|
sort = dict( |
||||
|
sorted(sale.items(), key=lambda item: item[1], reverse=True)) |
||||
|
out = dict(itertools.islice(sort.items(), 10)) |
||||
|
for team in out: |
||||
|
lead_template[team.name] = out[team] |
||||
|
return { |
||||
|
'lead_templates': lead_template, |
||||
|
} |
||||
|
|
||||
|
@api.model |
||||
|
def get_least_sold(self): |
||||
|
"""Returns least sold product data to the graph of dashboard""" |
||||
|
lead_template = {} |
||||
|
sale = {} |
||||
|
product_id = self.env['product.template'].search([]) |
||||
|
for record in product_id: |
||||
|
if record.sales_count != 0: |
||||
|
sale.update({record: record.sales_count}) |
||||
|
sort = dict( |
||||
|
sorted(sale.items(), key=lambda item: item[1], reverse=False)) |
||||
|
out = dict(itertools.islice(sort.items(), 10)) |
||||
|
for product in out: |
||||
|
lead_template[product.name] = out[product] |
||||
|
return { |
||||
|
'lead_templates': lead_template, |
||||
|
} |
@ -0,0 +1,201 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import api, fields, models, _ |
||||
|
from odoo.tools import float_compare |
||||
|
|
||||
|
|
||||
|
class SaleOrderLine(models.Model): |
||||
|
"""Inherits sale.order.line.""" |
||||
|
_inherit = 'sale.order.line' |
||||
|
|
||||
|
sale_date = fields.Datetime(comodel_name='sale.order', string='Sale Date', |
||||
|
related='order_id.date_order', store=True, |
||||
|
help="Sale order date") |
||||
|
product_warehouse_id = fields.Many2one( |
||||
|
'stock.warehouse', |
||||
|
string='Warehouse', help='Warehouses') |
||||
|
order_line_image = fields.Binary(string="Image", |
||||
|
related="product_id.image_1920", |
||||
|
help="Product image should be shown or " |
||||
|
"not.") |
||||
|
contact_email = fields.Char(string="Email", |
||||
|
related="order_partner_id.email", |
||||
|
help="Email of the customer.") |
||||
|
contact_phone = fields.Char(string="Phone no.", |
||||
|
related="order_partner_id.phone", |
||||
|
help="Phone no. of the customer.") |
||||
|
qty_available = fields.Float(string="On Hand Quantity", |
||||
|
help='Count of On Hand quantity') |
||||
|
forecast_quantity = fields.Float(string="Forecast Quantity", |
||||
|
help='Count of Forecast quantity') |
||||
|
discount = fields.Float(string='Discount (%)', |
||||
|
digits=(16, 2), default=0.0, |
||||
|
help="Discount in percentage.") |
||||
|
total_discount = fields.Float(string="Total Discount", |
||||
|
default=0.0, store=True, |
||||
|
help="Total Discount.") |
||||
|
barcode_scan = fields.Char(string='Product Barcode', |
||||
|
help="Here you can provide " |
||||
|
"the barcode for the product") |
||||
|
|
||||
|
def action_get_product_form(self): |
||||
|
""" |
||||
|
This method returns an action that opens a form view for a specific product. |
||||
|
It sets the order partner ID based on the order's partner ID and constructs an action |
||||
|
to open the product's form view with the product's details. |
||||
|
:return: Dictionary representing an action to open the product's form view. |
||||
|
:rtype: dict |
||||
|
""" |
||||
|
self.product_id.order_partner_id = self.order_id.partner_id.id |
||||
|
return { |
||||
|
'name': self.product_id.name, |
||||
|
'view_mode': 'form', |
||||
|
'res_model': 'product.product', |
||||
|
'type': 'ir.actions.act_window', |
||||
|
'target': 'current', |
||||
|
'res_id': self.product_id.id |
||||
|
} |
||||
|
|
||||
|
def _action_launch_stock_rule(self, previous_product_uom_qty=False): |
||||
|
""" |
||||
|
Overwriting the function for adding functionalities of |
||||
|
multiple warehouses in the sale order line. |
||||
|
param previous_product_uom_qty(str): |
||||
|
Uom quantity of previous product |
||||
|
boolean: Returns True, if the picking created. |
||||
|
""" |
||||
|
if self._context.get("skip_procurement"): |
||||
|
return True |
||||
|
precision = self.env['decimal.precision'].precision_get( |
||||
|
'Product Unit of Measure') |
||||
|
procurements = [] |
||||
|
for line in self: |
||||
|
line = line.with_company(line.company_id) |
||||
|
if line.state != 'sale' or not line.product_id.type in ( |
||||
|
'consu', 'product'): |
||||
|
continue |
||||
|
qty = line._get_qty_procurement(previous_product_uom_qty) |
||||
|
if float_compare(qty, line.product_uom_qty, |
||||
|
precision_digits=precision) == 0: |
||||
|
continue |
||||
|
group_id = line._get_procurement_group() |
||||
|
if not group_id: |
||||
|
group_id = self.env['procurement.group'].create( |
||||
|
line._prepare_procurement_group_vals()) |
||||
|
line.order_id.procurement_group_id = group_id |
||||
|
else: |
||||
|
updated_vals = {} |
||||
|
if group_id.partner_id != line.order_id.partner_shipping_id: |
||||
|
updated_vals.update( |
||||
|
{'partner_id': line.order_id.partner_shipping_id.id}) |
||||
|
if group_id.move_type != line.order_id.picking_policy: |
||||
|
updated_vals.update( |
||||
|
{'move_type': line.order_id.picking_policy}) |
||||
|
if updated_vals: |
||||
|
group_id.write(updated_vals) |
||||
|
values = line._prepare_procurement_values(group_id=group_id) |
||||
|
#replacing default warehouse_id into product_warehouse_id in the |
||||
|
#sale order line and adding it into procurement values. |
||||
|
if line.product_warehouse_id: |
||||
|
values['warehouse_id'] = line.product_warehouse_id |
||||
|
product_qty = line.product_uom_qty - qty |
||||
|
line_uom = line.product_uom |
||||
|
quant_uom = line.product_id.uom_id |
||||
|
product_qty, procurement_uom = line_uom._adjust_uom_quantities( |
||||
|
product_qty, quant_uom) |
||||
|
procurements.append(self.env['procurement.group'].Procurement( |
||||
|
line.product_id, product_qty, procurement_uom, |
||||
|
line.order_id.partner_shipping_id.property_stock_customer, |
||||
|
line.product_id.display_name, line.order_id.name, |
||||
|
line.order_id.company_id, values)) |
||||
|
if procurements: |
||||
|
self.env['procurement.group'].run(procurements) |
||||
|
orders = self.mapped('order_id') |
||||
|
for order in orders: |
||||
|
pickings_to_confirm = order.picking_ids.filtered( |
||||
|
lambda p: p.state not in ['cancel', 'done']) |
||||
|
if pickings_to_confirm: |
||||
|
pickings_to_confirm.action_confirm() |
||||
|
return True |
||||
|
|
||||
|
@api.onchange('product_id') |
||||
|
def _onchange_product_id(self): |
||||
|
"""it is to check product stock according th the chosen product |
||||
|
restriction.""" |
||||
|
product_restriction = self.env['ir.config_parameter'].sudo().get_param( |
||||
|
'sale_stock_restrict.product_restriction') |
||||
|
check_stock = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'sale_stock_restrict.check_stock') |
||||
|
if product_restriction: |
||||
|
if check_stock == 'on_hand_quantity': |
||||
|
self.qty_available = self.product_id.qty_available |
||||
|
if check_stock == 'forecast_quantity': |
||||
|
self.forecast_quantity = self.product_id.virtual_available |
||||
|
|
||||
|
@api.onchange('barcode_scan') |
||||
|
def _onchange_barcode_scan(self): |
||||
|
"""It is to add the scanned products to the order line.""" |
||||
|
product_rec = self.env['product.product'] |
||||
|
if self.barcode_scan: |
||||
|
product = product_rec.search([('barcode', '=', self.barcode_scan)]) |
||||
|
self.product_id = product.id |
||||
|
|
||||
|
def action_get_product_history_data(self): |
||||
|
"""It is to pass previous history of the chosen product for that |
||||
|
customer.""" |
||||
|
values = [] |
||||
|
customer_id = self.order_id.partner_id |
||||
|
customer_order = self.env['sale.order'].search( |
||||
|
[('partner_id', '=', customer_id.id), ( |
||||
|
'state', 'in', ('sale', 'done'))]) |
||||
|
for order in customer_order: |
||||
|
for line in order.order_line: |
||||
|
if line.product_id == self.product_id: |
||||
|
values.append((0, 0, {'sale_order_id': order.id, |
||||
|
'history_price': line.price_unit, |
||||
|
'history_qty': line.product_uom_qty, |
||||
|
'history_total': order.amount_total |
||||
|
})) |
||||
|
history_id = self.env['product.sale.order.history'].create({ |
||||
|
'product_id': self.product_id.id, |
||||
|
'product_sale_history_ids': values |
||||
|
}) |
||||
|
return { |
||||
|
'name': 'Customer Product Sales History', |
||||
|
'view_mode': 'form', |
||||
|
'res_model': 'product.sale.order.history', |
||||
|
'type': 'ir.actions.act_window', |
||||
|
'target': 'new', |
||||
|
'res_id': history_id.id |
||||
|
} |
||||
|
|
||||
|
def action_add_catalog_control(self): |
||||
|
"""It is to add function to the button catalog.""" |
||||
|
return { |
||||
|
'type': 'ir.actions.act_window', |
||||
|
'name': _('Products'), |
||||
|
'context': {'order_id': self.env.context.get('id')}, |
||||
|
'res_model': 'product.product', |
||||
|
'view_mode': 'kanban,tree,form', |
||||
|
'target': 'current', |
||||
|
} |
@ -0,0 +1,540 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
import io |
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
try: |
||||
|
from odoo.tools.misc import xlsxwriter |
||||
|
except ImportError: |
||||
|
import xlsxwriter |
||||
|
|
||||
|
|
||||
|
class SalesReport(models.Model): |
||||
|
"""A new class sales.report is created.""" |
||||
|
_name = "sales.report" |
||||
|
_description = "Sales Report" |
||||
|
|
||||
|
sale_report = fields.Char(string="Sale Report", help="Sale Report") |
||||
|
date_from = fields.Datetime(string="Date From", |
||||
|
help="Date from which the report should be " |
||||
|
"viewed.") |
||||
|
date_to = fields.Datetime(string="Date to", |
||||
|
help="Date to which the report should be viewed.") |
||||
|
report_type = fields.Selection([ |
||||
|
('report_by_order', 'Report By Order'), |
||||
|
('report_by_order_detail', 'Report By Order Detail'), |
||||
|
('report_by_product', 'Report By Product'), |
||||
|
('report_by_categories', 'Report By Categories'), |
||||
|
('report_by_salesperson', 'Report By Sales Person'), |
||||
|
('report_by_state', 'Report By State')], default='report_by_order', |
||||
|
help="Report type", string="Report type") |
||||
|
|
||||
|
@api.model |
||||
|
def sale_report(self, option): |
||||
|
"""This is to pass values to the sales report.""" |
||||
|
report_values = self.env['sales.report'].browse(option[0]) |
||||
|
data = { |
||||
|
'report_type': report_values.report_type, |
||||
|
'model': self, |
||||
|
} |
||||
|
if report_values.date_from: |
||||
|
data.update({ |
||||
|
'date_from': report_values.date_from, |
||||
|
}) |
||||
|
if report_values.date_to: |
||||
|
data.update({ |
||||
|
'date_to': report_values.date_to, |
||||
|
}) |
||||
|
filters = self.get_filter(option) |
||||
|
lines = self._get_report_values(data).get('SALE') |
||||
|
main_line = self._get_report_values(data).get('sale_main') |
||||
|
return { |
||||
|
'name': "Sale Orders", |
||||
|
'type': 'ir.actions.client', |
||||
|
'tag': 's_r', |
||||
|
'orders': data, |
||||
|
'filters': filters, |
||||
|
'report_lines': lines, |
||||
|
'report_main_line': main_line, |
||||
|
} |
||||
|
|
||||
|
def get_filter(self, option): |
||||
|
"""It is to get value for the chosen filter.""" |
||||
|
data = self.get_filter_data(option) |
||||
|
filters = {} |
||||
|
if data.get('report_type') == 'report_by_order': |
||||
|
filters['report_type'] = 'Report By Order' |
||||
|
elif data.get('report_type') == 'report_by_order_detail': |
||||
|
filters['report_type'] = 'Report By Order Detail' |
||||
|
elif data.get('report_type') == 'report_by_product': |
||||
|
filters['report_type'] = 'Report By Product' |
||||
|
elif data.get('report_type') == 'report_by_categories': |
||||
|
filters['report_type'] = 'Report By Categories' |
||||
|
elif data.get('report_type') == 'report_by_salesperson': |
||||
|
filters['report_type'] = 'Report By Sales Person' |
||||
|
elif data.get('report_type') == 'report_by_state': |
||||
|
filters['report_type'] = 'Report By State' |
||||
|
else: |
||||
|
filters['report_type'] = 'report_by_order' |
||||
|
return filters |
||||
|
|
||||
|
def get_filter_data(self, option): |
||||
|
"""It is to get data according to the filter selected.""" |
||||
|
filter_dict = { |
||||
|
'report_type': self.env['sales.report'].browse( |
||||
|
option[0]).report_type, |
||||
|
} |
||||
|
return filter_dict |
||||
|
|
||||
|
@api.model |
||||
|
def create(self, vals): |
||||
|
"""It super create.""" |
||||
|
res = super(SalesReport, self).create(vals) |
||||
|
return res |
||||
|
|
||||
|
def write(self, vals): |
||||
|
"""It super write.""" |
||||
|
res = super(SalesReport, self).write(vals) |
||||
|
return res |
||||
|
|
||||
|
def _get_report_sub_lines(self, data): |
||||
|
"""This is to get the table lines according to the filter.""" |
||||
|
report_sub_lines = [] |
||||
|
if data.get('report_type') == 'report_by_order': |
||||
|
query = ''' |
||||
|
select so.id,so.name as number,so.date_order, |
||||
|
so.partner_id,so.amount_total, |
||||
|
so.user_id,res_partner.name as customer, |
||||
|
res_users.partner_id as user_partner,so.id as id, |
||||
|
sum(sale_order_line.product_uom_qty), |
||||
|
(SELECT res_partner.name as sales_man |
||||
|
FROM res_partner |
||||
|
WHERE res_partner.id = res_users.partner_id) |
||||
|
from sale_order as so |
||||
|
inner join res_partner |
||||
|
on so.partner_id = res_partner.id |
||||
|
inner join res_users |
||||
|
on so.user_id = res_users.id |
||||
|
inner join sale_order_line |
||||
|
on so.id = sale_order_line.order_id |
||||
|
''' |
||||
|
term = 'Where ' |
||||
|
if data.get('date_from'): |
||||
|
query += "Where so.date_order >= '%s' " % data.get('date_from') |
||||
|
term = 'AND ' |
||||
|
if data.get('date_to'): |
||||
|
query += term + "so.date_order <= '%s' " % data.get('date_to') |
||||
|
query += "group by so.user_id,res_users.partner_id," \ |
||||
|
"res_partner.name,so.partner_id,so.date_order," \ |
||||
|
"so.name,so.amount_total,so.id" |
||||
|
self._cr.execute(query) |
||||
|
report_by_order = self._cr.dictfetchall() |
||||
|
report_sub_lines.append(report_by_order) |
||||
|
elif data.get('report_type') == 'report_by_order_detail': |
||||
|
query = ''' |
||||
|
SELECT so.id,so.name as number,so.date_order, |
||||
|
res_partner.name as customer, |
||||
|
rc.name as company, |
||||
|
product_template.name as product, |
||||
|
product_product.default_code, |
||||
|
so_line.product_uom_qty, |
||||
|
so_line.price_subtotal,so.amount_total, |
||||
|
so.partner_id, |
||||
|
so.user_id,ru.id,so_line.product_id, |
||||
|
sum(so_line.product_uom_qty), |
||||
|
(SELECT res_partner.name as salesman |
||||
|
FROM res_partner |
||||
|
WHERE res_partner.id = res_users.partner_id) |
||||
|
from sale_order as so |
||||
|
inner join sale_order_line as so_line |
||||
|
on so.id = so_line.order_id |
||||
|
inner join product_product |
||||
|
ON so_line.product_id=product_product.id |
||||
|
inner join product_template |
||||
|
ON product_product.product_tmpl_id = |
||||
|
product_template.id |
||||
|
inner join res_partner |
||||
|
on so.partner_id=res_partner.id |
||||
|
inner join res_users on so.user_id = res_users.id |
||||
|
inner join res_company as rc on so.company_id=rc.id |
||||
|
inner join res_users as ru on so.user_id=ru.id |
||||
|
''' |
||||
|
term = 'Where ' |
||||
|
if data.get('date_from'): |
||||
|
query += "Where so.date_order >= '%s' " % data.get('date_from') |
||||
|
term = 'AND ' |
||||
|
if data.get('date_to'): |
||||
|
query += term + "so.date_order <= '%s' " % data.get('date_to') |
||||
|
query += ''' group by so.user_id, so.name, so.id,so.date_order, |
||||
|
res_partner.name,rc.name,product_template.name, |
||||
|
product_product.default_code,so_line.product_uom_qty, |
||||
|
so_line.price_subtotal,so.amount_total,so.partner_id, |
||||
|
so.user_id,ru.id,so_line.product_id, |
||||
|
res_users.partner_id |
||||
|
''' |
||||
|
self._cr.execute(query) |
||||
|
report_by_order_details = self._cr.dictfetchall() |
||||
|
report_sub_lines.append(report_by_order_details) |
||||
|
elif data.get('report_type') == 'report_by_product': |
||||
|
query = ''' |
||||
|
SELECT so.id,so.date_order, |
||||
|
product_template.name as product, |
||||
|
product_category.name as category, |
||||
|
product_product.default_code, |
||||
|
so_line.product_uom_qty, |
||||
|
so.amount_total,so.name as number |
||||
|
From sale_order as so |
||||
|
inner join sale_order_line |
||||
|
as so_line on so.id = so_line.order_id |
||||
|
inner join product_product |
||||
|
ON so_line.product_id=product_product.id |
||||
|
inner join product_template |
||||
|
ON product_product.product_tmpl_id = |
||||
|
product_template.id |
||||
|
inner join product_category |
||||
|
on product_category.id = product_template.categ_id |
||||
|
''' |
||||
|
term = 'Where ' |
||||
|
if data.get('date_from'): |
||||
|
query += "Where so.date_order >= '%s' " % data.get('date_from') |
||||
|
term = 'AND ' |
||||
|
if data.get('date_to'): |
||||
|
query += term + "so.date_order <= '%s' " % data.get('date_to') |
||||
|
query += "group by so.id,so.date_order,product_template.name," \ |
||||
|
"product_category.name,product_product.default_code," \ |
||||
|
"so_line.product_uom_qty" |
||||
|
self._cr.execute(query) |
||||
|
report_by_product = self._cr.dictfetchall() |
||||
|
report_sub_lines.append(report_by_product) |
||||
|
elif data.get('report_type') == 'report_by_categories': |
||||
|
query = ''' |
||||
|
select product_category.name, |
||||
|
sum(so_line.product_uom_qty) as qty, |
||||
|
sum(so_line.price_subtotal) as amount_total |
||||
|
from sale_order_line as so_line |
||||
|
inner join product_template |
||||
|
on so_line.product_id = product_template.id |
||||
|
inner join product_category |
||||
|
on product_category.id = product_template.categ_id |
||||
|
inner join sale_order |
||||
|
on so_line.order_id = sale_order.id |
||||
|
''' |
||||
|
term = 'Where ' |
||||
|
if data.get('date_from'): |
||||
|
query += "Where sale_order.date_order >= '%s' " % data.get( |
||||
|
'date_from') |
||||
|
term = 'AND ' |
||||
|
if data.get('date_to'): |
||||
|
query += term + "sale_order.date_order <= '%s' " % data.get( |
||||
|
'date_to') |
||||
|
query += "group by product_category.name" |
||||
|
self._cr.execute(query) |
||||
|
report_by_categories = self._cr.dictfetchall() |
||||
|
report_sub_lines.append(report_by_categories) |
||||
|
elif data.get('report_type') == 'report_by_salesperson': |
||||
|
query = ''' |
||||
|
select res_partner.name, |
||||
|
sum(sale_order_line.product_uom_qty) as qty, |
||||
|
sum(sale_order_line.price_subtotal) as amount, |
||||
|
count(so.id) as order |
||||
|
from sale_order as so |
||||
|
inner join res_users |
||||
|
on so.user_id = res_users.id |
||||
|
inner join res_partner |
||||
|
on res_users.partner_id = res_partner.id |
||||
|
inner join sale_order_line |
||||
|
on so.id = sale_order_line.order_id |
||||
|
''' |
||||
|
term = 'Where ' |
||||
|
if data.get('date_from'): |
||||
|
query += "Where so.date_order >= '%s' " % data.get('date_from') |
||||
|
term = 'AND ' |
||||
|
if data.get('date_to'): |
||||
|
query += term + "so.date_order <= '%s' " % data.get('date_to') |
||||
|
query += "group by res_partner.name" |
||||
|
self._cr.execute(query) |
||||
|
report_by_salesperson = self._cr.dictfetchall() |
||||
|
report_sub_lines.append(report_by_salesperson) |
||||
|
elif data.get('report_type') == 'report_by_state': |
||||
|
query = ''' |
||||
|
select so.state,count(so.id), |
||||
|
sum(sale_order_line.product_uom_qty) as qty, |
||||
|
sum(sale_order_line.price_subtotal) |
||||
|
as amount from sale_order as so |
||||
|
inner join sale_order_line |
||||
|
on so.id = sale_order_line.order_id |
||||
|
''' |
||||
|
term = 'Where ' |
||||
|
if data.get('date_from'): |
||||
|
query += "Where so.date_order >= '%s' " % data.get('date_from') |
||||
|
term = 'AND ' |
||||
|
if data.get('date_to'): |
||||
|
query += term + "so.date_order <= '%s' " % data.get('date_to') |
||||
|
query += "group by so.state" |
||||
|
self._cr.execute(query) |
||||
|
report_by_state = self._cr.dictfetchall() |
||||
|
report_sub_lines.append(report_by_state) |
||||
|
return report_sub_lines |
||||
|
|
||||
|
def _get_report_total_value(self, data, report): |
||||
|
"""It is to pass total for each report type.""" |
||||
|
report_main_lines = [] |
||||
|
if data.get('report_type') == 'report_by_order': |
||||
|
self._cr.execute(''' |
||||
|
select count(so.id) as order,sum(so.amount_total) as amount |
||||
|
from sale_order as so |
||||
|
''') |
||||
|
report_by_order = self._cr.dictfetchall() |
||||
|
report_main_lines.append(report_by_order) |
||||
|
elif data.get('report_type') == 'report_by_order_detail': |
||||
|
self._cr.execute(''' |
||||
|
select count(so_line.id) as order, |
||||
|
sum(so_line.price_subtotal) as total |
||||
|
from sale_order_line as so_line |
||||
|
''') |
||||
|
report_by_order_detail = self._cr.dictfetchall() |
||||
|
report_main_lines.append(report_by_order_detail) |
||||
|
elif data.get('report_type') == 'report_by_product': |
||||
|
self._cr.execute(''' |
||||
|
select count(so_line.product_id) as order, |
||||
|
sum(so_line.price_subtotal) as amount |
||||
|
from sale_order_line as so_line |
||||
|
''') |
||||
|
report_by_product = self._cr.dictfetchall() |
||||
|
report_main_lines.append(report_by_product) |
||||
|
else: |
||||
|
report_main_lines = False |
||||
|
return report_main_lines |
||||
|
|
||||
|
def _get_report_values(self, data): |
||||
|
"""It is to pass sublines for report.""" |
||||
|
docs = data['model'] |
||||
|
if data['report_type'] == 'report_by_order_detail': |
||||
|
report = ['Report By Order Detail'] |
||||
|
elif data['report_type'] == 'report_by_product': |
||||
|
report = ['Report By Product'] |
||||
|
elif data['report_type'] == 'report_by_categories': |
||||
|
report = ['Report By Categories'] |
||||
|
elif data['report_type'] == 'report_by_salesperson': |
||||
|
report = ['Report By Sales Person'] |
||||
|
elif data['report_type'] == 'report_by_state': |
||||
|
report = ['Report By State'] |
||||
|
else: |
||||
|
report = ['Report By Order'] |
||||
|
report_res_total = self._get_report_total_value(data, report) |
||||
|
if data.get('report_type'): |
||||
|
report_res = self._get_report_sub_lines(data)[0] |
||||
|
else: |
||||
|
report_res = self._get_report_sub_lines(data) |
||||
|
if data.get('report_type') == 'report_by_order': |
||||
|
report_res_total = self._get_report_total_value(data, report)[0] |
||||
|
return { |
||||
|
'doc_ids': self.ids, |
||||
|
'docs': docs, |
||||
|
'SALE': report_res, |
||||
|
'sale_main': report_res_total, |
||||
|
} |
||||
|
|
||||
|
def get_xlsx_report(self, data, response): |
||||
|
"""This function is to pass values to the xlsx report.""" |
||||
|
report_data_main = data['report_lines'] |
||||
|
output = io.BytesIO() |
||||
|
filters = data['filters'] |
||||
|
workbook = xlsxwriter.Workbook(output, {'in_memory': True}) |
||||
|
sheet = workbook.add_worksheet() |
||||
|
head = workbook.add_format({'align': 'center', 'bold': True, |
||||
|
'font_size': '20px'}) |
||||
|
heading = workbook.add_format( |
||||
|
{'align': 'center', 'bold': True, 'font_size': '10px', |
||||
|
'border': 2, |
||||
|
'border_color': 'black'}) |
||||
|
txt_l = workbook.add_format( |
||||
|
{'font_size': '10px', 'border': 1, 'bold': True}) |
||||
|
sheet.merge_range('A2:H3', |
||||
|
'Sales Report', |
||||
|
head) |
||||
|
if filters.get('report_type') == 'Report By Order': |
||||
|
sheet.merge_range('B5:D5', 'Report Type: ' + |
||||
|
filters.get('report_type'), txt_l) |
||||
|
sheet.write('A7', 'Sale', heading) |
||||
|
sheet.write('B7', 'Date Order', heading) |
||||
|
sheet.write('C7', 'Customer', heading) |
||||
|
sheet.write('D7', 'Sales Person', heading) |
||||
|
sheet.write('E7', 'Total Qty', heading) |
||||
|
sheet.write('F7', 'Amount Total', heading) |
||||
|
lst = [] |
||||
|
for rec in report_data_main[0]: |
||||
|
lst.append(rec) |
||||
|
row = 6 |
||||
|
col = 0 |
||||
|
sheet.set_column(3, 0, 15) |
||||
|
sheet.set_column(4, 1, 15) |
||||
|
sheet.set_column(5, 2, 15) |
||||
|
sheet.set_column(6, 3, 15) |
||||
|
sheet.set_column(7, 4, 15) |
||||
|
sheet.set_column(8, 5, 15) |
||||
|
for rec_data in report_data_main: |
||||
|
row += 1 |
||||
|
sheet.write(row, col, rec_data['number'], txt_l) |
||||
|
sheet.write(row, col + 1, rec_data['date_order'], txt_l) |
||||
|
sheet.write(row, col + 2, rec_data['customer'], txt_l) |
||||
|
sheet.write(row, col + 3, rec_data['sales_man'], txt_l) |
||||
|
sheet.write(row, col + 4, rec_data['sum'], txt_l) |
||||
|
sheet.write(row, col + 5, rec_data['amount_total'], txt_l) |
||||
|
if filters.get('report_type') == 'Report By Order Detail': |
||||
|
sheet.merge_range('B5:D5', 'Report Type: ' + |
||||
|
filters.get('report_type'), txt_l) |
||||
|
sheet.write('A7', 'Sale', heading) |
||||
|
sheet.write('B7', 'Date Order', heading) |
||||
|
sheet.write('C7', 'Customer', heading) |
||||
|
sheet.write('D7', 'Company', heading) |
||||
|
sheet.write('E7', 'Sales Person', heading) |
||||
|
sheet.write('F7', 'Product Name', heading) |
||||
|
sheet.write('G7', 'Product Code', heading) |
||||
|
sheet.write('H7', 'Quantity', heading) |
||||
|
sheet.write('I7', 'Price Subtotal', heading) |
||||
|
sheet.write('J7', 'Amount Total', heading) |
||||
|
lst = [] |
||||
|
for rec in report_data_main[0]: |
||||
|
lst.append(rec) |
||||
|
row = 6 |
||||
|
col = 0 |
||||
|
sheet.set_column(3, 0, 15) |
||||
|
sheet.set_column(4, 1, 15) |
||||
|
sheet.set_column(5, 2, 15) |
||||
|
sheet.set_column(6, 3, 15) |
||||
|
sheet.set_column(7, 4, 15) |
||||
|
sheet.set_column(8, 5, 15) |
||||
|
sheet.set_column(9, 6, 15) |
||||
|
sheet.set_column(10, 7, 15) |
||||
|
sheet.set_column(11, 8, 15) |
||||
|
sheet.set_column(12, 9, 15) |
||||
|
for rec_data in report_data_main: |
||||
|
row += 1 |
||||
|
product = [val for val in rec_data['product'].values()] |
||||
|
sheet.write(row, col, rec_data['number'], txt_l) |
||||
|
sheet.write(row, col + 1, rec_data['date_order'], txt_l) |
||||
|
sheet.write(row, col + 2, rec_data['customer'], txt_l) |
||||
|
sheet.write(row, col + 3, rec_data['company'], txt_l) |
||||
|
sheet.write(row, col + 4, rec_data['salesman'], txt_l) |
||||
|
sheet.write(row, col + 5, product[0], txt_l) |
||||
|
sheet.write(row, col + 6, rec_data['default_code'], txt_l) |
||||
|
sheet.write(row, col + 7, rec_data['product_uom_qty'], txt_l) |
||||
|
sheet.write(row, col + 8, rec_data['price_subtotal'], txt_l) |
||||
|
sheet.write(row, col + 9, rec_data['amount_total'], txt_l) |
||||
|
if filters.get('report_type') == 'Report By Product': |
||||
|
sheet.merge_range('B5:D5', 'Report Type: ' + |
||||
|
filters.get('report_type'), txt_l) |
||||
|
sheet.write('A7', 'Product', heading) |
||||
|
sheet.write('B7', 'Category', heading) |
||||
|
sheet.write('C7', 'Product Code', heading) |
||||
|
sheet.write('D7', 'Quantity', heading) |
||||
|
sheet.write('E7', 'Amount Total', heading) |
||||
|
lst = [] |
||||
|
for rec in report_data_main[0]: |
||||
|
lst.append(rec) |
||||
|
row = 6 |
||||
|
col = 0 |
||||
|
sheet.set_column(3, 0, 15) |
||||
|
sheet.set_column(4, 1, 15) |
||||
|
sheet.set_column(5, 2, 15) |
||||
|
sheet.set_column(6, 3, 15) |
||||
|
sheet.set_column(7, 4, 15) |
||||
|
for rec_data in report_data_main: |
||||
|
row += 1 |
||||
|
product = [val for val in rec_data['product'].values()] |
||||
|
sheet.write(row, col, product[0], txt_l) |
||||
|
sheet.write(row, col + 1, rec_data['category'], txt_l) |
||||
|
sheet.write(row, col + 2, rec_data['default_code'], txt_l) |
||||
|
sheet.write(row, col + 3, rec_data['product_uom_qty'], txt_l) |
||||
|
sheet.write(row, col + 4, rec_data['amount_total'], txt_l) |
||||
|
if filters.get('report_type') == 'Report By Categories': |
||||
|
sheet.merge_range('B5:D5', 'Report Type: ' + |
||||
|
filters.get('report_type'), txt_l) |
||||
|
sheet.write('B7', 'Category', heading) |
||||
|
sheet.write('C7', 'Qty', heading) |
||||
|
sheet.write('D7', 'Amount Total', heading) |
||||
|
lst = [] |
||||
|
for rec in report_data_main[0]: |
||||
|
lst.append(rec) |
||||
|
row = 6 |
||||
|
col = 1 |
||||
|
sheet.set_column(3, 1, 15) |
||||
|
sheet.set_column(4, 2, 15) |
||||
|
sheet.set_column(5, 3, 15) |
||||
|
for rec_data in report_data_main: |
||||
|
row += 1 |
||||
|
sheet.write(row, col, rec_data['name'], txt_l) |
||||
|
sheet.write(row, col + 1, rec_data['qty'], txt_l) |
||||
|
sheet.write(row, col + 2, rec_data['amount_total'], txt_l) |
||||
|
if filters.get('report_type') == 'Report By Sales Person': |
||||
|
sheet.merge_range('B5:D5', 'Report Type: ' + |
||||
|
filters.get('report_type'), txt_l) |
||||
|
sheet.write('A7', 'Sales Person', heading) |
||||
|
sheet.write('B7', 'Total Order', heading) |
||||
|
sheet.write('C7', 'Total Qty', heading) |
||||
|
sheet.write('D7', 'Total Amount', heading) |
||||
|
lst = [] |
||||
|
for rec in report_data_main[0]: |
||||
|
lst.append(rec) |
||||
|
row = 6 |
||||
|
col = 0 |
||||
|
sheet.set_column(3, 0, 15) |
||||
|
sheet.set_column(4, 1, 15) |
||||
|
sheet.set_column(5, 2, 15) |
||||
|
sheet.set_column(6, 3, 15) |
||||
|
for rec_data in report_data_main: |
||||
|
row += 1 |
||||
|
sheet.write(row, col, rec_data['name'], txt_l) |
||||
|
sheet.write(row, col + 1, rec_data['order'], txt_l) |
||||
|
sheet.write(row, col + 2, rec_data['qty'], txt_l) |
||||
|
sheet.write(row, col + 3, rec_data['amount'], txt_l) |
||||
|
if filters.get('report_type') == 'Report By State': |
||||
|
sheet.merge_range('B5:D5', 'Report Type: ' + |
||||
|
filters.get('report_type'), txt_l) |
||||
|
sheet.write('A7', 'State', heading) |
||||
|
sheet.write('B7', 'Total Count', heading) |
||||
|
sheet.write('C7', 'Quantity', heading) |
||||
|
sheet.write('D7', 'Amount', heading) |
||||
|
lst = [] |
||||
|
for rec in report_data_main[0]: |
||||
|
lst.append(rec) |
||||
|
row = 6 |
||||
|
col = 0 |
||||
|
sheet.set_column(3, 0, 15) |
||||
|
sheet.set_column(4, 1, 15) |
||||
|
sheet.set_column(5, 2, 15) |
||||
|
sheet.set_column(6, 3, 15) |
||||
|
for rec_data in report_data_main: |
||||
|
row += 1 |
||||
|
if rec_data['state'] == 'draft': |
||||
|
sheet.write(row, col, 'Quotation', txt_l) |
||||
|
elif rec_data['state'] == 'sent': |
||||
|
sheet.write(row, col, 'Quotation Sent', txt_l) |
||||
|
elif rec_data['state'] == 'sale': |
||||
|
sheet.write(row, col, 'Sale Order', txt_l) |
||||
|
sheet.write(row, col + 1, rec_data['count'], txt_l) |
||||
|
sheet.write(row, col + 2, rec_data['qty'], txt_l) |
||||
|
sheet.write(row, col + 3, rec_data['amount'], txt_l) |
||||
|
workbook.close() |
||||
|
output.seek(0) |
||||
|
response.stream.write(output.read()) |
||||
|
output.close() |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Swetha Anand (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import sale_order_report |
@ -0,0 +1,97 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for Invoice Analysis Report --> |
||||
|
<template id="invoice_analysis_view"> |
||||
|
<t t-call="web.html_container"> |
||||
|
<t t-call="web.external_layout"> |
||||
|
<t class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<center> |
||||
|
<b> |
||||
|
<h3>Invoice Analysis Report</h3> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-if="start_date and end_date"> |
||||
|
<center> |
||||
|
<span t-esc="start_date"/> |
||||
|
To |
||||
|
<span t-esc="end_date"/> |
||||
|
</center> |
||||
|
</t> |
||||
|
<t t-foreach="partner_id" t-as="partner"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="partner['name']"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<br/> |
||||
|
<t t-set="t_invoiced" t-value="0"/> |
||||
|
<t t-set="t_paid" t-value="0"/> |
||||
|
<t t-set="t_due" t-value="0"/> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order Number</th> |
||||
|
<th>Order Date</th> |
||||
|
<th>Invoice Number</th> |
||||
|
<th>Invoice Date</th> |
||||
|
<th>Amount Invoiced</th> |
||||
|
<th>Amount Paid</th> |
||||
|
<th>Amount Due</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['partner_id'] == partner['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['so']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['order_date']" |
||||
|
t-options='{"widget": "date"}'/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['invoice']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['invoiced']"/> |
||||
|
<t t-set="t_invoiced" |
||||
|
t-value="t_invoiced + order['invoiced']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['paid']"/> |
||||
|
<t t-set="t_paid" |
||||
|
t-value="t_paid + order['paid']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['due']"/> |
||||
|
<t t-set="t_due" |
||||
|
t-value="t_due + order['due']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<span>Total invoiced</span> |
||||
|
<t t-esc="t_invoiced"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total paid:</span> |
||||
|
<t t-esc="t_paid"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total due:</span> |
||||
|
<t t-esc="t_due"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,26 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- To inherit sale.report_saleorder_document --> |
||||
|
<template id="report_saleorder_inherit" |
||||
|
inherit_id="sale.report_saleorder_document"> |
||||
|
<xpath expr="//table[hasclass('o_main_table')]//tr/th[@name='th_quantity']" position="after"> |
||||
|
<t t-if="request.env['ir.config_parameter'].sudo().get_param( |
||||
|
'sale_product_image.show_product_image_in_sale_report')"> |
||||
|
<th> |
||||
|
<strong>Image</strong> |
||||
|
</th> |
||||
|
</t> |
||||
|
</xpath> |
||||
|
<xpath expr="//t[@t-foreach='lines_to_report']//td[@name='td_quantity']" |
||||
|
position="after"> |
||||
|
<t t-if="request.env['ir.config_parameter'].sudo().get_param( |
||||
|
'sale_product_image.show_product_image_in_sale_report')"> |
||||
|
<td style="height:20px !important;width:20px !important;"> |
||||
|
<span t-field="line.order_line_image" |
||||
|
t-options='{"widget": "image"}' |
||||
|
/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,42 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from odoo import api, models |
||||
|
|
||||
|
|
||||
|
class SaleOrderReport(models.AbstractModel): |
||||
|
"""It is to add new abstract model for sale_order_report.""" |
||||
|
_name = 'report.all_in_one_sales_kit.sale_order_report' |
||||
|
_description = "Sale Order Report" |
||||
|
|
||||
|
@api.model |
||||
|
def _get_report_values(self, docids, data=None): |
||||
|
"""It is to pass report values.""" |
||||
|
if self.env.context.get('sale_order_report'): |
||||
|
if data.get('report_data'): |
||||
|
report_lines = data.get('report_data')['report_lines'] |
||||
|
total_amount = sum( |
||||
|
line.get('amount_total', 0) for line in report_lines) |
||||
|
data.update({'report_main_line_data': report_lines, |
||||
|
'Filters': data.get('report_data')['filters'], |
||||
|
'company': self.env.company, |
||||
|
'total_amount': total_amount, |
||||
|
}) |
||||
|
return data |
@ -0,0 +1,397 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- To Show dynamic sale order report. --> |
||||
|
<template id="sale_order_report"> |
||||
|
<t t-call="web.html_container"> |
||||
|
<t t-call="web.internal_layout"> |
||||
|
<t t-if="Filters.get('report_type')=='Report By Order'"> |
||||
|
<t t-call="all_in_one_sales_kit.report_order"/> |
||||
|
</t> |
||||
|
<t t-if="Filters.get('report_type')=='Report By Order Detail'"> |
||||
|
<t t-call="all_in_one_sales_kit.report_order_detail"/> |
||||
|
</t> |
||||
|
<t t-if="Filters.get('report_type')=='Report By Product'"> |
||||
|
<t t-call="all_in_one_sales_kit.report_product"/> |
||||
|
</t> |
||||
|
<t t-if="Filters.get('report_type')=='Report By Categories'"> |
||||
|
<t t-call="all_in_one_sales_kit.report_category"/> |
||||
|
</t> |
||||
|
<t t-if="Filters.get('report_type')=='Report By Sales Person'"> |
||||
|
<t t-call="all_in_one_sales_kit.report_salesman"/> |
||||
|
</t> |
||||
|
<t t-if="Filters.get('report_type')=='Report By State'"> |
||||
|
<t t-call="all_in_one_sales_kit.report_state"/> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
||||
|
<template id="report_order"> |
||||
|
<div class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<span t-if="Filters.get('date_from')"> |
||||
|
<strong>From:</strong> |
||||
|
<t t-esc="Filters['date_from']"/> |
||||
|
</span> |
||||
|
<span t-if="Filters.get('date_to')"> |
||||
|
<strong>To:</strong> |
||||
|
<t t-esc="Filters['date_to']"/> |
||||
|
</span> |
||||
|
<div> |
||||
|
<div style="width:100%;"> |
||||
|
<div style="text-align:centre;" class="row"> |
||||
|
<div class="col-2"> |
||||
|
<strong>Report Type:</strong> |
||||
|
<t t-esc="Filters.get('report_type')"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br/> |
||||
|
<table class="table table-sm table-reports"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th class="text-left" colspan="6">Sale</th> |
||||
|
<th colspan="6" class="text-center">Date Order</th> |
||||
|
<th colspan="6" class="text-right">Customer</th> |
||||
|
<th colspan="6" class="text-right">Sales Person |
||||
|
</th> |
||||
|
<th colspan="6" class="text-center">Total Qty</th> |
||||
|
<th colspan="6" class="text-left">Amount Total</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="text-left"> |
||||
|
<t t-foreach="report_main_line_data" t-as="main"> |
||||
|
<tr style="font-weight: bold;"> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['number']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['date_order']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['customer']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['sales_man']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['sum']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['amount_total']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
<tr style="font-weight: bold;"> |
||||
|
<td colspan="6"/> |
||||
|
<td colspan="6"/> |
||||
|
<td colspan="6"/> |
||||
|
<td colspan="6"/> |
||||
|
<td colspan="6">Grand Total</td> |
||||
|
<td colspan="6"><span t-esc="total_amount"/></td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<br/> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template id="report_order_detail"> |
||||
|
<div class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<span t-if="Filters.get('date_from')"> |
||||
|
<strong>From:</strong> |
||||
|
<t t-esc="Filters['date_from']"/> |
||||
|
</span> |
||||
|
<span t-if="Filters.get('date_to')"> |
||||
|
<strong>To:</strong> |
||||
|
<t t-esc="Filters['date_to']"/> |
||||
|
</span> |
||||
|
<div> |
||||
|
<div style="width:100%;"> |
||||
|
<div style="text-align:centre;" class="row"> |
||||
|
<div class="col-2"> |
||||
|
<strong>Report Type:</strong> |
||||
|
<t t-esc="Filters.get('report_type')"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br/> |
||||
|
<table class="table table-sm table-reports"> |
||||
|
<thead> |
||||
|
<tr class="text-right"> |
||||
|
<th colspan="6">Sale</th> |
||||
|
<th colspan="6">Date Order</th> |
||||
|
<th colspan="6">Customer</th> |
||||
|
<th colspan="6">Company</th> |
||||
|
<th colspan="6">Sales Person</th> |
||||
|
<th colspan="6">Product Name</th> |
||||
|
<th colspan="6">Product Code</th> |
||||
|
<th colspan="6">Quantity</th> |
||||
|
<th colspan="6">Price Subtotal</th> |
||||
|
<th colspan="6">Amount Total</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<t t-foreach="report_main_line_data" t-as="main"> |
||||
|
<tr style="font-weight: bold;"> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['number']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['date_order']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['customer']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['company']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['salesman']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['product']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['default_code']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['product_uom_qty']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['price_subtotal']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['amount_total']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<br/> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template id="report_product"> |
||||
|
<div class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<span t-if="Filters.get('date_from')"> |
||||
|
<strong>From:</strong> |
||||
|
<t t-esc="Filters['date_from']"/> |
||||
|
</span> |
||||
|
<span t-if="Filters.get('date_to')"> |
||||
|
<strong>To:</strong> |
||||
|
<t t-esc="Filters['date_to']"/> |
||||
|
</span> |
||||
|
<div> |
||||
|
<div style="width:100%;"> |
||||
|
<div style="text-align:centre;" class="row"> |
||||
|
<div class="col-2"> |
||||
|
<strong>Report Type:</strong> |
||||
|
<t t-esc="Filters.get('report_type')"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br/> |
||||
|
<table class="table table-sm table-reports"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th class="text-left" colspan="6">Product</th> |
||||
|
<th colspan="6" class="text-center">Category</th> |
||||
|
<th colspan="6" class="text-center">Product Code |
||||
|
</th> |
||||
|
<th colspan="6" class="text-center">Quantity</th> |
||||
|
<th colspan="6">Amount Total</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<t t-foreach="report_main_line_data" t-as="main"> |
||||
|
<tr style="font-weight: bold;"> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['product']['en_US']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['category']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['default_code']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['product_uom_qty']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['amount_total']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<br/> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template id="report_category"> |
||||
|
<div class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<span t-if="Filters.get('date_from')"> |
||||
|
<strong>From:</strong> |
||||
|
<t t-esc="Filters['date_from']"/> |
||||
|
</span> |
||||
|
<span t-if="Filters.get('date_to')"> |
||||
|
<strong>To:</strong> |
||||
|
<t t-esc="Filters['date_to']"/> |
||||
|
</span> |
||||
|
<div> |
||||
|
<div style="width:100%;"> |
||||
|
<div style="text-align:centre;" class="row"> |
||||
|
<div class="col-2"> |
||||
|
<strong>Report Type:</strong> |
||||
|
<t t-esc="Filters.get('report_type')"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br/> |
||||
|
<table class="table table-sm table-reports"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th colspan="6">Category</th> |
||||
|
<th colspan="6">Qty</th> |
||||
|
<th colspan="6">Amount Total</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<t t-foreach="report_main_line_data" |
||||
|
t-as="sale_category"> |
||||
|
<tr style="font-weight: bold;"> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="sale_category['name']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="sale_category['qty']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="sale_category['amount_total']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<br/> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template id="report_salesman"> |
||||
|
<div class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<span t-if="Filters.get('date_from')"> |
||||
|
<strong>From:</strong> |
||||
|
<t t-esc="Filters['date_from']"/> |
||||
|
</span> |
||||
|
<span t-if="Filters.get('date_to')"> |
||||
|
<strong>To:</strong> |
||||
|
<t t-esc="Filters['date_to']"/> |
||||
|
</span> |
||||
|
<div> |
||||
|
<div style="width:100%;"> |
||||
|
<div style="text-align:centre;" class="row"> |
||||
|
<div class="col-2"> |
||||
|
<strong>Report Type:</strong> |
||||
|
<t t-esc="Filters.get('report_type')"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br/> |
||||
|
<table class="table table-sm table-reports"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Sales Person</th> |
||||
|
<th colspan="6">Total Order</th> |
||||
|
<th colspan="6">Total Qty</th> |
||||
|
<th colspan="6">Total Amount</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<t t-foreach="report_main_line_data" t-as="main"> |
||||
|
<tr style="font-weight: bold;"> |
||||
|
<td> |
||||
|
<span t-esc="main['name']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['order']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['qty']"/> |
||||
|
</td> |
||||
|
<td colspan="6"> |
||||
|
<span t-esc="main['amount']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<br/> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template id="report_state"> |
||||
|
<div class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<span t-if="Filters.get('date_from')"> |
||||
|
<strong>From:</strong> |
||||
|
<t t-esc="Filters['date_from']"/> |
||||
|
</span> |
||||
|
<span t-if="Filters.get('date_to')"> |
||||
|
<strong>To:</strong> |
||||
|
<t t-esc="Filters['date_to']"/> |
||||
|
</span> |
||||
|
<div> |
||||
|
<div style="width:100%;"> |
||||
|
<div style="text-align:centre;" class="row"> |
||||
|
<div class="col-2"> |
||||
|
<strong>Report Type:</strong> |
||||
|
<t t-esc="Filters.get('report_type')"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br/> |
||||
|
<table class="table table-sm table-reports"> |
||||
|
<thead> |
||||
|
<tr class="text-left"> |
||||
|
<th colspan="6">State</th> |
||||
|
<th colspan="6">Total Count</th> |
||||
|
<th colspan="6">Quantity</th> |
||||
|
<th colspan="6">Amount</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<t t-foreach="report_main_line_data" t-as="main"> |
||||
|
<tr style="font-weight: bold;"> |
||||
|
<td colspan="6"> |
||||
|
<t t-if="main['state'] == 'draft'"> |
||||
|
<span>Quotation</span> |
||||
|
</t> |
||||
|
<t t-if="main['state'] == 'sent'"> |
||||
|
<span>Quotation Sent</span> |
||||
|
</t> |
||||
|
<t t-if="main['state'] == 'sale'"> |
||||
|
<span>Sale Order</span> |
||||
|
</t> |
||||
|
</td> |
||||
|
<td colspan="6" class="text-left"> |
||||
|
<span t-esc="main['count']"/> |
||||
|
</td> |
||||
|
<td colspan="6" class="text-left"> |
||||
|
<span t-esc="main['qty']"/> |
||||
|
</td> |
||||
|
<td colspan="6" class="text-left"> |
||||
|
<span t-esc="main['amount']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<br/> |
||||
|
</div> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,353 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for Sales Profit Report --> |
||||
|
<template id="sale_profit_report_view"> |
||||
|
<t t-call="web.html_container"> |
||||
|
<t t-call="web.external_layout"> |
||||
|
<t class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<center> |
||||
|
<b> |
||||
|
<h3>Sales Profit Report</h3> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-if="start_date and end_date"> |
||||
|
<center> |
||||
|
<span t-esc="start_date"/> |
||||
|
To |
||||
|
<span t-esc="end_date"/> |
||||
|
</center> |
||||
|
</t> |
||||
|
<t t-if="type=='customer'"> |
||||
|
<t t-foreach="partner_id" t-as="partner"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="partner['name']"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-set="t_cost" t-value="0"/> |
||||
|
<t t-set="t_price" t-value="0"/> |
||||
|
<t t-set="t_profit" t-value="0"/> |
||||
|
<t t-set="t_margin" t-value="0"/> |
||||
|
<br/> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order</th> |
||||
|
<th>Date</th> |
||||
|
<th>Product</th> |
||||
|
<th>Quantity</th> |
||||
|
<th>Cost</th> |
||||
|
<th>Sale Price</th> |
||||
|
<th>Profit</th> |
||||
|
<th>Margin(%)</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['partner_id'] == partner['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['sequence']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']" |
||||
|
t-options='{"widget": "date"}'/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['product']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['quantity']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['cost']"/> |
||||
|
<t t-set="t_cost" |
||||
|
t-value="t_cost + order['cost']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['price']"/> |
||||
|
<t t-set="t_price" |
||||
|
t-value="t_price + order['price']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['profit']"/> |
||||
|
<t t-set="t_profit" |
||||
|
t-value="t_profit + order['profit']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['margin']"/> |
||||
|
<t t-set="t_margin" |
||||
|
t-value="t_margin + order['margin']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<span>Total cost</span> |
||||
|
<t t-esc="t_cost"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Price:</span> |
||||
|
<t t-esc="t_price"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Profit:</span> |
||||
|
<t t-esc="t_profit"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total margin:</span> |
||||
|
<t t-esc="t_margin"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
<t t-if="type=='product'"> |
||||
|
<t t-foreach="product_id" t-as="product"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="product['name']"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-set="t_cost" t-value="0"/> |
||||
|
<t t-set="t_price" t-value="0"/> |
||||
|
<t t-set="t_profit" t-value="0"/> |
||||
|
<t t-set="t_margin" t-value="0"/> |
||||
|
<br/> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order</th> |
||||
|
<th>Date</th> |
||||
|
<th>Customer</th> |
||||
|
<th>Quantity</th> |
||||
|
<th>Cost</th> |
||||
|
<th>Sale Price</th> |
||||
|
<th>Profit</th> |
||||
|
<th>Margin(%)</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['product_id'] == product['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['sequence']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']" |
||||
|
t-options='{"widget": "date"}'/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['partner']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['quantity']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['cost']"/> |
||||
|
<t t-set="t_cost" |
||||
|
t-value="t_cost + order['cost']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['price']"/> |
||||
|
<t t-set="t_price" |
||||
|
t-value="t_price + order['price']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['profit']"/> |
||||
|
<t t-set="t_profit" |
||||
|
t-value="t_profit + order['profit']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['margin']"/> |
||||
|
<t t-set="t_margin" |
||||
|
t-value="t_margin + order['margin']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<span>Total cost</span> |
||||
|
<t t-esc="t_cost"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Price:</span> |
||||
|
<t t-esc="t_price"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Profit:</span> |
||||
|
<t t-esc="t_profit"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total margin:</span> |
||||
|
<t t-esc="t_margin"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
<t t-if="type=='both'"> |
||||
|
<table class="table table-condensed"> |
||||
|
<t t-set="t_cost" t-value="0"/> |
||||
|
<t t-set="t_price" t-value="0"/> |
||||
|
<t t-set="t_profit" t-value="0"/> |
||||
|
<t t-set="t_margin" t-value="0"/> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order</th> |
||||
|
<th>Date</th> |
||||
|
<th>Customer</th> |
||||
|
<th>Product</th> |
||||
|
<th>Quantity</th> |
||||
|
<th>Cost</th> |
||||
|
<th>Sale Price</th> |
||||
|
<th>Profit</th> |
||||
|
<th>Margin(%)</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<td> |
||||
|
<span t-esc="order['sequence']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']" |
||||
|
t-options='{"widget": "date"}'/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['partner']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['product']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['quantity']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['cost']"/> |
||||
|
<t t-set="t_cost" |
||||
|
t-value="t_cost + order['cost']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['price']"/> |
||||
|
<t t-set="t_price" |
||||
|
t-value="t_price + order['price']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['profit']"/> |
||||
|
<t t-set="t_profit" |
||||
|
t-value="t_profit + order['profit']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['margin']"/> |
||||
|
<t t-set="t_margin" |
||||
|
t-value="t_margin + order['margin']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<span>Total cost</span> |
||||
|
<t t-esc="t_cost"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Price:</span> |
||||
|
<t t-esc="t_price"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Profit:</span> |
||||
|
<t t-esc="t_profit"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total margin:</span> |
||||
|
<t t-esc="t_margin"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
<t t-if="no_value == True"> |
||||
|
<table class="table table-condensed"> |
||||
|
<t t-set="t_cost" t-value="0"/> |
||||
|
<t t-set="t_price" t-value="0"/> |
||||
|
<t t-set="t_profit" t-value="0"/> |
||||
|
<t t-set="t_margin" t-value="0"/> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order</th> |
||||
|
<th>Date</th> |
||||
|
<th>Customer</th> |
||||
|
<th>Product</th> |
||||
|
<th>Quantity</th> |
||||
|
<th>Cost</th> |
||||
|
<th>Sale Price</th> |
||||
|
<th>Profit</th> |
||||
|
<th>Margin(%)</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<td> |
||||
|
<span t-esc="order['sequence']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']" |
||||
|
t-options='{"widget": "date"}'/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['partner']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['product']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['quantity']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['cost']"/> |
||||
|
<t t-set="t_cost" |
||||
|
t-value="t_cost + order['cost']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['price']"/> |
||||
|
<t t-set="t_price" |
||||
|
t-value="t_price + order['price']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['profit']"/> |
||||
|
<t t-set="t_profit" |
||||
|
t-value="t_profit + order['profit']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['margin']"/> |
||||
|
<t t-set="t_margin" |
||||
|
t-value="t_margin + order['margin']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<span>Total cost</span> |
||||
|
<t t-esc="t_cost"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Price:</span> |
||||
|
<t t-esc="t_price"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Profit:</span> |
||||
|
<t t-esc="t_profit"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total margin:</span> |
||||
|
<t t-esc="t_margin"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,59 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- It is to print Sale report --> |
||||
|
<record id="sale_report_action" model="ir.actions.report"> |
||||
|
<field name="name">Sales</field> |
||||
|
<field name="model">sale.report.advance</field> |
||||
|
<field name="report_type">qweb-pdf</field> |
||||
|
<field name="report_name">all_in_one_sales_kit.sale_profit_report_view</field> |
||||
|
<field name="report_file">all_in_one_sales_kit.sale_profit_report_view</field> |
||||
|
</record> |
||||
|
<!-- It is to print Invoice Analysis report --> |
||||
|
<record id="invoice_analysis_action" model="ir.actions.report"> |
||||
|
<field name="name">Invoice Analysis</field> |
||||
|
<field name="model">sale.report.invoice</field> |
||||
|
<field name="report_type">qweb-pdf</field> |
||||
|
<field name="report_name">all_in_one_sales_kit.invoice_analysis_view</field> |
||||
|
<field name="report_file">all_in_one_sales_kit.invoice_analysis_view</field> |
||||
|
</record> |
||||
|
<!-- It is to print Sales Category report --> |
||||
|
<record id="sale_category_action" model="ir.actions.report"> |
||||
|
<field name="name">Sales Category</field> |
||||
|
<field name="model">sale.report.category</field> |
||||
|
<field name="report_type">qweb-pdf</field> |
||||
|
<field name="report_name">all_in_one_sales_kit.sales_category_view</field> |
||||
|
<field name="report_file">all_in_one_sales_kit.sales_category_view</field> |
||||
|
</record> |
||||
|
<!-- It is to print Product Sales Indent report --> |
||||
|
<record id="sale_indent_action" model="ir.actions.report"> |
||||
|
<field name="name">Product Sales Indent</field> |
||||
|
<field name="model">sale.report.indent</field> |
||||
|
<field name="report_type">qweb-pdf</field> |
||||
|
<field name="report_name">all_in_one_sales_kit.sales_indent_view</field> |
||||
|
<field name="report_file">all_in_one_sales_kit.sales_indent_view</field> |
||||
|
</record> |
||||
|
<!-- It is to print Sales Analysis Report--> |
||||
|
<record id="sales_analysis_action" model="ir.actions.report"> |
||||
|
<field name="name">Sales Analysis Report</field> |
||||
|
<field name="model">sale.report.analysis</field> |
||||
|
<field name="report_type">qweb-pdf</field> |
||||
|
<field name="report_name">all_in_one_sales_kit.sales_analysis_view</field> |
||||
|
<field name="report_file">all_in_one_sales_kit.sales_analysis_view</field> |
||||
|
</record> |
||||
|
<!-- It is to print Hourly Sales Report --> |
||||
|
<record id="sales_weekly_action" model="ir.actions.report"> |
||||
|
<field name="name">Hourly Sales Report</field> |
||||
|
<field name="model">sale.report.weekly</field> |
||||
|
<field name="report_type">qweb-pdf</field> |
||||
|
<field name="report_name">all_in_one_sales_kit.sales_hourly_view</field> |
||||
|
<field name="report_file">all_in_one_sales_kit.sales_hourly_view</field> |
||||
|
</record> |
||||
|
<!-- It is to print Sales All In One Report --> |
||||
|
<record id="report_sale_all_in_one_action" model="ir.actions.report"> |
||||
|
<field name="name">Sales All In One Report</field> |
||||
|
<field name="model">sales.report</field> |
||||
|
<field name="report_type">qweb-pdf</field> |
||||
|
<field name="report_name">all_in_one_sales_kit.sale_order_report</field> |
||||
|
<field name="report_file">all_in_one_sales_kit.sale_order_report</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,173 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for Sales Analysis Report --> |
||||
|
<template id="sales_analysis_view"> |
||||
|
<t t-call="web.html_container"> |
||||
|
<t t-call="web.external_layout"> |
||||
|
<style> |
||||
|
</style> |
||||
|
<t class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<center> |
||||
|
<b> |
||||
|
<h3>Sales Analysis Report</h3> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-if="start_date and end_date"> |
||||
|
<center> |
||||
|
<span t-esc="start_date"/> |
||||
|
To |
||||
|
<span t-esc="end_date"/> |
||||
|
</center> |
||||
|
</t> |
||||
|
<t t-foreach="partner_id" t-as="partner"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="partner['name']" |
||||
|
style="font-size:22px;"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-if="type =='sale'"> |
||||
|
<t t-set="t_amt" t-value="0"/> |
||||
|
<t t-set="t_paid" t-value="0"/> |
||||
|
<t t-set="t_balance" t-value="0"/> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order Number</th> |
||||
|
<th>Order Date</th> |
||||
|
<th>Sales Person</th> |
||||
|
<th>Sales Amount</th> |
||||
|
<th>Amount Paid</th> |
||||
|
<th>Balance</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['partner_id'] == partner['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['so']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['sales_person']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['s_amt']"/> |
||||
|
<t t-set="t_amt" |
||||
|
t-value="t_amt + order['s_amt']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['p_amt']"/> |
||||
|
<t t-set="t_paid" |
||||
|
t-value="t_paid + order['p_amt']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['balance']"/> |
||||
|
<t t-set="t_balance" |
||||
|
t-value="t_balance + order['balance']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td colsapn="3"> |
||||
|
<span>Total Amount</span> |
||||
|
<t t-esc="t_amt"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Paid:</span> |
||||
|
<t t-esc="t_paid"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Balance:</span> |
||||
|
<t t-esc="t_balance"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
<t t-else=""> |
||||
|
<t t-set="t_total" t-value="0"/> |
||||
|
<t t-set="t_price" t-value="0"/> |
||||
|
<t t-set="t_disc" t-value="0"/> |
||||
|
<t t-set="t_qty" t-value="0"/> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order</th> |
||||
|
<th>Date</th> |
||||
|
<th>Product</th> |
||||
|
<th>Quantity</th> |
||||
|
<th>price</th> |
||||
|
<th>Discount(%)</th> |
||||
|
<th>Tax(%)</th> |
||||
|
<th>Subtotal</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['partner_id'] == partner['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['so']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['product_id']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['quantity']"/> |
||||
|
<t t-set="t_qty" |
||||
|
t-value="t_qty + order['quantity']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['price']"/> |
||||
|
<t t-set="t_price" |
||||
|
t-value="t_price + order['price']"/> |
||||
|
|
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['discount']"/> |
||||
|
<t t-set="t_disc" |
||||
|
t-value="t_disc + order['discount']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['tax']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['total']"/> |
||||
|
<t t-set="t_total" |
||||
|
t-value="t_total + order['total']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td colsapn="3"> |
||||
|
<span>Total Quantity</span> |
||||
|
<t t-esc="t_qty"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Price:</span> |
||||
|
<t t-esc="t_price"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Discount:</span> |
||||
|
<t t-esc="t_disc"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Subtotal</span> |
||||
|
<t t-esc="t_total"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,114 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for Sales category Report --> |
||||
|
<template id="sales_category_view"> |
||||
|
<t t-call="web.html_container"> |
||||
|
<t t-call="web.external_layout"> |
||||
|
<t class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<center> |
||||
|
<b> |
||||
|
<h3>Sales category Report</h3> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-if="start_date and end_date"> |
||||
|
<center> |
||||
|
<span t-esc="start_date"/> |
||||
|
To |
||||
|
<span t-esc="end_date"/> |
||||
|
</center> |
||||
|
</t> |
||||
|
<t t-if="categ_id"> |
||||
|
<t t-foreach="categ_id" t-as="categ"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="categ['name']"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<br/> |
||||
|
<t t-set="t_qty" t-value="0"/> |
||||
|
<t t-set="t_price" t-value="0"/> |
||||
|
<t t-set="t_total" t-value="0"/> |
||||
|
<t t-set="t_subtotal" t-value="0"/> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order</th> |
||||
|
<th>Date</th> |
||||
|
<th>Product</th> |
||||
|
<th>Quantity</th> |
||||
|
<th>UOM</th> |
||||
|
<th>Price</th> |
||||
|
<th>Tax(%)</th> |
||||
|
<th>Subtotal</th> |
||||
|
<th>Total</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['category_id'] == categ['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['so']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']" |
||||
|
t-options='{"widget": "date"}'/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['product_id']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['quantity']"/> |
||||
|
<t t-set="t_qty" |
||||
|
t-value="t_qty + order['quantity']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['uom']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['price']"/> |
||||
|
<t t-set="t_price" |
||||
|
t-value="t_price + order['price']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['tax']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['subtotal']"/> |
||||
|
<t t-set="t_subtotal" |
||||
|
t-value="t_subtotal + order['subtotal']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['total']"/> |
||||
|
<t t-set="t_total" |
||||
|
t-value="t_total + order['total']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td colsapn="3"> |
||||
|
<span>Total Quantity</span> |
||||
|
<t t-esc="t_qty"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Price:</span> |
||||
|
<t t-esc="t_price"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Subtotal:</span> |
||||
|
<t t-esc="t_subtotal"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span>Total Total:</span> |
||||
|
<t t-esc="t_total"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,61 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for Product Sales Indent Report --> |
||||
|
<template id="sales_indent_view"> |
||||
|
<t t-call="web.html_container"> |
||||
|
<t t-call="web.external_layout"> |
||||
|
<t class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<center> |
||||
|
<b> |
||||
|
<h3>Product Sales Indent Report</h3> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-if="start_date and end_date"> |
||||
|
<center> |
||||
|
<span t-esc="start_date"/> |
||||
|
To |
||||
|
<span t-esc="end_date"/> |
||||
|
</center> |
||||
|
</t> |
||||
|
<t t-foreach="partner_id" t-as="partner"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="partner['name']" |
||||
|
style="font-size:22px;"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-foreach="categ_id" t-as="categ"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="categ['name']" |
||||
|
style="font-size:17px;"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Product</th> |
||||
|
<th>Quantity</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['category_id'] == categ['id'] and order['partner_id'] == partner['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['product_id']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['quantity']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,68 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for Hourly Analysis Report --> |
||||
|
<template id="sales_hourly_view"> |
||||
|
<t t-call="web.html_container"> |
||||
|
<t t-call="web.external_layout"> |
||||
|
<style> |
||||
|
</style> |
||||
|
<t class="page"> |
||||
|
<div class="oe_structure"/> |
||||
|
<center> |
||||
|
<b> |
||||
|
<h3>Hourly Sales Report</h3> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-foreach="times" t-as="t"> |
||||
|
<center> |
||||
|
<b> |
||||
|
<span t-esc="t['name']" |
||||
|
style="font-size:21px;"/> |
||||
|
</b> |
||||
|
</center> |
||||
|
<t t-set="t_amt" t-value="0"/> |
||||
|
<table class="table table-condensed"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order Number</th> |
||||
|
<th>Order Date</th> |
||||
|
<t t-if="type=='untax'"> |
||||
|
<th>Untaxed Total</th> |
||||
|
</t> |
||||
|
<t t-else=""> |
||||
|
<th>Total</th> |
||||
|
</t> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr t-foreach="form" t-as="order"> |
||||
|
<t t-if="order['time'] == t['id']"> |
||||
|
<td> |
||||
|
<span t-esc="order['order']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['date']"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span t-esc="order['amount']"/> |
||||
|
<t t-set="t_amt" |
||||
|
t-value="t_amt + order['amount']"/> |
||||
|
</td> |
||||
|
</t> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td colsapn="3"> |
||||
|
<b> |
||||
|
<span>Total Amount</span> |
||||
|
</b> |
||||
|
<t t-esc="t_amt"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,18 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data noupdate="0"> |
||||
|
<!-- It is to set access for res.groups --> |
||||
|
<record id="module_sale_order_discount_approval" model="ir.module.category"> |
||||
|
<field name="name">Sale Order Discount Approval</field> |
||||
|
<field name="description">Category for Discount Approval</field> |
||||
|
</record> |
||||
|
<record id="group_approval_manager" model="res.groups"> |
||||
|
<field name="name">Discount Approval Manager</field> |
||||
|
<field name="category_id" |
||||
|
ref="module_sale_order_discount_approval"/> |
||||
|
</record> |
||||
|
<record id="group_add_sale_custom_fields" model="res.groups"> |
||||
|
<field name="name">Create Custom Fields in Sale</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</odoo> |
|
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 327 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 301 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 170 KiB |
After Width: | Height: | Size: 152 KiB |
After Width: | Height: | Size: 153 KiB |
After Width: | Height: | Size: 167 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 306 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 67 KiB |