| @ -0,0 +1,46 @@ | |||||
|  | .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg | ||||
|  |     :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html | ||||
|  |     :alt: License: AGPL-3 | ||||
|  | 
 | ||||
|  | All in One Inventory Kit | ||||
|  | ======================== | ||||
|  | This module helps to get so many features of modules related to inventory in a single module. | ||||
|  | 
 | ||||
|  | Configuration | ||||
|  | ============= | ||||
|  | No configuration needed. | ||||
|  | 
 | ||||
|  | License | ||||
|  | ------- | ||||
|  | General Public License, Version 3 (AGPL V3). | ||||
|  | (https://www.gnu.org/licenses/agpl-3.0-standalone.html) | ||||
|  | 
 | ||||
|  | Company | ||||
|  | ------- | ||||
|  | * `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | ||||
|  | 
 | ||||
|  | Credits | ||||
|  | ------- | ||||
|  | Developer: (V16) MOHAMMED DILSHAD TK @cybrosys, 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) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 reports | ||||
|  | from . import wizard | ||||
| @ -0,0 +1,85 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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': "All in One Inventory Kit", | ||||
|  |     'version': '16.0.1.0.0', | ||||
|  |     'category': 'Warehouse', | ||||
|  |     'summary': """Manage Multiple Inventory Features with One Module""", | ||||
|  |     'description': """ All in One Inventory Kit helps to get the features like | ||||
|  |                   Current Stock Report for all Products in each Warehouse, Add | ||||
|  |                   brands to products, Inventory Dashboard with all necessary  | ||||
|  |                   details, Avoid manual entry of item count in Stock Picking | ||||
|  |                   and Use barcode to add product, Invoice From Stock Picking,  | ||||
|  |                   All In One Report Generator,  Get product quantity reviews  | ||||
|  |                   for each stock location from the product form and Print PDF  | ||||
|  |                   report of them, Stock Picking From Customer Invoice and Stock | ||||
|  |                   Picking From Supplier bill, Order Line Description of Shipment | ||||
|  |                   and Delivery, Catch Weight of Stock, Incoming and Outgoing  | ||||
|  |                   Picking Operations Views are included with images of their  | ||||
|  |                   related products, Form, Tree, Kanban, Pivot, Graph and  | ||||
|  |                   Calendar views of Incoming and Outgoing Picking Operations""", | ||||
|  |     'author': 'Cybrosys Techno Solutions', | ||||
|  |     'company': 'Cybrosys Techno Solutions', | ||||
|  |     'maintainer': 'Cybrosys Techno Solutions', | ||||
|  |     'website': 'https://www.cybrosys.com', | ||||
|  |     'depends': ['sale_management', 'stock', 'purchase'], | ||||
|  |     'data': [ | ||||
|  |         'security/ir.model.access.csv', | ||||
|  |         'views/stock_move_line_views.xml', | ||||
|  |         'views/incoming_stock_move_line_views.xml', | ||||
|  |         'views/outgoing_stock_move_line_views.xml', | ||||
|  |         'views/product_brand_views.xml', | ||||
|  |         'views/dashboard_menu.xml', | ||||
|  |         'views/font_style.xml', | ||||
|  |         'views/stock_picking_views.xml', | ||||
|  |         'views/product_product_views.xml', | ||||
|  |         'views/stock_return_picking_views.xml', | ||||
|  |         'views/stock_scrap_views.xml', | ||||
|  |         'views/stock_valuation_layer_views.xml', | ||||
|  |         'views/product_template_views.xml', | ||||
|  |         'views/res_config_settings_views.xml', | ||||
|  |         'views/account_move_views.xml', | ||||
|  |         'reports/inventory_report.xml', | ||||
|  |         'reports/inventory_pdf_report.xml', | ||||
|  |         'reports/stock_picking_report.xml', | ||||
|  |         'reports/product_product_stock_report.xml', | ||||
|  |         'reports/product_stock_report_template.xml', | ||||
|  |         'wizard/wizard_stock_history_views.xml', | ||||
|  |         'wizard/picking_invoice_wizard_views.xml', | ||||
|  |     ], | ||||
|  |     'assets': { | ||||
|  |         'web.assets_backend': [ | ||||
|  |             'all_in_one_inventory_kit/static/src/js/action_manager.js', | ||||
|  |             'all_in_one_inventory_kit/static/src/js/inventory_report.js', | ||||
|  |             'all_in_one_inventory_kit/static/src/js/lib/Chart.bundle.js', | ||||
|  |             'all_in_one_inventory_kit/static/src/js/dashboard.js', | ||||
|  |             'all_in_one_inventory_kit/static/src/css/inventory_report.css', | ||||
|  |             'all_in_one_inventory_kit/static/src/css/dashboard.css', | ||||
|  |             'all_in_one_inventory_kit/static/src/xml/inventory_report_views.xml', | ||||
|  |             'all_in_one_inventory_kit/static/src/xml/dashboard.xml', | ||||
|  |         ], | ||||
|  |     }, | ||||
|  |     'images': ['static/description/banner.png'], | ||||
|  |     'license': 'AGPL-3', | ||||
|  |     'installable': True, | ||||
|  |     'auto_install': False, | ||||
|  |     'application': False | ||||
|  | } | ||||
| @ -0,0 +1,22 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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_report_excel | ||||
| @ -0,0 +1,63 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | import json | ||||
|  | from odoo import http | ||||
|  | from odoo.http import content_disposition, request, \ | ||||
|  |     serialize_exception as _serialize_exception | ||||
|  | from odoo.tools import html_escape | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class XLSXReportController(http.Controller): | ||||
|  |     """Controller for handling XLSX report generation and download in Odoo.""" | ||||
|  | 
 | ||||
|  |     @http.route('/xlsx_reports', type='http', auth='user', methods=['POST'], | ||||
|  |                 csrf=False) | ||||
|  |     def get_report_xlsx(self, model, options, output_format, report_name, | ||||
|  |                         report_data=None): | ||||
|  |         """Endpoint to generate and download an XLSX report.""" | ||||
|  |         uid = request.session.uid | ||||
|  |         report_obj = request.env[model].with_user(uid) | ||||
|  |         token = 'dummy-because-api-expects-one' | ||||
|  |         try: | ||||
|  |             if output_format == 'xlsx': | ||||
|  |                 response = request.make_response( | ||||
|  |                     None, | ||||
|  |                     headers=[ | ||||
|  |                         ('Content-Type', 'application/vnd.ms-excel'), | ||||
|  |                         ('Content-Disposition', | ||||
|  |                          content_disposition(report_name + '.xlsx')) | ||||
|  |                     ] | ||||
|  |                 ) | ||||
|  |                 try: | ||||
|  |                     report_obj.get_xlsx_report(options, response, report_data) | ||||
|  |                 except Exception: | ||||
|  |                     report_obj.get_xlsx_report(json.loads(options), response) | ||||
|  |                 response.set_cookie('fileToken', token) | ||||
|  |                 return response | ||||
|  |         except Exception as e: | ||||
|  |             se = _serialize_exception(e) | ||||
|  |             error = { | ||||
|  |                 'code': 200, | ||||
|  |                 'message': 'Odoo Server Error', | ||||
|  |                 'data': se | ||||
|  |             } | ||||
|  |             return request.make_response(html_escape(json.dumps(error))) | ||||
| @ -0,0 +1,6 @@ | |||||
|  | ## Module <all_in_one_inventory_kit> | ||||
|  | 
 | ||||
|  | #### 27.06.2024 | ||||
|  | #### Version 16.0.1.0.0 | ||||
|  | #### ADD | ||||
|  | - Initial commit for All in One Inventory Kit | ||||
| @ -0,0 +1,36 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 account_move | ||||
|  | from . import account_move_line | ||||
|  | from . import inventory_report | ||||
|  | from . import product_brand | ||||
|  | from . import product_product | ||||
|  | from . import product_template | ||||
|  | from . import res_config_settings | ||||
|  | from . import stock_move | ||||
|  | from . import stock_move_line | ||||
|  | from . import stock_picking | ||||
|  | from . import stock_picking_return_line | ||||
|  | from . import stock_quant | ||||
|  | from . import stock_return_picking | ||||
|  | from . import stock_scrap | ||||
|  | from . import stock_valuation_layer | ||||
| @ -0,0 +1,142 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 AccountMove(models.Model): | ||||
|  |     """Inherits Account Move""" | ||||
|  |     _inherit = 'account.move' | ||||
|  | 
 | ||||
|  |     picking_id = fields.Many2one('stock.picking', string='Picking', | ||||
|  |                                  help="picking type") | ||||
|  | 
 | ||||
|  |     def _get_stock_type_ids(self): | ||||
|  |         """Gets stock types""" | ||||
|  |         data = self.env['stock.picking.type'].search([]) | ||||
|  |         if self._context.get('default_move_type') == 'out_invoice': | ||||
|  |             for line in data: | ||||
|  |                 if line.code == 'outgoing': | ||||
|  |                     return line | ||||
|  |         if self._context.get('default_move_type') == 'in_invoice': | ||||
|  |             for line in data: | ||||
|  |                 if line.code == 'incoming': | ||||
|  |                     return line | ||||
|  | 
 | ||||
|  |     picking_count = fields.Integer(string="Count", copy=False, | ||||
|  |                                    help="Picking Count") | ||||
|  |     invoice_picking_id = fields.Many2one('stock.picking', | ||||
|  |                                          string="stock Pickings", | ||||
|  |                                          copy=False, help="Select a Stock " | ||||
|  |                                                           "picking") | ||||
|  |     picking_type_id = fields.Many2one('stock.picking.type', | ||||
|  |                                       string='Picking Type', | ||||
|  |                                       default=_get_stock_type_ids, | ||||
|  |                                       help="This will determine picking type" | ||||
|  |                                            " of incoming shipment") | ||||
|  |     state = fields.Selection([ | ||||
|  |         ('draft', 'Draft'), | ||||
|  |         ('proforma', 'Pro-forma'), | ||||
|  |         ('proforma2', 'Pro-forma'), | ||||
|  |         ('posted', 'Posted'), | ||||
|  |         ('post', 'Post'), | ||||
|  |         ('cancel', 'Cancelled'), | ||||
|  |         ('done', 'Received'), | ||||
|  |     ], string='Status', index=True, readonly=True, default='draft', | ||||
|  |         track_visibility='onchange', copy=False, help="States of the record") | ||||
|  |     transfer_created = fields.Boolean(string='Transfer Created') | ||||
|  | 
 | ||||
|  |     def action_stock_move(self): | ||||
|  |         """ Button action for Transfer """ | ||||
|  |         if not self.picking_type_id: | ||||
|  |             raise UserError(_( | ||||
|  |                 " Please select a picking type")) | ||||
|  |         for order in self: | ||||
|  |             if not self.invoice_picking_id: | ||||
|  |                 pick = {} | ||||
|  |                 if self.picking_type_id.code == 'outgoing': | ||||
|  |                     pick = { | ||||
|  |                         'picking_type_id': self.picking_type_id.id, | ||||
|  |                         'partner_id': self.partner_id.id, | ||||
|  |                         'origin': self.name, | ||||
|  |                         'location_dest_id': self.partner_id. | ||||
|  |                         property_stock_customer.id, | ||||
|  |                         'location_id': self.picking_type_id. | ||||
|  |                         default_location_src_id.id, | ||||
|  |                         'move_type': 'direct', | ||||
|  |                         'invoice_created': True | ||||
|  |                     } | ||||
|  |                 if self.picking_type_id.code == 'incoming': | ||||
|  |                     pick = { | ||||
|  |                         'picking_type_id': self.picking_type_id.id, | ||||
|  |                         'partner_id': self.partner_id.id, | ||||
|  |                         'origin': self.name, | ||||
|  |                         'location_dest_id': self.picking_type_id. | ||||
|  |                         default_location_dest_id.id, | ||||
|  |                         'location_id': self.partner_id. | ||||
|  |                         property_stock_supplier.id, | ||||
|  |                         'move_type': 'direct', | ||||
|  |                         'invoice_created': True | ||||
|  |                     } | ||||
|  |                 picking = self.env['stock.picking'].create(pick) | ||||
|  |                 self.invoice_picking_id = picking.id | ||||
|  |                 self.picking_count = len(picking) | ||||
|  |                 moves = order.invoice_line_ids.filtered( | ||||
|  |                     lambda r: r.product_id.type in ['product','consu']).\ | ||||
|  |                     _create_stock_moves(picking) | ||||
|  |                 move_ids = moves._action_confirm() | ||||
|  |                 move_ids._action_assign() | ||||
|  | 
 | ||||
|  |     def action_view_picking(self): | ||||
|  |         """ Shows corresponding picking in smart tab """ | ||||
|  |         action = self.env.ref('stock.action_picking_tree_ready') | ||||
|  |         result = action.read()[0] | ||||
|  |         result.pop('id', None) | ||||
|  |         result['context'] = {} | ||||
|  |         result['domain'] = [('id', '=', self.invoice_picking_id.id)] | ||||
|  |         pick_ids = sum([self.invoice_picking_id.id]) | ||||
|  |         if pick_ids: | ||||
|  |             res = self.env.ref('stock.view_picking_form', False) | ||||
|  |             result['views'] = [(res and res.id or False, 'form')] | ||||
|  |             result['res_id'] = pick_ids or False | ||||
|  |         return result | ||||
|  | 
 | ||||
|  |     def _reverse_moves(self, default_values_list=None, cancel=False): | ||||
|  |         """ Reverse a recordset of account.move. | ||||
|  |         If cancel parameter is true, the reconcilable or liquidity lines | ||||
|  |         of each original move will be reconciled with its reverse's. | ||||
|  |         :param default_values_list: A list of default values to consider per | ||||
|  |          move.('type' & 'reversed_entry_id' are computed in the method). | ||||
|  |         :return: An account move recordset, reverse of the current self. | ||||
|  |         """ | ||||
|  |         if self.picking_type_id.code == 'outgoing': | ||||
|  |             data = self.env['stock.picking.type'].search( | ||||
|  |                 [('company_id', '=', self.company_id.id), | ||||
|  |                  ('code', '=', 'incoming')], limit=1) | ||||
|  |             self.picking_type_id = data.id | ||||
|  |         elif self.picking_type_id.code == 'incoming': | ||||
|  |             data = self.env['stock.picking.type'].search( | ||||
|  |                 [('company_id', '=', self.company_id.id), | ||||
|  |                  ('code', '=', 'outgoing')], limit=1) | ||||
|  |             self.picking_type_id = data.id | ||||
|  |         reverse_moves = super(AccountMove, self)._reverse_moves() | ||||
|  |         return reverse_moves | ||||
| @ -0,0 +1,78 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 SupplierInvoiceLine(models.Model): | ||||
|  |     """ Inherits account.move.line """ | ||||
|  |     _inherit = 'account.move.line' | ||||
|  | 
 | ||||
|  |     def _create_stock_moves(self, picking): | ||||
|  |         """ Creating stock moves """ | ||||
|  |         moves = self.env['stock.move'] | ||||
|  |         done = self.env['stock.move'].browse() | ||||
|  |         for line in self: | ||||
|  |             price_unit = line.price_unit | ||||
|  |             if picking.picking_type_id.code == 'outgoing': | ||||
|  |                 template = { | ||||
|  |                     'name': line.name or '', | ||||
|  |                     'product_id': line.product_id.id, | ||||
|  |                     'product_uom': line.product_uom_id.id, | ||||
|  |                     'location_id': picking.picking_type_id. | ||||
|  |                     default_location_src_id.id, | ||||
|  |                     'location_dest_id': line.move_id.partner_id. | ||||
|  |                     property_stock_customer.id, | ||||
|  |                     'picking_id': picking.id, | ||||
|  |                     'state': 'draft', | ||||
|  |                     'company_id': line.move_id.company_id.id, | ||||
|  |                     'price_unit': price_unit, | ||||
|  |                     'picking_type_id': picking.picking_type_id.id, | ||||
|  |                     'route_ids': 1 and [ | ||||
|  |                         (6, 0, [x.id for x in self.env['stock.rule'].search( | ||||
|  |                             [('id', 'in', (2, 3))])])] or [], | ||||
|  |                     'warehouse_id': picking.picking_type_id.warehouse_id.id,} | ||||
|  |             if picking.picking_type_id.code == 'incoming': | ||||
|  |                 template = { | ||||
|  |                     'name': line.name or '', | ||||
|  |                     'product_id': line.product_id.id, | ||||
|  |                     'product_uom': line.product_uom_id.id, | ||||
|  |                     'location_id': line.move_id.partner_id. | ||||
|  |                     property_stock_supplier.id, | ||||
|  |                     'location_dest_id': picking.picking_type_id. | ||||
|  |                     default_location_dest_id.id, | ||||
|  |                     'picking_id': picking.id, | ||||
|  |                     'state': 'draft', | ||||
|  |                     'company_id': line.move_id.company_id.id, | ||||
|  |                     'price_unit': price_unit, | ||||
|  |                     'picking_type_id': picking.picking_type_id.id, | ||||
|  |                     'route_ids': 1 and [ | ||||
|  |                         (6, 0, [x.id for x in self.env['stock.rule'].search( | ||||
|  |                             [('id', 'in', (2, 3))])])] or [], | ||||
|  |                     'warehouse_id': picking.picking_type_id.warehouse_id.id,} | ||||
|  |             diff_quantity = line.quantity | ||||
|  |             tmp = template.copy() | ||||
|  |             tmp.update({ | ||||
|  |                 'product_uom_qty': diff_quantity, | ||||
|  |             }) | ||||
|  |             template['product_uom_qty'] = diff_quantity | ||||
|  |             done += moves.create(template) | ||||
|  |         return done | ||||
| @ -0,0 +1,362 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 io | ||||
|  | import json | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | try: | ||||
|  |     from odoo.tools.misc import xlsxwriter | ||||
|  | except ImportError: | ||||
|  |     import xlsxwriter | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class DynamicInventoryReport(models.Model): | ||||
|  |     """Creation of Dynamic Inventory Report""" | ||||
|  |     _name = "dynamic.inventory.report" | ||||
|  | 
 | ||||
|  |     purchase_report = fields.Char(string="Inventory Report", | ||||
|  |                                   help="Inventory report") | ||||
|  |     date_from = fields.Datetime(string="Date From", help="Start date") | ||||
|  |     date_to = fields.Datetime(string="Date to", help="End date") | ||||
|  |     report_type = fields.Selection([ | ||||
|  |         ('report_by_transfers', 'Report By Transfers'), | ||||
|  |         ('report_by_categories', 'Report By Categories'), | ||||
|  |         ('report_by_warehouse', 'Report By Warehouse'), | ||||
|  |         ('report_by_location', 'Report By Location')], | ||||
|  |         default='report_by_transfers', help="Type of the report") | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def inventory_report(self, option): | ||||
|  |         """ Inventory report """ | ||||
|  |         report_values = self.env['dynamic.inventory.report'].search( | ||||
|  |             [('id', '=', 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('INVENTORY') | ||||
|  |         return { | ||||
|  |             'name': "Inventory Orders", | ||||
|  |             'type': 'ir.actions.client', | ||||
|  |             'tag': 's_r', | ||||
|  |             'orders': data, | ||||
|  |             'filters': filters, | ||||
|  |             'report_lines': lines, | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def get_filter(self, option): | ||||
|  |         """Apply filter for the report""" | ||||
|  |         data = self.get_filter_data(option) | ||||
|  |         filters = {} | ||||
|  |         if data.get('report_type') == 'report_by_transfers': | ||||
|  |             filters['report_type'] = 'Report By Transfers' | ||||
|  |         elif data.get('report_type') == 'report_by_categories': | ||||
|  |             filters['report_type'] = 'Report By Categories' | ||||
|  |         elif data.get('report_type') == 'report_by_warehouse': | ||||
|  |             filters['report_type'] = 'Report By Warehouse' | ||||
|  |         elif data.get('report_type') == 'report_by_location': | ||||
|  |             filters['report_type'] = 'Report By Location' | ||||
|  |         else: | ||||
|  |             filters['report_type'] = 'report_by_transfers' | ||||
|  |         return filters | ||||
|  | 
 | ||||
|  |     def get_filter_data(self, option): | ||||
|  |         """ Gets filter data """ | ||||
|  |         report = self.env['dynamic.inventory.report'].search( | ||||
|  |             [('id', '=', option[0])]) | ||||
|  |         default_filters = {} | ||||
|  |         filter_dict = { | ||||
|  |             'report_type': report.report_type, | ||||
|  |         } | ||||
|  |         filter_dict.update(default_filters) | ||||
|  |         return filter_dict | ||||
|  | 
 | ||||
|  |     def _get_report_sub_lines(self, data, report, date_from, date_to): | ||||
|  |         """ Gets report sublines""" | ||||
|  |         report_sub_lines = [] | ||||
|  |         if data.get('report_type') == 'report_by_transfers': | ||||
|  |             query = '''select l.name,l.partner_id,l.scheduled_date,l.origin, | ||||
|  |             l.company_id,l.state,res_partner.name as partner, | ||||
|  |             res_company.name as company,l.id as id from stock_picking as l | ||||
|  |             left join res_partner on l.partner_id = res_partner.id left join | ||||
|  |             res_company on l.company_id = res_company.id''' | ||||
|  |             term = 'Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += f""" Where l.scheduled_date >= '%s' """ % data.get( | ||||
|  |                     'date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + f""" l.scheduled_date <= '%s' """ % data.get( | ||||
|  |                     'date_to') | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_order = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_order) | ||||
|  |         elif data.get('report_type') == 'report_by_categories': | ||||
|  |             query = ''' | ||||
|  |               select prop_date.res_id,prop_date.value_float,product_template. | ||||
|  |               name,product_template.create_date,product_template.categ_id, | ||||
|  |               product_product.id, stock_quant.quantity,product_category.name as | ||||
|  |               category from product_product | ||||
|  |               inner join product_template on  product_product.product_tmpl_id = | ||||
|  |               product_template.id | ||||
|  | 			  inner join stock_quant on product_product.id = stock_quant. | ||||
|  | 			  product_id | ||||
|  | 			  LEFT OUTER JOIN ir_property prop_date ON prop_date.res_id = | ||||
|  | 			  CONCAT('product.product,', product_product.id) | ||||
|  | 			  left join product_category on product_category.id = | ||||
|  | 			  product_template.categ_id | ||||
|  |                     ''' | ||||
|  |             term = ' Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += f""" Where prop_date.create_date >= '%s' """ % data.get( | ||||
|  |                     'date_from') | ||||
|  |                 term = ' AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + " prop_date.create_date <= '%s' " % data.get( | ||||
|  |                     'date_to') | ||||
|  |             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_warehouse': | ||||
|  |             query = '''select l.name,l.company_id,l.view_location_id, | ||||
|  |             l.reception_route_id as route,l.write_date,res_company.name as | ||||
|  |             company,stock_location.name as location,stock_route.name as | ||||
|  |             route from stock_warehouse as l left join res_company on | ||||
|  |             res_company.id = l.company_id left join stock_location on | ||||
|  |             stock_location.id = l.view_location_id left join stock_route on | ||||
|  |             stock_route.id = l.reception_route_id''' | ||||
|  |             term = ' Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += " Where l.write_date >= '%s' " % data.get('date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "l.write_date <= '%s' " % data.get('date_to') | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_product = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_product) | ||||
|  |         elif data.get('report_type') == 'report_by_location': | ||||
|  |             query = '''select l.complete_name,l.usage as location_type, | ||||
|  |             l.create_date,l.company_id,res_company.name as company from | ||||
|  |             stock_location as l left join res_company on res_company.id = | ||||
|  |             l.company_id''' | ||||
|  |             term = ' Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += " Where l.create_date >= '%s' " % data.get('date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "l.create_date <= '%s' " % data.get('date_to') | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_categories = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_categories) | ||||
|  |         return report_sub_lines | ||||
|  | 
 | ||||
|  |     def _get_report_total_value(self, data, report): | ||||
|  |         """ get report total values """ | ||||
|  |         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): | ||||
|  |         """get report values""" | ||||
|  |         docs = data['model'] | ||||
|  |         date_from = data.get('date_from') | ||||
|  |         date_to = data.get('date_to') | ||||
|  |         if data['report_type'] == 'report_by_transfers': | ||||
|  |             report = ['Report By Transfers'] | ||||
|  |         elif data['report_type'] == 'report_by_categories': | ||||
|  |             report = ['Report By Categories'] | ||||
|  |         elif data['report_type'] == 'report_by_warehouse': | ||||
|  |             report = ['Report By Warehouse'] | ||||
|  |         elif data['report_type'] == 'report_by_location': | ||||
|  |             report = ['Report By Location'] | ||||
|  |         else: | ||||
|  |             report = ['report_by_transfers By Order'] | ||||
|  |         if data.get('report_type'): | ||||
|  |             report_res = \ | ||||
|  |                 self._get_report_sub_lines(data, report, date_from, date_to)[0] | ||||
|  |         else: | ||||
|  |             report_res = self._get_report_sub_lines(data, report, date_from, | ||||
|  |                                                     date_to) | ||||
|  |         return { | ||||
|  |             'doc_ids': self.ids, | ||||
|  |             'docs': docs, | ||||
|  |             'INVENTORY': report_res, | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def get_xlsx_report(self, data, response, report_data): | ||||
|  |         """Adds data to inventory xlsx report""" | ||||
|  |         report_data_main = json.loads(report_data) | ||||
|  |         output = io.BytesIO() | ||||
|  |         filters = json.loads(data) | ||||
|  |         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', 'Inventory Report', head) | ||||
|  |         if filters.get('report_type') == 'report_by_transfers': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('A7', 'Reference', heading) | ||||
|  |             sheet.write('B7', 'Scheduled Date', heading) | ||||
|  |             sheet.write('C7', 'Source Document', heading) | ||||
|  |             sheet.write('D7', 'Company', heading) | ||||
|  |             sheet.write('E7', 'Delivery Address', heading) | ||||
|  |             sheet.write('F7', 'State', 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['name'], txt_l) | ||||
|  |                 sheet.write(row, col + 1, rec_data['scheduled_date'], txt_l) | ||||
|  |                 sheet.write(row, col + 2, rec_data['origin'], txt_l) | ||||
|  |                 sheet.write(row, col + 3, rec_data['company'], txt_l) | ||||
|  |                 sheet.write(row, col + 4, rec_data['partner'], txt_l) | ||||
|  |                 sheet.write(row, col + 5, rec_data['state'], 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('A7', 'Category', heading) | ||||
|  |             sheet.write('B7', 'Product Name', heading) | ||||
|  |             sheet.write('C7', 'Create Date', heading) | ||||
|  |             sheet.write('D7', 'Product Cost', heading) | ||||
|  |             sheet.write('E7', 'On Hand Qty', 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 | ||||
|  |                 sheet.write(row, col, rec_data['category'], txt_l) | ||||
|  |                 sheet.write(row, col + 1, rec_data['name']['en_US'], txt_l) | ||||
|  |                 sheet.write(row, col + 2, rec_data['create_date'], txt_l) | ||||
|  |                 sheet.write(row, col + 3, rec_data['value_float'], txt_l) | ||||
|  |                 sheet.write(row, col + 4, rec_data['quantity'], txt_l) | ||||
|  |         if filters.get('report_type') == 'report_by_warehouse': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('A7', 'Warehouse', heading) | ||||
|  |             sheet.write('B7', 'Date', heading) | ||||
|  |             sheet.write('C7', 'Company', heading) | ||||
|  |             sheet.write('D7', 'Location', heading) | ||||
|  |             sheet.write('E7', 'Route', 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 | ||||
|  |                 sheet.write(row, col, rec_data['name'], txt_l) | ||||
|  |                 sheet.write(row, col + 1, rec_data['write_date'], txt_l) | ||||
|  |                 sheet.write(row, col + 2, rec_data['company'], txt_l) | ||||
|  |                 sheet.write(row, col + 3, rec_data['location'], txt_l) | ||||
|  |                 sheet.write(row, col + 4, rec_data['route']['en_US'], txt_l) | ||||
|  |         if filters.get('report_type') == 'report_by_location': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('B7', 'Location', heading) | ||||
|  |             sheet.write('C7', 'Location Type', heading) | ||||
|  |             sheet.write('D7', 'Create Date', heading) | ||||
|  |             sheet.write('E7', 'Company', 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) | ||||
|  |             sheet.set_column(6, 4, 15) | ||||
|  |             for rec_data in report_data_main: | ||||
|  |                 row += 1 | ||||
|  |                 sheet.write(row, col, rec_data['complete_name'], txt_l) | ||||
|  |                 sheet.write(row, col + 1, rec_data['location_type'], txt_l) | ||||
|  |                 sheet.write(row, col + 2, rec_data['create_date'], txt_l) | ||||
|  |                 sheet.write(row, col + 3, rec_data['company'], txt_l) | ||||
|  |         workbook.close() | ||||
|  |         output.seek(0) | ||||
|  |         response.stream.write(output.read()) | ||||
|  |         output.close() | ||||
| @ -0,0 +1,42 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 ProductBrand(models.Model): | ||||
|  |     """Creates product brand""" | ||||
|  |     _name = 'product.brand' | ||||
|  |     _description = "Product Brand" | ||||
|  | 
 | ||||
|  |     name = fields.Char(string="Name", help="Name of brand", required=True) | ||||
|  |     brand_image = fields.Binary(string="Image", help='Image of brand') | ||||
|  |     member_ids = fields.One2many('product.template', | ||||
|  |                                  'brand_id', | ||||
|  |                                  string="Products", help="Product in a brand") | ||||
|  |     product_count = fields.Char(string='Product Count', | ||||
|  |                                 compute='get_count_products', store=True, | ||||
|  |                                 help="Product count") | ||||
|  | 
 | ||||
|  |     @api.depends('member_ids') | ||||
|  |     def get_count_products(self): | ||||
|  |         """Show count of products""" | ||||
|  |         self.product_count = len(self.member_ids) | ||||
| @ -0,0 +1,37 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 ProductProduct(models.Model): | ||||
|  |     """ Inherits product.product """ | ||||
|  |     _inherit = 'product.product' | ||||
|  | 
 | ||||
|  |     product_stock_location_ids = fields.One2many('stock.quant', | ||||
|  |                                                  'product_id', | ||||
|  |                                                  help="Product stock locations") | ||||
|  | 
 | ||||
|  |     def get_wo_description(self): | ||||
|  |         """Method for print pdf report """ | ||||
|  |         return self.env.ref( | ||||
|  |             'all_in_one_inventory_kit.product_product_report_action')\ | ||||
|  |             .report_action(self, data='') | ||||
| @ -0,0 +1,51 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 ProductTemplate(models.Model): | ||||
|  |     """inherits product.template""" | ||||
|  |     _inherit = 'product.template' | ||||
|  | 
 | ||||
|  |     brand_id = fields.Many2one('product.brand', string='Brand', | ||||
|  |                                help="Product Brand") | ||||
|  |     category_id = fields.Many2one('uom.category', | ||||
|  |                                   default=lambda self: self.env.ref( | ||||
|  |                                       'uom.product_uom_categ_kgm'), | ||||
|  |                                   help="Unit of measure categories") | ||||
|  |     cw_uom_id = fields.Many2one('uom.uom', string='CW-Uom', | ||||
|  |                                 stored=True, | ||||
|  |                                 help="Catch weight unit of measure", | ||||
|  |                                 domain="[('category_id', '=', category_id)]") | ||||
|  |     catch_weight_ok = fields.Boolean(default=False, | ||||
|  |                                      string="Catch Weight Product", | ||||
|  |                                      help="Is catch weight enabled") | ||||
|  |     average_cw_qty = fields.Float(string='Catch Weight', digits=(16, 4), | ||||
|  |                                   help="Catch weight quantity") | ||||
|  | 
 | ||||
|  |     @api.onchange('cw_uom_id', 'uom_id') | ||||
|  |     def _onchange_cw_uom_id(self): | ||||
|  |         """Calculating cw qty if uom and cw uom category is same""" | ||||
|  |         if self.uom_id.category_id == self.cw_uom_id.category_id: | ||||
|  |             self.average_cw_qty = self.cw_uom_id.factor / self.uom_id.factor | ||||
|  |         else: | ||||
|  |             self.average_cw_qty = 1.00 | ||||
| @ -0,0 +1,59 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 ResConfigSettings(models.TransientModel): | ||||
|  |     """ Inherits res.config.settings """ | ||||
|  |     _inherit = 'res.config.settings' | ||||
|  | 
 | ||||
|  |     customer_journal_id = fields.Many2one( | ||||
|  |         'account.journal', | ||||
|  |         string='Customer Journal', | ||||
|  |         config_parameter='stock_move_invoice.customer_journal_id', | ||||
|  |         help="Customer journals") | ||||
|  |     vendor_journal_id = fields.Many2one( | ||||
|  |         'account.journal', | ||||
|  |         string='Vendor Journal', | ||||
|  |         config_parameter='stock_move_invoice.vendor_journal_id', | ||||
|  |         help="Vendor journals") | ||||
|  |     out_of_stock = fields.Boolean( | ||||
|  |         string="Out Of Stock", | ||||
|  |         config_parameter='all_in_one_inventory_kit.out_of_stock', | ||||
|  |         help="Is out of stock") | ||||
|  |     out_of_stock_quantity = fields.Integer( | ||||
|  |         string="Quantity", | ||||
|  |         config_parameter='all_in_one_inventory_kit.out_of_stock_quantity', | ||||
|  |         required=True, | ||||
|  |         help="Out of stock quantity") | ||||
|  |     dead_stock_bol = fields.Boolean( | ||||
|  |         string="Dead Stock", | ||||
|  |         config_parameter='all_in_one_inventory_kit.dead_stock_bol', | ||||
|  |         help="Is this is a dead stock") | ||||
|  |     dead_stock = fields.Integer( | ||||
|  |         config_parameter='all_in_one_inventory_kit.dead_stock', | ||||
|  |         required=True, help="Dead stock") | ||||
|  |     dead_stock_type = fields.Selection( | ||||
|  |         [('day', 'Day'), ('week', 'Week'), ('month', 'Month')], | ||||
|  |         string="Type", default='day', | ||||
|  |         config_parameter='all_in_one_inventory_kit.dead_stock_type', | ||||
|  |         required=True, help="Dead stock type") | ||||
| @ -0,0 +1,440 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 datetime import datetime, timedelta | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class StockMove(models.Model): | ||||
|  |     """Inherits stock.move""" | ||||
|  |     _inherit = 'stock.move' | ||||
|  | 
 | ||||
|  |     barcode = fields.Char(string='Barcode', help="Barcode") | ||||
|  |     category_id = fields.Many2one('uom.category', | ||||
|  |                                   default=lambda self: self.env.ref( | ||||
|  |                                       'uom.product_uom_categ_kgm'), | ||||
|  |                                   help="category") | ||||
|  |     cw_uom_id = fields.Many2one('uom.uom', string='CW-Uom', | ||||
|  |                                 help="Catch weight unit of measure", | ||||
|  |                                 domain="[('category_id', '=', category_id)]") | ||||
|  |     cw_demand = fields.Float(string='CW-Demand', default=1.0, required=True, | ||||
|  |                              digits=(16, 4), | ||||
|  |                              compute='_cal_cw_demand', | ||||
|  |                              help="Catch weight demand") | ||||
|  |     cw_reserved = fields.Float(string='CW-Reserved', compute='_cal_cw_demand', | ||||
|  |                                digits=(16, 4), help="Catch weight reserved") | ||||
|  |     cw_done = fields.Float(string='CW-Done', digits=(16, 4), | ||||
|  |                            help="Catch weight done") | ||||
|  |     cw_hide = fields.Boolean(string='Is CW Product', | ||||
|  |                              compute="_compute_cw_hide", default=False, | ||||
|  |                              help="Catch weight hide") | ||||
|  |     move_line_image = fields.Binary(string="Image", | ||||
|  |                                     related="product_id.image_1920", | ||||
|  |                                     help="Product image") | ||||
|  | 
 | ||||
|  |     # cw_stock functions | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_hide(self): | ||||
|  |         """ Computes the cw_hide feature""" | ||||
|  |         for rec in self: | ||||
|  |             rec.cw_hide = bool(rec.product_id.catch_weight_ok) | ||||
|  | 
 | ||||
|  |     @api.onchange('product_id', 'product_uom_qty') | ||||
|  |     def _onchange_product_id(self): | ||||
|  |         """Calculating cw demand and cw uom""" | ||||
|  |         for rec in self: | ||||
|  |             rec.cw_demand = rec.product_uom_qty * rec.product_id.average_cw_qty | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 rec.cw_uom_id = rec.product_id.cw_uom_id | ||||
|  |             else: | ||||
|  |                 rec.cw_uom_id = None | ||||
|  | 
 | ||||
|  |     @api.onchange('cw_done') | ||||
|  |     def _onchange_cw_done(self): | ||||
|  |         """Calculating done qty""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok and rec.product_id.average_cw_qty\ | ||||
|  |                     != 0: | ||||
|  |                 rec.quantity_done = rec.cw_done / rec.product_id.average_cw_qty | ||||
|  | 
 | ||||
|  |     @api.onchange('quantity_done') | ||||
|  |     def _onchange_quantity_done(self): | ||||
|  |         """Calculating cw done""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 rec.cw_done = rec.quantity_done * rec.product_id.average_cw_qty | ||||
|  | 
 | ||||
|  |     @api.onchange('cw_demand') | ||||
|  |     def onchange_cw_demand(self): | ||||
|  |         """Calculating cw qty""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok and rec.product_id.average_cw_qty\ | ||||
|  |                     != 0: | ||||
|  |                 if rec.cw_uom_id == rec.product_uom: | ||||
|  |                     rec.product_uom_qty = rec.cw_demand | ||||
|  |                 else: | ||||
|  |                     rec.product_uom_qty = rec.cw_demand / rec.product_id.\ | ||||
|  |                         average_cw_qty | ||||
|  | 
 | ||||
|  |     @api.onchange('product_uom_qty') | ||||
|  |     def _onchange_product_uom_qty(self): | ||||
|  |         """Calculating cw demand""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok and rec.product_id.average_cw_qty\ | ||||
|  |                     != 0: | ||||
|  |                 if rec.cw_uom_id == rec.product_uom: | ||||
|  |                     rec.cw_demand = rec.product_uom_qty | ||||
|  |                 else: | ||||
|  |                     rec.product_uom_qty = rec.cw_demand / rec.product_id.\ | ||||
|  |                         average_cw_qty | ||||
|  | 
 | ||||
|  |     def _cal_cw_demand(self): | ||||
|  |         """Calculating cw demand,cw uom, cw reserved and cw done""" | ||||
|  |         for rec in self: | ||||
|  |             rec.update( | ||||
|  |                 { | ||||
|  |                     'cw_demand': rec.product_uom_qty * rec.product_id. | ||||
|  |                     average_cw_qty, | ||||
|  |                     'cw_uom_id': rec.product_id.cw_uom_id, | ||||
|  |                     'cw_done': rec.quantity_done * rec.product_id. | ||||
|  |                     average_cw_qty, | ||||
|  |                     'cw_reserved': rec.product_uom_qty * rec.product_id. | ||||
|  |                     average_cw_qty, | ||||
|  |                 }) | ||||
|  | 
 | ||||
|  |     # product barcode functions | ||||
|  |     @api.onchange('barcode') | ||||
|  |     def _onchange_barcode(self): | ||||
|  |         """ gets product with given barcode """ | ||||
|  |         product_rec = self.env['product.product'] | ||||
|  |         if self.barcode: | ||||
|  |             product = product_rec.search([('barcode', '=', self.barcode)]) | ||||
|  |             self.product_id = product.id | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_the_top_products(self): | ||||
|  |         """Rpc method of top products graph | ||||
|  |         Returns top ten products and done quantity""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = '''select product_template.name,sum(product_uom_qty)  from | ||||
|  |          stock_move | ||||
|  |             inner join stock_picking on stock_move.picking_id = stock_picking.id | ||||
|  |             inner join stock_picking_type on stock_picking.picking_type_id =  | ||||
|  |             stock_picking_type.id | ||||
|  |             inner join product_product on stock_move.product_id =  | ||||
|  |             product_product.id | ||||
|  |             inner join product_template on product_template.id =  | ||||
|  |             product_product.product_tmpl_id  | ||||
|  |             where stock_move.state = 'done' and stock_move.company_id=%s and  | ||||
|  |             stock_picking_type.code = 'outgoing' and  | ||||
|  |             stock_move.create_date between (now() - interval '10 day') and now() | ||||
|  |             group by product_template.name ORDER BY sum DESC''' % company_id | ||||
|  |         self._cr.execute(query) | ||||
|  |         top_product = self._cr.dictfetchall() | ||||
|  |         total_quantity = [] | ||||
|  |         product_name = [] | ||||
|  |         for record in top_product[:10]: | ||||
|  |             total_quantity.append(record.get('sum')) | ||||
|  |             product_name.append(record.get('name')['en_US']) | ||||
|  |         value = {'products': product_name, 'count': total_quantity} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def top_products_last_ten(self): | ||||
|  |         """rpc method of top products graph for last 10 days | ||||
|  |         Returns top ten products and done quantity""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = '''select product_template.name,sum(product_uom_qty)  from  | ||||
|  |             stock_move inner join stock_picking on stock_move.picking_id =  | ||||
|  |             stock_picking.id inner join stock_picking_type on stock_picking. | ||||
|  |             picking_type_id =  stock_picking_type.id | ||||
|  |             inner join product_product on stock_move.product_id =  | ||||
|  |             product_product.id inner join product_template on product_template. | ||||
|  |             id = product_product.product_tmpl_id  | ||||
|  |             where stock_move.state = 'done' and stock_move.company_id=%s  | ||||
|  |             and stock_picking_type.code = 'outgoing' and  | ||||
|  |             stock_move.create_date between (now() - interval '10 day') and now() | ||||
|  |             group by product_template.name ORDER BY sum DESC''' % company_id | ||||
|  |         self._cr.execute(query) | ||||
|  |         top_product = self._cr.dictfetchall() | ||||
|  |         total_quantity = [] | ||||
|  |         product_name = [] | ||||
|  |         for record in top_product[:10]: | ||||
|  |             total_quantity.append(record.get('sum')) | ||||
|  |             product_name.append(record.get('name')['en_US']) | ||||
|  |         value = {'products': product_name, 'count': total_quantity} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def top_products_last_thirty(self): | ||||
|  |         """rpc method of top products graph for last 30 days | ||||
|  |         Returns top ten products and done quantity""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = '''select product_template.name,sum(product_uom_qty)  from  | ||||
|  |                 stock_move inner join stock_picking on stock_move.picking_id =  | ||||
|  |                 stock_picking.id inner join stock_picking_type on stock_picking. | ||||
|  |                 picking_type_id = stock_picking_type.id | ||||
|  |                 inner join product_product on stock_move.product_id =  | ||||
|  |                 product_product.id inner join product_template on  | ||||
|  |                 product_template.id = product_product.product_tmpl_id  | ||||
|  |                 where stock_move.state = 'done' and stock_move.company_id=%s  | ||||
|  |                 and stock_picking_type.code = 'outgoing'  | ||||
|  |                 and stock_move.create_date between (now() - interval '30 day')  | ||||
|  |                 and now() group by product_template.name ORDER BY sum DESC''' \ | ||||
|  |                 % company_id | ||||
|  |         self._cr.execute(query) | ||||
|  |         top_product = self._cr.dictfetchall() | ||||
|  |         total_quantity = [] | ||||
|  |         product_name = [] | ||||
|  |         for record in top_product[:10]: | ||||
|  |             total_quantity.append(record.get('sum')) | ||||
|  |             product_name.append(record.get('name')['en_US']) | ||||
|  |         value = {'products': product_name, 'count': total_quantity} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def top_products_last_three_months(self): | ||||
|  |         """RPC method of top products graph select last 3 months | ||||
|  |         Returns top ten products and done quantity""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         now = datetime.now() | ||||
|  |         start_three_months_ago = now - timedelta(days=90) | ||||
|  |         query = ''' | ||||
|  |         SELECT product_template.name, SUM(stock_move.product_uom_qty) | ||||
|  |         FROM stock_move | ||||
|  |         INNER JOIN stock_picking ON stock_move.picking_id = stock_picking.id | ||||
|  |         INNER JOIN stock_picking_type ON stock_picking.picking_type_id = stock_picking_type.id | ||||
|  |         INNER JOIN product_product ON stock_move.product_id = product_product.id | ||||
|  |         INNER JOIN product_template ON product_template.id = product_product.product_tmpl_id | ||||
|  |         WHERE stock_move.state = 'done' | ||||
|  |           AND stock_move.company_id = %s | ||||
|  |           AND stock_picking_type.code = 'outgoing' | ||||
|  |           AND stock_move.create_date BETWEEN %s AND %s | ||||
|  |         GROUP BY product_template.name | ||||
|  |         ORDER BY SUM(stock_move.product_uom_qty) DESC | ||||
|  |         ''' | ||||
|  |         self._cr.execute(query, (company_id, start_three_months_ago, now)) | ||||
|  |         top_product = self._cr.dictfetchall() | ||||
|  |         total_quantity = [] | ||||
|  |         product_name = [] | ||||
|  |         for record in top_product[:10]: | ||||
|  |             total_quantity.append(record.get('sum')) | ||||
|  |             product_name.append(record.get('name')['en_US']) | ||||
|  |         value = {'products': product_name, 'count': total_quantity} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def top_products_last_year(self): | ||||
|  |         """RPC method of top products graph select last year | ||||
|  |         Returns top ten products and done quantity""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         now = datetime.now() | ||||
|  |         start_last_year = datetime(now.year - 1, 1, 1) | ||||
|  |         end_last_year = datetime(now.year - 1, 12, 31, 23, 59, 59) | ||||
|  |         query = ''' | ||||
|  |         SELECT product_template.name, SUM(stock_move.product_uom_qty) | ||||
|  |         FROM stock_move | ||||
|  |         INNER JOIN stock_picking ON stock_move.picking_id = stock_picking.id | ||||
|  |         INNER JOIN stock_picking_type ON stock_picking.picking_type_id = stock_picking_type.id | ||||
|  |         INNER JOIN product_product ON stock_move.product_id = product_product.id | ||||
|  |         INNER JOIN product_template ON product_template.id = product_product.product_tmpl_id | ||||
|  |         WHERE stock_move.state = 'done' | ||||
|  |           AND stock_move.company_id = %s | ||||
|  |           AND stock_picking_type.code = 'outgoing' | ||||
|  |           AND stock_move.create_date BETWEEN %s AND %s | ||||
|  |         GROUP BY product_template.name | ||||
|  |         ORDER BY SUM(stock_move.product_uom_qty) DESC | ||||
|  |         ''' | ||||
|  |         self._cr.execute(query, (company_id, start_last_year, end_last_year)) | ||||
|  |         top_product = self._cr.dictfetchall() | ||||
|  |         total_quantity = [] | ||||
|  |         product_name = [] | ||||
|  |         for record in top_product[:10]: | ||||
|  |             total_quantity.append(record.get('sum')) | ||||
|  |             product_name.append(record.get('name')['en_US']) | ||||
|  |         value = {'products': product_name, 'count': total_quantity} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_stock_moves(self): | ||||
|  |         """rpc method of stock moves graph | ||||
|  |             Returns location name and quantity_done""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = ('''select stock_location.complete_name, count(stock_move.id)  | ||||
|  |                 from stock_move inner join stock_location on stock_move. | ||||
|  |                 location_id = stock_location.id where stock_move.state = 'done'  | ||||
|  |             and stock_move.company_id = %s group by stock_location.complete_name | ||||
|  |             ''' % company_id) | ||||
|  |         self._cr.execute(query) | ||||
|  |         stock_move = self._cr.dictfetchall() | ||||
|  |         count = [] | ||||
|  |         complete_name = [] | ||||
|  |         for record in stock_move: | ||||
|  |             count.append(record.get('count')) | ||||
|  |             complete_name.append(record.get('complete_name')) | ||||
|  |         value = {'name': complete_name, 'count': count} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def stock_move_last_ten_days(self, post): | ||||
|  |         """rpc method of stock moves graph select last ten days | ||||
|  |             Returns location name and quantity_done""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = ('''select stock_location.name,sum(stock_move_line.qty_done)  | ||||
|  |                 from stock_move_line inner join stock_location on  | ||||
|  |                 stock_move_line.location_id = stock_location.id where  | ||||
|  |                 stock_move_line.state = 'done' and stock_move_line.company_id = | ||||
|  |                  %s and stock_move_line.create_date between (now() - interval  | ||||
|  |                  '10 day') and now() group by stock_location.name''' | ||||
|  |                  % company_id) | ||||
|  |         self._cr.execute(query) | ||||
|  |         location_quantity = self._cr.dictfetchall() | ||||
|  |         quantity_done = [] | ||||
|  |         name = [] | ||||
|  |         for record in location_quantity: | ||||
|  |             quantity_done.append(record.get('sum')) | ||||
|  |             name.append(record.get('name')) | ||||
|  |         value = {'name': name, 'count': quantity_done} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def this_month(self, post): | ||||
|  |         """RPC method of stock moves graph select this month | ||||
|  |         Returns location name and quantity_done""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         now = datetime.now() | ||||
|  |         start_this_month = datetime(now.year, now.month, 1) | ||||
|  |         end_this_month = now | ||||
|  |         query = ''' | ||||
|  |         SELECT stock_location.name, SUM(stock_move_line.qty_done) | ||||
|  |         FROM stock_move_line | ||||
|  |         INNER JOIN stock_location ON stock_move_line.location_id = stock_location.id | ||||
|  |         WHERE stock_move_line.state = 'done' | ||||
|  |           AND stock_move_line.company_id = %s | ||||
|  |           AND stock_move_line.create_date BETWEEN %s AND %s | ||||
|  |         GROUP BY stock_location.name | ||||
|  |         ''' | ||||
|  |         self._cr.execute(query, (company_id, start_this_month, end_this_month)) | ||||
|  |         location_quantity = self._cr.dictfetchall() | ||||
|  |         quantity_done = [] | ||||
|  |         name = [] | ||||
|  |         for record in location_quantity: | ||||
|  |             quantity_done.append(record.get('sum')) | ||||
|  |             name.append(record.get('name')) | ||||
|  |         value = {'name': name, 'count': quantity_done} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def last_three_month(self, post): | ||||
|  |         """rpc method of stock moves graph select 3 month | ||||
|  |             Returns location name and quantity_done""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = ('''select stock_location.name,sum(stock_move_line.qty_done)  | ||||
|  |         from stock_move_line inner join stock_location on stock_move_line. | ||||
|  |         location_id = stock_location.id where stock_move_line.state =  | ||||
|  |         'done' and stock_move_line.company_id = %s and stock_move_line. | ||||
|  |         create_date between (now() - interval '3 months') and now() group by  | ||||
|  |         stock_location.name''' % company_id) | ||||
|  |         self._cr.execute(query) | ||||
|  |         location_quantity = self._cr.dictfetchall() | ||||
|  |         quantity_done = [] | ||||
|  |         name = [] | ||||
|  |         for record in location_quantity: | ||||
|  |             quantity_done.append(record.get('sum')) | ||||
|  |             name.append(record.get('name')) | ||||
|  |         value = {'name': name, 'count': quantity_done} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def last_year(self, post): | ||||
|  |         """RPC method of stock moves graph select last year | ||||
|  |         Returns location name and quantity_done""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         now = datetime.now() | ||||
|  |         start_last_year = datetime(now.year - 1, 1, 1) | ||||
|  |         end_last_year = datetime(now.year - 1, 12, 31, 23, 59, 59) | ||||
|  |         query = ''' | ||||
|  |         SELECT stock_location.name, SUM(stock_move_line.qty_done)  | ||||
|  |         FROM stock_move_line | ||||
|  |         INNER JOIN stock_location ON stock_move_line.location_id = stock_location.id | ||||
|  |         WHERE stock_move_line.state = 'done' | ||||
|  |           AND stock_move_line.company_id = %s | ||||
|  |           AND stock_move_line.create_date BETWEEN %s AND %s | ||||
|  |         GROUP BY stock_location.name | ||||
|  |         ''' | ||||
|  |         self._cr.execute(query, (company_id, start_last_year, end_last_year)) | ||||
|  |         location_quantity = self._cr.dictfetchall() | ||||
|  |         quantity_done = [] | ||||
|  |         name = [] | ||||
|  |         for record in location_quantity: | ||||
|  |             quantity_done.append(record.get('sum')) | ||||
|  |             name.append(record.get('name')) | ||||
|  |         value = {'name': name, 'count': quantity_done} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_dead_of_stock(self): | ||||
|  |         """rpc method of dead of stock graph | ||||
|  |         Returns product name and dead quantity""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         sett_dead_stock_bool = self.env['ir.config_parameter'].sudo(). \ | ||||
|  |             get_param("inventory_stock_dashboard_odoo.dead_stock_bol", | ||||
|  |                       default="") | ||||
|  |         sett_dead_stock_quantity = self.env[ | ||||
|  |             'ir.config_parameter'].sudo().get_param( | ||||
|  |             "inventory_stock_dashboard_odoo.dead_stock", | ||||
|  |             default="") | ||||
|  |         sett_dead_stock_type = self.env['ir.config_parameter'].sudo().get_param( | ||||
|  |             "inventory_stock_dashboard_odoo.dead_stock_type", | ||||
|  |             default="") | ||||
|  |         if sett_dead_stock_bool == "True": | ||||
|  |             if sett_dead_stock_quantity: | ||||
|  |                 out_stock_value = int(sett_dead_stock_quantity) | ||||
|  |                 query = '''select product_product.id,stock_quant.quantity from  | ||||
|  |                 product_product inner join stock_quant on product_product.id =  | ||||
|  |                 stock_quant.product_id where stock_quant.company_id = %s and  | ||||
|  |                 product_product.create_date not between (now() - interval '%s  | ||||
|  |                 %s') and now() and product_product.id NOT IN (select product_id | ||||
|  |                 from stock_move inner join stock_picking on stock_move. | ||||
|  |                 picking_id = stock_picking.id inner join stock_picking_type on  | ||||
|  |                 stock_picking.picking_type_id = stock_picking_type.id | ||||
|  |                 where stock_move.company_id = %s and stock_picking_type.code =  | ||||
|  |                 'outgoing' and stock_move.state = 'done'   and stock_move. | ||||
|  |                 create_date between (now() - interval '%s %s') and now() | ||||
|  |                 group by product_id)''' % \ | ||||
|  |                 (company_id, out_stock_value, sett_dead_stock_type, | ||||
|  |                  company_id, out_stock_value, | ||||
|  |                  sett_dead_stock_type) | ||||
|  |                 self._cr.execute(query) | ||||
|  |                 result = self._cr.fetchall() | ||||
|  |                 total_quantity = [] | ||||
|  |                 product_name = [] | ||||
|  |                 for record in result: | ||||
|  |                     if record[1] > 0: | ||||
|  |                         complete_name = self.env['product.product'].browse( | ||||
|  |                             record[0]).display_name | ||||
|  |                         product_name.append(complete_name) | ||||
|  |                         total_quantity.append(record[1]) | ||||
|  |                 value = { | ||||
|  |                     'product_name': product_name, | ||||
|  |                     'total_quantity': total_quantity | ||||
|  |                 } | ||||
|  |                 return value | ||||
| @ -0,0 +1,157 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 StockMoveLine(models.Model): | ||||
|  |     """Inherits Stock Move Line""" | ||||
|  |     _inherit = "stock.move.line" | ||||
|  | 
 | ||||
|  |     cw_qty_done = fields.Float(string='CW-Qty Done', | ||||
|  |                                compute='_compute_cw_qty_done', default=0, | ||||
|  |                                digits=(16, 4), | ||||
|  |                                help="Catch weight Quantity Done") | ||||
|  |     category_id = fields.Many2one('uom.category', | ||||
|  |                                   default=lambda self: self.env.ref( | ||||
|  |                                       'uom.product_uom_categ_kgm'), | ||||
|  |                                   help="Category") | ||||
|  |     cw_uom_id = fields.Many2one('uom.uom', string='CW-Uom', | ||||
|  |                                 domain="[('category_id', '=', category_id)]", | ||||
|  |                                 compute='_compute_cw_uom_id', | ||||
|  |                                 help="Unit of measure") | ||||
|  |     cw_hide = fields.Boolean(string='Is CW Product', | ||||
|  |                              compute="_compute_cw_hide", default=False, | ||||
|  |                              help="Catch weight hide") | ||||
|  |     move_line_image = fields.Binary(string="Image", | ||||
|  |                                     related="product_id.image_1920", | ||||
|  |                                     help="Product image") | ||||
|  |     scheduled_date = fields.Datetime(related="picking_id.scheduled_date", | ||||
|  |                                      store=True, help="Scheduled date") | ||||
|  |     date_done = fields.Datetime(related="picking_id.date_done", | ||||
|  |                                 help="Date of done") | ||||
|  |     code = fields.Selection(related="picking_id.picking_type_id.code", | ||||
|  |                             help="Code") | ||||
|  |     picking_type_id = fields.Many2one(related="picking_id.picking_type_id", | ||||
|  |                                       store=True, help="Picking type") | ||||
|  |     origin = fields.Char(related="picking_id.origin", store=True, | ||||
|  |                          help="Origin of the picking") | ||||
|  |     reserved_available = fields.Float( | ||||
|  |         related="picking_id.move_ids.forecast_availability", | ||||
|  |         help="Reserved available") | ||||
|  |     date_deadline = fields.Datetime(related="picking_id.date_deadline", | ||||
|  |                                     string="Deadline", help="Date deadline") | ||||
|  |     has_deadline_issue = fields.Boolean(string="Is late", | ||||
|  |                                         related="picking_id.has_deadline_issue", | ||||
|  |                                         help="is deadline has issue") | ||||
|  | 
 | ||||
|  |     # cw_stock functions | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_uom_id(self): | ||||
|  |         """Calculating cw uom""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 rec.cw_uom_id = rec.product_id.cw_uom_id | ||||
|  |             else: | ||||
|  |                 rec.cw_uom_id = None | ||||
|  | 
 | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_hide(self): | ||||
|  |         """ Computes the cw_hide feature""" | ||||
|  |         for rec in self: | ||||
|  |             rec.cw_hide = bool(rec.product_id.catch_weight_ok) | ||||
|  | 
 | ||||
|  |     @api.depends('product_id', 'qty_done') | ||||
|  |     def _compute_cw_qty_done(self): | ||||
|  |         """Calculating cw qty done""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 rec.cw_qty_done = rec.qty_done * rec.product_id.average_cw_qty | ||||
|  |             else: | ||||
|  |                 rec.cw_qty_done = 0 | ||||
|  | 
 | ||||
|  |     # cw_stock functions end | ||||
|  |     @api.model | ||||
|  |     def get_product_moves(self): | ||||
|  |         """rpc method of product moves graph | ||||
|  |             Returns product move product and quantity_done""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = ('''select product_template.name,sum(stock_move_line.qty_done) | ||||
|  |          from stock_move_line | ||||
|  |                 inner join product_product on stock_move_line.product_id =  | ||||
|  |                 product_product.id | ||||
|  |                 inner join product_template on product_product.product_tmpl_id = | ||||
|  |                  product_template.id | ||||
|  |                 where stock_move_line.company_id = %s group by | ||||
|  |                  product_template.name''' % company_id) | ||||
|  |         self._cr.execute(query) | ||||
|  |         products_quantity = self._cr.dictfetchall() | ||||
|  |         quantity_done = [] | ||||
|  |         name = [] | ||||
|  |         for record in products_quantity: | ||||
|  |             quantity_done.append(record.get('sum')) | ||||
|  |             name.append(record.get('name')) | ||||
|  |         value = {'name': name, 'count': quantity_done} | ||||
|  |         category_query = '''select product_category.id,product_category.name  | ||||
|  |         from stock_move_line | ||||
|  |                 inner join product_product on stock_move_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_template.categ_id =  | ||||
|  |                 product_category.id where stock_move_line.company_id = %s and  | ||||
|  |                 stock_move_line.state = 'done' group by product_category.id''' \ | ||||
|  |                          % company_id | ||||
|  |         self._cr.execute(category_query) | ||||
|  |         category = self._cr.dictfetchall() | ||||
|  |         category_id = [] | ||||
|  |         category_name = [] | ||||
|  |         for record in category: | ||||
|  |             category_id.append(record.get('id')) | ||||
|  |             category_name.append(record.get('name')) | ||||
|  |         value1 = {'category_id': category_id, 'category_name': category_name} | ||||
|  |         return value, value1 | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def product_move_by_category(self, args): | ||||
|  |         """rpc method of product moves by category | ||||
|  |             Returns category name and quantity_done""" | ||||
|  |         category_id = int(args) | ||||
|  |         company_id = self.env.company.id | ||||
|  |         query = ('''select product_template.name,sum(stock_move_line.qty_done)  | ||||
|  |         from stock_move_line inner join product_product on stock_move_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_template.categ_id = product_category.id | ||||
|  |         where stock_move_line.company_id = %s and product_category.id = %s  | ||||
|  |         group by product_template.name''' % | ||||
|  |                  (company_id, category_id)) | ||||
|  |         self._cr.execute(query) | ||||
|  |         product_move = self._cr.dictfetchall() | ||||
|  |         quantity_done = [] | ||||
|  |         name = [] | ||||
|  |         for record in product_move: | ||||
|  |             quantity_done.append(record.get('sum')) | ||||
|  |             name.append(record.get('name')['en_US']) | ||||
|  |         value = { | ||||
|  |             'name': name, | ||||
|  |             'count': quantity_done, | ||||
|  |         } | ||||
|  |         return value | ||||
| @ -0,0 +1,372 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 StockPicking(models.Model): | ||||
|  |     """Inherits stock.picking""" | ||||
|  |     _inherit = 'stock.picking' | ||||
|  | 
 | ||||
|  |     barcode = fields.Char(string='Barcode', help="Product barcode") | ||||
|  |     invoice_count = fields.Integer(string='Invoices', | ||||
|  |                                    compute='_compute_invoice_count', | ||||
|  |                                    help="Count of invoices") | ||||
|  |     operation_code = fields.Selection(string="Operation code", | ||||
|  |                                       related='picking_type_id.code', | ||||
|  |                                       help="Operation code") | ||||
|  |     is_return = fields.Boolean(string="Is return picking", | ||||
|  |                                help="is this a return picking") | ||||
|  |     invoice_created = fields.Boolean(string='Invoice Created') | ||||
|  | 
 | ||||
|  |     @api.onchange('barcode') | ||||
|  |     def _onchange_barcode(self): | ||||
|  |         """ Scanning the barcode """ | ||||
|  |         print('llll') | ||||
|  |         match = False | ||||
|  |         product_obj = self.env['product.product'] | ||||
|  |         product_id = product_obj.search([('barcode', '=', self.barcode)]) | ||||
|  |         if self.barcode and not product_id: | ||||
|  |             warning_mess = { | ||||
|  |                 'title': _('Warning !'), | ||||
|  |                 'message': _('No product is available for this barcode') | ||||
|  |             } | ||||
|  |             return {'warning': warning_mess} | ||||
|  |         if self.barcode and self.move_ids_without_package: | ||||
|  |             for line in self.move_ids_without_package: | ||||
|  |                 if line.product_id.barcode == self.barcode: | ||||
|  |                     line.quantity_done += 1 | ||||
|  |                     match = True | ||||
|  |         if self.barcode and not match: | ||||
|  |             if product_id: | ||||
|  |                 warning_mess = { | ||||
|  |                     'title': _('Warning !'), | ||||
|  |                     'message': _('This product is not available in the order.' | ||||
|  |                                  'You can add this product by clicking the ' | ||||
|  |                                  '"Add a line" and scan')} | ||||
|  |                 return {'warning': warning_mess} | ||||
|  | 
 | ||||
|  |     def write(self, vals): | ||||
|  |         """Write values to order line""" | ||||
|  |         res = super(StockPicking, self).write(vals) | ||||
|  |         if vals.get('barcode') and self.move_ids_without_package: | ||||
|  |             for line in self.move_ids_without_package: | ||||
|  |                 if line.product_id.barcode == vals['barcode']: | ||||
|  |                     # Using a context flag to prevent multiple increments | ||||
|  |                     if self.env.context.get('barcode_processed'): | ||||
|  |                         line.with_context(barcode_processed=False).write( | ||||
|  |                             {'quantity_done': line.quantity_done + 1}) | ||||
|  |                     self.barcode = None | ||||
|  |         return res | ||||
|  | 
 | ||||
|  |     def _compute_invoice_count(self): | ||||
|  |         """This computes function used to count the number of invoice | ||||
|  |         for the picking""" | ||||
|  |         for picking_id in self: | ||||
|  |             move_ids = picking_id.env['account.move'].search( | ||||
|  |                 [('invoice_origin', '=', picking_id.name)]) | ||||
|  |             if move_ids: | ||||
|  |                 self.invoice_count = len(move_ids) | ||||
|  |             else: | ||||
|  |                 self.invoice_count = 0 | ||||
|  | 
 | ||||
|  |     def create_invoice(self): | ||||
|  |         """This is the function for creating customer invoice | ||||
|  |         from the picking""" | ||||
|  |         for picking_id in self: | ||||
|  |             current_user = self.env.uid | ||||
|  |             if picking_id.picking_type_id.code == 'outgoing': | ||||
|  |                 customer_journal_id = picking_id.env[ | ||||
|  |                                           'ir.config_parameter'].sudo().get_param( | ||||
|  |                     'stock_move_invoice.customer_journal_id') or False | ||||
|  |                 if not customer_journal_id: | ||||
|  |                     raise UserError( | ||||
|  |                         _("Please configure the journal from settings")) | ||||
|  |                 invoice_line_list = [] | ||||
|  |                 for move_ids_without_package in picking_id. \ | ||||
|  |                         move_ids_without_package: | ||||
|  |                     vals = (0, 0, { | ||||
|  |                         'name': move_ids_without_package.description_picking, | ||||
|  |                         'product_id': move_ids_without_package.product_id.id, | ||||
|  |                         'price_unit': move_ids_without_package.product_id. | ||||
|  |                             lst_price, | ||||
|  |                         'account_id': move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id.id if | ||||
|  |                         move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id | ||||
|  |                         else move_ids_without_package.product_id.categ_id. | ||||
|  |                             property_account_income_categ_id.id, | ||||
|  |                         'tax_ids': [(6, 0, [ | ||||
|  |                             picking_id.company_id.account_sale_tax_id.id])], | ||||
|  |                         'quantity': move_ids_without_package.quantity_done, | ||||
|  |                     }) | ||||
|  |                     invoice_line_list.append(vals) | ||||
|  |                     invoice = picking_id.env['account.move'].create({ | ||||
|  |                         'move_type': 'out_invoice', | ||||
|  |                         'invoice_origin': picking_id.name, | ||||
|  |                         'invoice_user_id': current_user, | ||||
|  |                         'narration': picking_id.name, | ||||
|  |                         'partner_id': picking_id.partner_id.id, | ||||
|  |                         'currency_id': picking_id.env.user.company_id. | ||||
|  |                         currency_id.id, | ||||
|  |                         'journal_id': int(customer_journal_id), | ||||
|  |                         'payment_reference': picking_id.name, | ||||
|  |                         'picking_id': picking_id.id, | ||||
|  |                         'invoice_line_ids': invoice_line_list, | ||||
|  |                         'transfer_created': True | ||||
|  |                     }) | ||||
|  |                     return invoice | ||||
|  | 
 | ||||
|  |     def create_bill(self): | ||||
|  |         """This is the function for creating vendor bill | ||||
|  |                 from the picking""" | ||||
|  |         for picking_id in self: | ||||
|  |             current_user = self.env.uid | ||||
|  |             if picking_id.picking_type_id.code == 'incoming': | ||||
|  |                 vendor_journal_id = picking_id.env[ | ||||
|  |                                         'ir.config_parameter'].sudo().get_param( | ||||
|  |                     'stock_move_invoice.vendor_journal_id') or False | ||||
|  |                 if not vendor_journal_id: | ||||
|  |                     raise UserError( | ||||
|  |                         _("Please configure the journal from the settings.")) | ||||
|  |                 invoice_line_list = [] | ||||
|  |                 for move_ids_without_package in picking_id. \ | ||||
|  |                         move_ids_without_package: | ||||
|  |                     vals = (0, 0, { | ||||
|  |                         'name': move_ids_without_package.description_picking, | ||||
|  |                         'product_id': move_ids_without_package.product_id.id, | ||||
|  |                         'price_unit': move_ids_without_package.product_id. | ||||
|  |                             lst_price, | ||||
|  |                         'account_id': move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id.id if | ||||
|  |                         move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id | ||||
|  |                         else move_ids_without_package.product_id.categ_id. | ||||
|  |                             property_account_income_categ_id.id, | ||||
|  |                         'tax_ids': [(6, 0, [ | ||||
|  |                             picking_id.company_id.account_purchase_tax_id.id])], | ||||
|  |                         'quantity': move_ids_without_package.quantity_done, | ||||
|  |                     }) | ||||
|  |                     invoice_line_list.append(vals) | ||||
|  |                     invoice = picking_id.env['account.move'].create({ | ||||
|  |                         'move_type': 'in_invoice', | ||||
|  |                         'invoice_origin': picking_id.name, | ||||
|  |                         'invoice_user_id': current_user, | ||||
|  |                         'narration': picking_id.name, | ||||
|  |                         'partner_id': picking_id.partner_id.id, | ||||
|  |                         'currency_id': picking_id.env.user.company_id. | ||||
|  |                         currency_id.id, | ||||
|  |                         'journal_id': int(vendor_journal_id), | ||||
|  |                         'payment_reference': picking_id.name, | ||||
|  |                         'picking_id': picking_id.id, | ||||
|  |                         'invoice_line_ids': invoice_line_list, | ||||
|  |                         'transfer_created': True | ||||
|  |                     }) | ||||
|  |                     return invoice | ||||
|  | 
 | ||||
|  |     def create_customer_credit(self): | ||||
|  |         """This is the function for creating customer credit note | ||||
|  |                 from the picking""" | ||||
|  |         for picking_id in self: | ||||
|  |             current_user = picking_id.env.uid | ||||
|  |             if picking_id.picking_type_id.code == 'incoming': | ||||
|  |                 customer_journal_id = picking_id.env[ | ||||
|  |                                           'ir.config_parameter'].sudo() \ | ||||
|  |                                           .get_param( | ||||
|  |                     'stock_move_invoice.customer_journal_id') or False | ||||
|  |                 if not customer_journal_id: | ||||
|  |                     raise UserError( | ||||
|  |                         _("Please configure the journal from settings")) | ||||
|  |                 invoice_line_list = [] | ||||
|  |                 for move_ids_without_package in picking_id. \ | ||||
|  |                         move_ids_without_package: | ||||
|  |                     vals = (0, 0, { | ||||
|  |                         'name': move_ids_without_package.description_picking, | ||||
|  |                         'product_id': move_ids_without_package.product_id.id, | ||||
|  |                         'price_unit': move_ids_without_package.product_id. | ||||
|  |                             lst_price, | ||||
|  |                         'account_id': move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id.id if | ||||
|  |                         move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id | ||||
|  |                         else move_ids_without_package.product_id.categ_id. | ||||
|  |                             property_account_income_categ_id.id, | ||||
|  |                         'tax_ids': [(6, 0, [ | ||||
|  |                             picking_id.company_id.account_sale_tax_id.id])], | ||||
|  |                         'quantity': move_ids_without_package.quantity_done, | ||||
|  |                     }) | ||||
|  |                     invoice_line_list.append(vals) | ||||
|  |                     invoice = picking_id.env['account.move'].create({ | ||||
|  |                         'move_type': 'out_refund', | ||||
|  |                         'invoice_origin': picking_id.name, | ||||
|  |                         'invoice_user_id': current_user, | ||||
|  |                         'narration': picking_id.name, | ||||
|  |                         'partner_id': picking_id.partner_id.id, | ||||
|  |                         'currency_id': picking_id.env.user.company_id. | ||||
|  |                         currency_id.id, | ||||
|  |                         'journal_id': int(customer_journal_id), | ||||
|  |                         'payment_reference': picking_id.name, | ||||
|  |                         'picking_id': picking_id.id, | ||||
|  |                         'invoice_line_ids': invoice_line_list | ||||
|  |                     }) | ||||
|  |                     return invoice | ||||
|  | 
 | ||||
|  |     def create_vendor_credit(self): | ||||
|  |         """This is the function for creating refund | ||||
|  |                 from the picking""" | ||||
|  |         for picking_id in self: | ||||
|  |             current_user = self.env.uid | ||||
|  |             if picking_id.picking_type_id.code == 'outgoing': | ||||
|  |                 vendor_journal_id = picking_id.env[ | ||||
|  |                                         'ir.config_parameter'].sudo().get_param( | ||||
|  |                     'stock_move_invoice.vendor_journal_id') or False | ||||
|  |                 if not vendor_journal_id: | ||||
|  |                     raise UserError( | ||||
|  |                         _("Please configure the journal from the settings.")) | ||||
|  |                 invoice_line_list = [] | ||||
|  |                 for move_ids_without_package in picking_id. \ | ||||
|  |                         move_ids_without_package: | ||||
|  |                     vals = (0, 0, { | ||||
|  |                         'name': move_ids_without_package.description_picking, | ||||
|  |                         'product_id': move_ids_without_package.product_id.id, | ||||
|  |                         'price_unit': move_ids_without_package.product_id. | ||||
|  |                             lst_price, | ||||
|  |                         'account_id': move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id.id if | ||||
|  |                         move_ids_without_package.product_id. | ||||
|  |                             property_account_income_id | ||||
|  |                         else move_ids_without_package.product_id.categ_id. | ||||
|  |                             property_account_income_categ_id.id, | ||||
|  |                         'tax_ids': [(6, 0, [ | ||||
|  |                             picking_id.company_id.account_purchase_tax_id.id])], | ||||
|  |                         'quantity': move_ids_without_package.quantity_done, | ||||
|  |                     }) | ||||
|  |                     invoice_line_list.append(vals) | ||||
|  |                     invoice = picking_id.env['account.move'].create({ | ||||
|  |                         'move_type': 'in_refund', | ||||
|  |                         'invoice_origin': picking_id.name, | ||||
|  |                         'invoice_user_id': current_user, | ||||
|  |                         'narration': picking_id.name, | ||||
|  |                         'partner_id': picking_id.partner_id.id, | ||||
|  |                         'currency_id': picking_id.env.user.company_id. | ||||
|  |                         currency_id.id, | ||||
|  |                         'journal_id': int(vendor_journal_id), | ||||
|  |                         'payment_reference': picking_id.name, | ||||
|  |                         'picking_id': picking_id.id, | ||||
|  |                         'invoice_line_ids': invoice_line_list | ||||
|  |                     }) | ||||
|  |                     return invoice | ||||
|  | 
 | ||||
|  |     def action_open_picking_invoice(self): | ||||
|  |         """This is the function of the smart button which redirect to the | ||||
|  |         invoice related to the current picking""" | ||||
|  |         return { | ||||
|  |             'name': 'Invoices', | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'view_mode': 'tree,form', | ||||
|  |             'res_model': 'account.move', | ||||
|  |             'domain': [('invoice_origin', '=', self.name)], | ||||
|  |             'context': {'create': False}, | ||||
|  |             'target': 'current' | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_operation_types(self): | ||||
|  |         """rpc method of operation type tiles,operation type graph | ||||
|  |             Returns operation type details. | ||||
|  |             no_transfer - each operation type transfer count, | ||||
|  |             late - each operation type late count | ||||
|  |             waiting - each operation type waiting count | ||||
|  |             operation_type_name - have all the operation type name | ||||
|  |             backorder - each operation type backorders count | ||||
|  |                 """ | ||||
|  |         no_transfer = {} | ||||
|  |         stock_picking_type = self.env['stock.picking.type'].search([]) | ||||
|  |         stock_picking = self.env['stock.picking'].search([]) | ||||
|  |         stock = [] | ||||
|  |         length = [] | ||||
|  |         names = [] | ||||
|  |         late = {} | ||||
|  |         query = '''select stock_picking.picking_type_id, count(stock_picking. | ||||
|  |         picking_type_id) from stock_picking | ||||
|  |             inner join stock_picking_type on stock_picking.picking_type_id =  | ||||
|  |             stock_picking_type.id | ||||
|  |             where stock_picking.company_id = %s and | ||||
|  |             stock_picking.state in ('assigned', 'waiting', 'confirmed') and  | ||||
|  |             (has_deadline_issue = true or  | ||||
|  |             date_deadline <= now() or scheduled_date <= now()) | ||||
|  |             group by stock_picking.picking_type_id''' % self.env.company.id | ||||
|  |         self._cr.execute(query) | ||||
|  |         lates = self._cr.dictfetchall() | ||||
|  |         for rec in lates: | ||||
|  |             late.update({rec.get('picking_type_id'): rec.get('count')}) | ||||
|  |         waiting = {} | ||||
|  |         backorder = {} | ||||
|  |         operation_type_name = {} | ||||
|  |         for type in stock_picking_type: | ||||
|  |             names.append(type.name) | ||||
|  |             orders = stock_picking.filtered( | ||||
|  |                 lambda r: r.picking_type_id.id == type.id) | ||||
|  |             stock.append(len(orders)) | ||||
|  |             length_stock_picking = len(orders) | ||||
|  |             length.append(len(stock_picking.filtered( | ||||
|  |                 lambda r: r.picking_type_id.id == type.id))) | ||||
|  |             no_transfer.update({type.id: length_stock_picking}) | ||||
|  |             operation_type_name.update({type.id: type.name}) | ||||
|  |             if len(orders) > 0: | ||||
|  |                 if len(orders.filtered(lambda r: r.state == 'confirmed')) > 0: | ||||
|  |                     waiting.update({type.id: len( | ||||
|  |                         orders.filtered(lambda r: r.state == 'confirmed'))}) | ||||
|  |                 if len(orders.mapped('backorder_id')) > 0: | ||||
|  |                     backorder.update( | ||||
|  |                         {type.id: len(orders.mapped('backorder_id'))}) | ||||
|  |         return no_transfer, late, waiting, operation_type_name, backorder | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_product_category(self): | ||||
|  |         """rpc method of product category graph | ||||
|  |         Returns product categories and category having on hand product quantity""" | ||||
|  |         category_ids = self.env['product.category'].search([]) | ||||
|  |         category_name = [] | ||||
|  |         product_count = [] | ||||
|  |         for rec in category_ids: | ||||
|  |             name = rec.name | ||||
|  |             category_name.append(name) | ||||
|  |             count = rec.product_count | ||||
|  |             product_count.append(count) | ||||
|  |         value = {'name': category_name, 'count': product_count} | ||||
|  |         return value | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_locations(self): | ||||
|  |         """rpc method of product location table | ||||
|  |                Returns locations and location having on hand product quantity""" | ||||
|  |         stock_quant_ids = self.env['stock.quant'].search([]) | ||||
|  |         locations = stock_quant_ids.mapped('location_id') | ||||
|  |         value = {} | ||||
|  |         for rec in locations: | ||||
|  |             loc_stock_quant = stock_quant_ids.filtered( | ||||
|  |                 lambda x: x.location_id == rec) | ||||
|  |             on_hand_quantity = sum( | ||||
|  |                 loc_stock_quant.mapped('inventory_quantity_auto_apply')) | ||||
|  |             value[rec.name] = on_hand_quantity | ||||
|  |         return value | ||||
| @ -0,0 +1,77 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 StockReturnPickingLine(models.TransientModel): | ||||
|  |     _inherit = "stock.return.picking.line" | ||||
|  | 
 | ||||
|  |     cw_qty = fields.Float(string='CW-Qty ', compute="_compute_cw_qty", | ||||
|  |                           help="Catch weight quantity", digits=(16, 4)) | ||||
|  |     category_id = fields.Many2one('uom.category', string="Category", | ||||
|  |                                   default=lambda self: self.env.ref( | ||||
|  |                                       'uom.product_uom_categ_kgm'), | ||||
|  |                                   help="Category") | ||||
|  |     cw_uom_id = fields.Many2one('uom.uom', string='CW-Uom', | ||||
|  |                                 domain="[('category_id', '=', category_id)]", | ||||
|  |                                 compute='_compute_cw_uom_id', | ||||
|  |                                 readonly=True, | ||||
|  |                                 help="Catch weight unit of measure") | ||||
|  |     cw_hide = fields.Boolean(string='Is CW Product', | ||||
|  |                              compute="_compute_cw_hide", | ||||
|  |                              default=False, help="Catch weight hide") | ||||
|  | 
 | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_hide(self): | ||||
|  |         """ Computes the cw_hide feature""" | ||||
|  |         for rec in self: | ||||
|  |             rec.cw_hide = bool(rec.product_id.catch_weight_ok) | ||||
|  | 
 | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_uom_id(self): | ||||
|  |         """Calculating cw uom""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 rec.cw_uom_id = rec.product_id.cw_uom_id | ||||
|  |             else: | ||||
|  |                 rec.cw_uom_id = None | ||||
|  | 
 | ||||
|  |     @api.depends('product_id', 'quantity') | ||||
|  |     def _compute_cw_qty(self): | ||||
|  |         """Calculating cw qty done""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 if rec.cw_uom_id == rec.uom_id: | ||||
|  |                     rec.quantity = rec.cw_qty | ||||
|  |                 else: | ||||
|  |                     rec.cw_qty = rec.quantity * rec.product_id.average_cw_qty | ||||
|  | 
 | ||||
|  |     @api.onchange('cw_qty') | ||||
|  |     def _onchange_cw_qty(self): | ||||
|  |         """Calculating cw qty from qty""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok and rec.product_id.average_cw_qty\ | ||||
|  |                     != 0: | ||||
|  |                 if rec.cw_uom_id == rec.uom_id: | ||||
|  |                     rec.quantity = rec.cw_qty | ||||
|  |                 else: | ||||
|  |                     rec.quantity = rec.cw_qty / rec.product_id.average_cw_qty | ||||
| @ -0,0 +1,83 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 ProductStockLocation(models.Model): | ||||
|  |     """ Inherits stock.quant """ | ||||
|  |     _inherit = "stock.quant" | ||||
|  | 
 | ||||
|  |     virtual_available = fields.Float(string='Forecasted Quantity', | ||||
|  |                                      compute="_compute_location_qty", | ||||
|  |                                      help="Forecasted Quantity") | ||||
|  |     incoming_qty = fields.Float(string='Incoming', compute="_compute_location_qty", | ||||
|  |                                 help="Incoming Quantity") | ||||
|  |     outgoing_qty = fields.Float(string='Outgoing', compute="_compute_location_qty", | ||||
|  |                                 help="Outgoing Quantity") | ||||
|  |     brand_id = fields.Many2one(related='product_id.brand_id', | ||||
|  |                                string='Brand', store=True, readonly=True, | ||||
|  |                                help="Product brand") | ||||
|  | 
 | ||||
|  |     def _compute_location_qty(self): | ||||
|  |         """Method to compute the quantity of incoming and outgoing stock.""" | ||||
|  |         for rec in self: | ||||
|  |             product = rec.product_id | ||||
|  |             rec.virtual_available = product.with_context( | ||||
|  |                 {'location': rec.location_id.id}).virtual_available | ||||
|  |             rec.incoming_qty = product.with_context( | ||||
|  |                 {'location': rec.location_id.id}).incoming_qty | ||||
|  |             rec.outgoing_qty = product.with_context( | ||||
|  |                 {'location': rec.location_id.id}).outgoing_qty | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_out_of_stock(self): | ||||
|  |         """rpc method of out of stock graph | ||||
|  |         Returns products and quantity""" | ||||
|  |         company_id = self.env.company.id | ||||
|  |         sett_out_stock_bool = self.env['ir.config_parameter'].sudo(). \ | ||||
|  |             get_param("inventory_stock_dashboard_odoo.out_of_stock", default="") | ||||
|  |         sett_out_stock_quantity = self.env['ir.config_parameter'].sudo(). \ | ||||
|  |             get_param("inventory_stock_dashboard_odoo.out_of_stock_quantity", | ||||
|  |                       default="") | ||||
|  |         if sett_out_stock_bool == "True": | ||||
|  |             if sett_out_stock_quantity: | ||||
|  |                 out_stock_value = int(sett_out_stock_quantity) | ||||
|  |                 query = '''select product_template.name,sum(stock_quant.quantity) | ||||
|  |                  from stock_quant inner join product_product on stock_quant. | ||||
|  |                  product_id = product_product.id inner join product_template on  | ||||
|  |                  product_product.product_tmpl_id = product_template.id  where  | ||||
|  |                  stock_quant.quantity < %s and stock_quant.company_id = %s group | ||||
|  |                  by product_template.name''' \ | ||||
|  |                  % (out_stock_value, company_id) | ||||
|  |                 self._cr.execute(query) | ||||
|  |                 result = self._cr.fetchall() | ||||
|  |                 total_quantity = [] | ||||
|  |                 for record in result: | ||||
|  |                     total_quantity.append(record[1]) | ||||
|  |                 product_name = [] | ||||
|  |                 for record in result: | ||||
|  |                     product_name.append(record[0]) | ||||
|  |                 value = { | ||||
|  |                     'product_name': product_name, | ||||
|  |                     'total_quantity': total_quantity | ||||
|  |                 } | ||||
|  |                 return value | ||||
| @ -0,0 +1,35 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 StockReturnInvoicePicking(models.TransientModel): | ||||
|  |     """ Inherits stock.return.picking """ | ||||
|  |     _inherit = 'stock.return.picking' | ||||
|  | 
 | ||||
|  |     def _create_returns(self): | ||||
|  |         """In this function the picking is marked as return""" | ||||
|  |         new_picking, pick_type_id = super(StockReturnInvoicePicking, | ||||
|  |                                           self)._create_returns() | ||||
|  |         picking = self.env['stock.picking'].browse(new_picking) | ||||
|  |         picking.write({'is_return': True}) | ||||
|  |         return new_picking, pick_type_id | ||||
| @ -0,0 +1,50 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 StockScrap(models.Model): | ||||
|  |     """inherits Stock Scrap""" | ||||
|  |     _inherit = 'stock.scrap' | ||||
|  | 
 | ||||
|  |     cw_qty = fields.Float(string='CW-Qty', digits=(16, 4), | ||||
|  |                           compute='_compute_cw_qty', | ||||
|  |                           help="Catch weight quantity") | ||||
|  |     category_id = fields.Many2one('uom.category', | ||||
|  |                                   help="Category of the scrap", | ||||
|  |                                   default=lambda self: | ||||
|  |                                   self.env.ref('uom.product_uom_categ_kgm')) | ||||
|  |     cw_uom_id = fields.Many2one('uom.uom', string='CW-Uom', | ||||
|  |                                 help="Catch weight unit of measure", | ||||
|  |                                 related='product_id.product_tmpl_id.cw_uom_id') | ||||
|  |     toggle_cw = fields.Boolean( | ||||
|  |         string='is_cw_product', | ||||
|  |         related='product_id.product_tmpl_id.catch_weight_ok', | ||||
|  |         help="Is cw stock") | ||||
|  | 
 | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_qty(self): | ||||
|  |         """computing the qty""" | ||||
|  |         self.cw_qty = 0 | ||||
|  |         if self.product_id.catch_weight_ok and self.product_id.average_cw_qty \ | ||||
|  |                 != 0: | ||||
|  |             self.cw_qty = self.product_id.average_cw_qty * self.scrap_qty | ||||
| @ -0,0 +1,66 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 StockValuationLayer(models.Model): | ||||
|  |     """Inherits stock valuation layer""" | ||||
|  |     _inherit = 'stock.valuation.layer' | ||||
|  | 
 | ||||
|  |     cw_qty_done = fields.Float(string='CW-Qty Done', | ||||
|  |                                compute='_compute_cw_qty_done', digits=(16, 4), | ||||
|  |                                help="Catch weight done quantity") | ||||
|  |     category_id = fields.Many2one('uom.category', | ||||
|  |                                   default=lambda self: self.env.ref( | ||||
|  |                                       'uom.product_uom_categ_kgm'), | ||||
|  |                                   help="Uom Category") | ||||
|  |     cw_uom_id = fields.Many2one('uom.uom', string='CW-Uom', | ||||
|  |                                 domain="[('category_id', '=', category_id)]", | ||||
|  |                                 compute='_compute_cw_uom_id', | ||||
|  |                                 help="Unit of measure") | ||||
|  |     cw_hide = fields.Boolean(string='Is CW Product', | ||||
|  |                              compute="_compute_cw_hide", default=False, | ||||
|  |                              help="Is catch weight hide") | ||||
|  | 
 | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_uom_id(self): | ||||
|  |         """Calculating cw uom""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 rec.cw_uom_id = rec.product_id.cw_uom_id | ||||
|  |             else: | ||||
|  |                 rec.cw_uom_id = None | ||||
|  | 
 | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_cw_hide(self): | ||||
|  |         """Compute hide cw_hide field""" | ||||
|  |         for rec in self: | ||||
|  |             rec.cw_hide = bool(rec.product_id.catch_weight_ok) | ||||
|  | 
 | ||||
|  |     @api.depends('product_id', 'quantity') | ||||
|  |     def _compute_cw_qty_done(self): | ||||
|  |         """Calculating cw qty done""" | ||||
|  |         for rec in self: | ||||
|  |             if rec.product_id.catch_weight_ok: | ||||
|  |                 rec.cw_qty_done = rec.quantity * rec.product_id.average_cw_qty | ||||
|  |             else: | ||||
|  |                 rec.cw_qty_done = 0 | ||||
| @ -0,0 +1,23 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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 inventory_pdf_report | ||||
|  | from . import product_stock_report | ||||
| @ -0,0 +1,39 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class PurchaseOrder(models.AbstractModel): | ||||
|  |     """ Creates report.all_in_one_inventory_kit.inventory_pdf_report """ | ||||
|  |     _name = 'report.all_in_one_inventory_kit.inventory_pdf_report' | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def _get_report_values(self, docids, data=None): | ||||
|  |         """ Takes report values """ | ||||
|  |         if self.env.context.get('inventory_pdf_report'): | ||||
|  |             if data.get('report_data'): | ||||
|  |                 data.update({'report_main_line_data': data.get('report_data') | ||||
|  |                 ['report_lines'], | ||||
|  |                              'Filters': data.get('report_data')['filters'], | ||||
|  |                              'company': self.env.company, | ||||
|  |                              }) | ||||
|  |             return data | ||||
| @ -0,0 +1,274 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!--    Dynamic inventory report action--> | ||||
|  |     <record id="dynamic_inventory_report_action" model="ir.actions.report"> | ||||
|  |         <field name="name">Inventory All In One Report</field> | ||||
|  |         <field name="model">dynamic.inventory.report</field> | ||||
|  |         <field name="report_type">qweb-pdf</field> | ||||
|  |         <field name="report_name">all_in_one_inventory_kit.inventory_pdf_report</field> | ||||
|  |         <field name="report_file">all_in_one_inventory_kit.inventory_pdf_report</field> | ||||
|  |         <field name="binding_type">report</field> | ||||
|  |     </record> | ||||
|  |     <template id="inventory_pdf_report"> | ||||
|  |         <t t-call="web.html_container"> | ||||
|  |             <t t-call="web.internal_layout"> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Transfers'"> | ||||
|  |                     <t t-call="all_in_one_inventory_kit.report_by_transfers"/> | ||||
|  |                 </t> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Categories'"> | ||||
|  |                     <t t-call="all_in_one_inventory_kit.report_by_categories"/> | ||||
|  |                 </t> | ||||
|  | 
 | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Warehouse'"> | ||||
|  |                     <t t-call="all_in_one_inventory_kit.report_by_warehouse"/> | ||||
|  |                 </t> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Location'"> | ||||
|  |                     <t t-call="all_in_one_inventory_kit.report_by_location"/> | ||||
|  |                 </t> | ||||
|  |             </t> | ||||
|  |         </t> | ||||
|  |     </template> | ||||
|  |     <!--    Report by transfers template--> | ||||
|  |     <template id="report_by_transfers"> | ||||
|  |         <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-3"> | ||||
|  |                             <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" class="text-left">Reference</th> | ||||
|  |                             <th colspan="6" class="text-center">Scheduled | ||||
|  |                                 Date | ||||
|  |                             </th> | ||||
|  |                             <th colspan="6" class="text-right">Source | ||||
|  |                                 Document | ||||
|  |                             </th> | ||||
|  |                             <th colspan="6" class="text-right">Company</th> | ||||
|  |                             <th colspan="6" class="text-center">Delivery | ||||
|  |                                 Address | ||||
|  |                             </th> | ||||
|  |                             <th colspan="6" class="text-left">State</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['name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['scheduled_date']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['origin']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['company']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['partner']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['state']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--    Report by categories template--> | ||||
|  |     <template id="report_by_categories"> | ||||
|  |         <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-3"> | ||||
|  |                             <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">Category</th> | ||||
|  |                             <th colspan="6">Product Name</th> | ||||
|  |                             <th colspan="6" class="text-right">Create Date</th> | ||||
|  |                             <th colspan="6" class="text-center">Product Cost | ||||
|  |                             </th> | ||||
|  |                             <th colspan="6" class="text-center">On Hand Qty | ||||
|  |                             </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['category']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['name']['en_US']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['create_date']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['value_float']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['quantity']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--    Report by warehouse template--> | ||||
|  |     <template id="report_by_warehouse"> | ||||
|  |         <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-3"> | ||||
|  |                             <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" class="text-left">Warehouse</th> | ||||
|  |                             <th colspan="6" class="text-center">Date</th> | ||||
|  |                             <th colspan="6" class="text-right">Company</th> | ||||
|  |                             <th colspan="6" class="text-right">Location</th> | ||||
|  |                             <th colspan="6" class="text-center">Route</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['name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['write_date']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['company']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['location']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['route']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--    Report by location template--> | ||||
|  |     <template id="report_by_location"> | ||||
|  |         <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-3"> | ||||
|  |                             <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">Location</th> | ||||
|  |                             <th colspan="6">Location Type</th> | ||||
|  |                             <th colspan="6">Create Date</th> | ||||
|  |                             <th colspan="6">Company</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['complete_name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['location_type']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['create_date']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['company']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,13 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | <odoo> | ||||
|  |     <!--    Inventory all report client action--> | ||||
|  |     <record id="inventory_all_report_client_action" model="ir.actions.client"> | ||||
|  |         <field name="name">All In One Inventory Report</field> | ||||
|  |         <field name="tag">inv_r</field> | ||||
|  |     </record> | ||||
|  |     <!--    Inventory menu--> | ||||
|  |     <menuitem action="inventory_all_report_client_action" | ||||
|  |               parent="stock.menu_warehouse_report" | ||||
|  |               id="inventory_report_sub_menu" | ||||
|  |               name="All In One Inventory Report"/> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,11 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!--    Product.product pdf report action --> | ||||
|  |     <record id="product_product_report_action" model="ir.actions.report"> | ||||
|  |         <field name="name">Stock Details</field> | ||||
|  |         <field name="model">product.product</field> | ||||
|  |         <field name="report_type">qweb-pdf</field> | ||||
|  |         <field name="report_name">all_in_one_inventory_kit.report_product_stock_template</field> | ||||
|  |         <field name="report_file">all_in_one_inventory_kit.report_product_stock_template</field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,37 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ################################################################################ | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Mohammed Dilshad Tk (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, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ProductStockDetails(models.AbstractModel): | ||||
|  |     """Creates report.all_in_one_inventory_kit.report_product_stock_template""" | ||||
|  |     _name = 'report.all_in_one_inventory_kit.report_product_stock_template' | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def _get_report_values(self, docids, data): | ||||
|  |         """Method for getting report values.""" | ||||
|  |         docs = self.env.context.get('active_ids') | ||||
|  |         if docs is None: | ||||
|  |             docs = docids | ||||
|  |         return { | ||||
|  |             'data': self.env['product.product'].search([('id', 'in', docs)]) | ||||
|  |         } | ||||
| @ -0,0 +1,115 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!--    Report template--> | ||||
|  |     <template id="report_product_stock_template"> | ||||
|  |         <t t-call="web.html_container"> | ||||
|  |             <t t-call="web.external_layout"> | ||||
|  |                 <div class="page"> | ||||
|  |                     <div> | ||||
|  |                         <div class="text-left ml-auto"> | ||||
|  |                             <strong>Date: | ||||
|  |                                 <span t-esc="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d')"/> | ||||
|  |                             </strong> | ||||
|  |                             <br/> | ||||
|  |                             <b>Product : | ||||
|  |                                 <t t-esc="data.name"/> | ||||
|  |                             </b> | ||||
|  |                             <br/><br/> | ||||
|  |                         </div> | ||||
|  |                         <table style="border:2px solid black;" | ||||
|  |                                class="table table-sm o_main_table"> | ||||
|  |                             <t t-set="qty_available" t-value="0"/> | ||||
|  |                             <t t-set="qty_forecasted" t-value="0"/> | ||||
|  |                             <t t-set="qty_incoming" t-value="0"/> | ||||
|  |                             <t t-set="qty_outgoing" t-value="0"/> | ||||
|  |                             <tbody style="border:2px solid black;"> | ||||
|  |                                 <tr style="border:2px solid black;" | ||||
|  |                                     align="center"> | ||||
|  |                                     <th style="border:2px solid black;"> | ||||
|  |                                         Location | ||||
|  |                                     </th> | ||||
|  |                                     <th style="border:2px solid black;"> | ||||
|  |                                         Available Qty | ||||
|  |                                     </th> | ||||
|  |                                     <th style="border:2px solid black;"> | ||||
|  |                                         Forecasted Qty | ||||
|  |                                     </th> | ||||
|  |                                     <th style="border:2px solid black;">Incoming | ||||
|  |                                         Qty | ||||
|  |                                     </th> | ||||
|  |                                     <th style="border:2px solid black;">Outgoing | ||||
|  |                                         Qty | ||||
|  |                                     </th> | ||||
|  |                                 </tr> | ||||
|  |                                 <t t-foreach="data.product_stock_location_ids" | ||||
|  |                                    t-as="t"> | ||||
|  |                                     <tr style="border:2px solid black;"> | ||||
|  |                                         <td style="border:2px solid black;" | ||||
|  |                                             align="left"> | ||||
|  |                                             <span t-esc="t.location_id.display_name"/> | ||||
|  |                                         </td> | ||||
|  |                                         <td style="border:2px solid black;" | ||||
|  |                                             align="right"> | ||||
|  |                                             <span t-field="t.available_quantity"/> | ||||
|  |                                         </td> | ||||
|  |                                         <td style="border:2px solid black;" | ||||
|  |                                             align="right"> | ||||
|  |                                             <span t-field="t.virtual_available"/> | ||||
|  |                                         </td> | ||||
|  |                                         <td style="border:2px solid black;" | ||||
|  |                                             align="right"> | ||||
|  |                                             <span t-field="t.incoming_qty"/> | ||||
|  |                                         </td> | ||||
|  |                                         <td style="border:2px solid black;" | ||||
|  |                                             align="right"> | ||||
|  |                                             <span t-field="t.outgoing_qty"/> | ||||
|  |                                         </td> | ||||
|  |                                     </tr> | ||||
|  |                                     <t t-set="qty_available" | ||||
|  |                                        t-value="qty_available+t.available_quantity"/> | ||||
|  |                                     <t t-set="qty_forecasted" | ||||
|  |                                        t-value="qty_forecasted+t.virtual_available"/> | ||||
|  |                                     <t t-set="qty_incoming" | ||||
|  |                                        t-value="qty_incoming+t.incoming_qty"/> | ||||
|  |                                     <t t-set="qty_outgoing" | ||||
|  |                                        t-value="qty_outgoing+t.outgoing_qty"/> | ||||
|  |                                 </t> | ||||
|  |                                 <tr> | ||||
|  |                                     <td style="border:2px solid black;" | ||||
|  |                                         align="right"> | ||||
|  |                                         <strong>Total:</strong> | ||||
|  |                                     </td> | ||||
|  |                                     <td style="border:2px solid black;" | ||||
|  |                                         align="right"> | ||||
|  |                                         <span> | ||||
|  |                                             <t t-esc="qty_available"/> | ||||
|  |                                         </span> | ||||
|  |                                     </td> | ||||
|  | 
 | ||||
|  |                                     <td style="border:2px solid black;" | ||||
|  |                                         align="right"> | ||||
|  |                                         <span> | ||||
|  |                                             <t t-esc="qty_forecasted"/> | ||||
|  |                                         </span> | ||||
|  |                                     </td> | ||||
|  |                                     <td style="border:2px solid black;" | ||||
|  |                                         align="right"> | ||||
|  |                                         <span> | ||||
|  |                                             <t t-esc="qty_incoming"/> | ||||
|  |                                         </span> | ||||
|  |                                     </td> | ||||
|  |                                     <td style="border:2px solid black;" | ||||
|  |                                         align="right"> | ||||
|  |                                         <span> | ||||
|  |                                             <t t-esc="qty_outgoing"/> | ||||
|  |                                         </span> | ||||
|  |                                     </td> | ||||
|  |                                 </tr> | ||||
|  |                             </tbody> | ||||
|  |                         </table> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  |             </t> | ||||
|  |         </t> | ||||
|  |     </template> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,43 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!--For adding the description field on the delivery report--> | ||||
|  |     <template id="report_delivery_document_description" | ||||
|  |               inherit_id="stock.report_delivery_document"> | ||||
|  |         <xpath expr="//div[hasclass('page')]/table/thead/tr/th[@name='th_sm_product']" | ||||
|  |                position="after"> | ||||
|  |             <th name="th_sm_description"> | ||||
|  |                 <strong>Description</strong> | ||||
|  |             </th> | ||||
|  |         </xpath> | ||||
|  |         <xpath expr="//div[hasclass('page')]/table/tbody/tr/td[1]" | ||||
|  |                position="after"> | ||||
|  |             <td> | ||||
|  |                 <t t-esc="move.name"/> | ||||
|  |             </td> | ||||
|  |         </xpath> | ||||
|  |         <xpath expr="//div[hasclass('page')]/table[2]/thead/tr/th[@name='th_sml_product']" | ||||
|  |                position="after"> | ||||
|  |             <th name="th_sml_description"> | ||||
|  |                 <strong>Description</strong> | ||||
|  |             </th> | ||||
|  |         </xpath> | ||||
|  |     </template> | ||||
|  |     <!-- If printing lots/serial numbers => keep products in original lines --> | ||||
|  |     <template id="report_delivery_has_serial_move_line_description" | ||||
|  |               inherit_id="stock.stock_report_delivery_has_serial_move_line"> | ||||
|  |         <xpath expr="//td[1]" position="after"> | ||||
|  |             <td> | ||||
|  |                 <span t-field="move_line.name"/> | ||||
|  |             </td> | ||||
|  |         </xpath> | ||||
|  |     </template> | ||||
|  |     <!-- If not printing lots/serial numbers => merge lines with same product+description+uom --> | ||||
|  |     <template id="report_delivery_aggregated_move_lines_description" | ||||
|  |               inherit_id="stock.stock_report_delivery_aggregated_move_lines"> | ||||
|  |         <xpath expr="//td[1]" position="after"> | ||||
|  |             <td> | ||||
|  |                 <span t-esc="aggregated_lines[line]['name']"/> | ||||
|  |             </td> | ||||
|  |         </xpath> | ||||
|  |     </template> | ||||
|  | </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: 80 KiB | 
| After Width: | Height: | Size: 79 KiB | 
| After Width: | Height: | Size: 74 KiB | 
| After Width: | Height: | Size: 71 KiB | 
| After Width: | Height: | Size: 85 KiB | 
| After Width: | Height: | Size: 81 KiB | 
| After Width: | Height: | Size: 86 KiB | 
| After Width: | Height: | Size: 113 KiB | 
| After Width: | Height: | Size: 16 KiB | 
| After Width: | Height: | Size: 29 KiB | 
| After Width: | Height: | Size: 126 KiB | 
| After Width: | Height: | Size: 49 KiB | 
| After Width: | Height: | Size: 78 KiB | 
| After Width: | Height: | Size: 85 KiB | 
| After Width: | Height: | Size: 180 KiB | 
| After Width: | Height: | Size: 92 KiB | 
| After Width: | Height: | Size: 25 KiB | 
| After Width: | Height: | Size: 74 KiB | 
| After Width: | Height: | Size: 88 KiB | 
| After Width: | Height: | Size: 83 KiB | 
| After Width: | Height: | Size: 62 KiB | 
| After Width: | Height: | Size: 92 KiB | 
| After Width: | Height: | Size: 52 KiB | 
| After Width: | Height: | Size: 148 KiB | 
| After Width: | Height: | Size: 141 KiB | 
| After Width: | Height: | Size: 171 KiB | 
| After Width: | Height: | Size: 98 KiB | 
| After Width: | Height: | Size: 48 KiB | 
| After Width: | Height: | Size: 104 KiB | 
| After Width: | Height: | Size: 109 KiB | 
| After Width: | Height: | Size: 86 KiB | 
| After Width: | Height: | Size: 103 KiB | 
| After Width: | Height: | Size: 61 KiB | 
| After Width: | Height: | Size: 43 KiB | 
| After Width: | Height: | Size: 139 KiB | 
| After Width: | Height: | Size: 84 KiB |