Browse Source

Jan 01 [ADD] : Initial Commit 'all_in_one_inventory_kit'

pull/254/merge
AjmalCybro 4 months ago
parent
commit
51ab581545
  1. 46
      all_in_one_inventory_kit/README.rst
  2. 25
      all_in_one_inventory_kit/__init__.py
  3. 86
      all_in_one_inventory_kit/__manifest__.py
  4. 22
      all_in_one_inventory_kit/controllers/__init__.py
  5. 63
      all_in_one_inventory_kit/controllers/all_in_one_report_excel.py
  6. 6
      all_in_one_inventory_kit/doc/RELEASE_NOTES.md
  7. 36
      all_in_one_inventory_kit/models/__init__.py
  8. 143
      all_in_one_inventory_kit/models/account_move.py
  9. 78
      all_in_one_inventory_kit/models/account_move_line.py
  10. 362
      all_in_one_inventory_kit/models/inventory_report.py
  11. 42
      all_in_one_inventory_kit/models/product_brand.py
  12. 38
      all_in_one_inventory_kit/models/product_product.py
  13. 51
      all_in_one_inventory_kit/models/product_template.py
  14. 59
      all_in_one_inventory_kit/models/res_config_settings.py
  15. 437
      all_in_one_inventory_kit/models/stock_move.py
  16. 155
      all_in_one_inventory_kit/models/stock_move_line.py
  17. 385
      all_in_one_inventory_kit/models/stock_picking.py
  18. 77
      all_in_one_inventory_kit/models/stock_picking_return_line.py
  19. 85
      all_in_one_inventory_kit/models/stock_quant.py
  20. 35
      all_in_one_inventory_kit/models/stock_return_picking.py
  21. 50
      all_in_one_inventory_kit/models/stock_scrap.py
  22. 66
      all_in_one_inventory_kit/models/stock_valuation_layer.py
  23. 23
      all_in_one_inventory_kit/reports/__init__.py
  24. 39
      all_in_one_inventory_kit/reports/inventory_pdf_report.py
  25. 274
      all_in_one_inventory_kit/reports/inventory_pdf_report.xml
  26. 13
      all_in_one_inventory_kit/reports/inventory_report.xml
  27. 11
      all_in_one_inventory_kit/reports/product_product_stock_report.xml
  28. 37
      all_in_one_inventory_kit/reports/product_stock_report.py
  29. 115
      all_in_one_inventory_kit/reports/product_stock_report_template.xml
  30. 43
      all_in_one_inventory_kit/reports/stock_picking_report.xml
  31. 6
      all_in_one_inventory_kit/security/ir.model.access.csv
  32. BIN
      all_in_one_inventory_kit/static/description/assets/icons/check.png
  33. BIN
      all_in_one_inventory_kit/static/description/assets/icons/chevron.png
  34. BIN
      all_in_one_inventory_kit/static/description/assets/icons/cogs.png
  35. BIN
      all_in_one_inventory_kit/static/description/assets/icons/consultation.png
  36. BIN
      all_in_one_inventory_kit/static/description/assets/icons/ecom-black.png
  37. BIN
      all_in_one_inventory_kit/static/description/assets/icons/education-black.png
  38. BIN
      all_in_one_inventory_kit/static/description/assets/icons/hotel-black.png
  39. BIN
      all_in_one_inventory_kit/static/description/assets/icons/license.png
  40. BIN
      all_in_one_inventory_kit/static/description/assets/icons/lifebuoy.png
  41. BIN
      all_in_one_inventory_kit/static/description/assets/icons/manufacturing-black.png
  42. BIN
      all_in_one_inventory_kit/static/description/assets/icons/pos-black.png
  43. BIN
      all_in_one_inventory_kit/static/description/assets/icons/puzzle.png
  44. BIN
      all_in_one_inventory_kit/static/description/assets/icons/restaurant-black.png
  45. BIN
      all_in_one_inventory_kit/static/description/assets/icons/service-black.png
  46. BIN
      all_in_one_inventory_kit/static/description/assets/icons/trading-black.png
  47. BIN
      all_in_one_inventory_kit/static/description/assets/icons/training.png
  48. BIN
      all_in_one_inventory_kit/static/description/assets/icons/update.png
  49. BIN
      all_in_one_inventory_kit/static/description/assets/icons/user.png
  50. BIN
      all_in_one_inventory_kit/static/description/assets/icons/wrench.png
  51. BIN
      all_in_one_inventory_kit/static/description/assets/misc/categories.png
  52. BIN
      all_in_one_inventory_kit/static/description/assets/misc/check-box.png
  53. BIN
      all_in_one_inventory_kit/static/description/assets/misc/compass.png
  54. BIN
      all_in_one_inventory_kit/static/description/assets/misc/corporate.png
  55. BIN
      all_in_one_inventory_kit/static/description/assets/misc/customer-support.png
  56. BIN
      all_in_one_inventory_kit/static/description/assets/misc/cybrosys-logo.png
  57. BIN
      all_in_one_inventory_kit/static/description/assets/misc/features.png
  58. BIN
      all_in_one_inventory_kit/static/description/assets/misc/logo.png
  59. BIN
      all_in_one_inventory_kit/static/description/assets/misc/pictures.png
  60. BIN
      all_in_one_inventory_kit/static/description/assets/misc/pie-chart.png
  61. BIN
      all_in_one_inventory_kit/static/description/assets/misc/right-arrow.png
  62. BIN
      all_in_one_inventory_kit/static/description/assets/misc/star.png
  63. BIN
      all_in_one_inventory_kit/static/description/assets/misc/support.png
  64. BIN
      all_in_one_inventory_kit/static/description/assets/misc/whatsapp.png
  65. BIN
      all_in_one_inventory_kit/static/description/assets/modules/1.png
  66. BIN
      all_in_one_inventory_kit/static/description/assets/modules/2.png
  67. BIN
      all_in_one_inventory_kit/static/description/assets/modules/3.png
  68. BIN
      all_in_one_inventory_kit/static/description/assets/modules/4.png
  69. BIN
      all_in_one_inventory_kit/static/description/assets/modules/5.png
  70. BIN
      all_in_one_inventory_kit/static/description/assets/modules/6.png
  71. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/1.png
  72. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/10.png
  73. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/11.png
  74. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/12.png
  75. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/13.png
  76. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/14.png
  77. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/15.png
  78. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/16.png
  79. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/17.png
  80. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/18.png
  81. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/19.png
  82. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/2.png
  83. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/20.png
  84. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/21.png
  85. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/22.png
  86. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/23.png
  87. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/24.png
  88. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/25.png
  89. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/26.png
  90. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/27.png
  91. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/28.png
  92. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/29.png
  93. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/3.png
  94. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/30.png
  95. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/31.png
  96. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/32.png
  97. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/33.png
  98. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/34.png
  99. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/35.png
  100. BIN
      all_in_one_inventory_kit/static/description/assets/screenshots/36.png

46
all_in_one_inventory_kit/README.rst

@ -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>`__

25
all_in_one_inventory_kit/__init__.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

86
all_in_one_inventory_kit/__manifest__.py

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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': '15.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',
],
'web.assets_qweb': [
'all_in_one_inventory_kit/static/src/xml/**/*',
],
},
'images': ['static/description/banner.png'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False
}

22
all_in_one_inventory_kit/controllers/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

63
all_in_one_inventory_kit/controllers/all_in_one_report_excel.py

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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)))

6
all_in_one_inventory_kit/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <all_in_one_inventory_kit>
#### 16.12.2024
#### Version 15.0.1.0.0
#### ADD
- Initial commit for All in One Inventory Kit

36
all_in_one_inventory_kit/models/__init__.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

143
all_in_one_inventory_kit/models/account_move.py

@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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="Choose the Picking")
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 the "
"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',
help='Check whether transfer is 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

78
all_in_one_inventory_kit/models/account_move_line.py

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

362
all_in_one_inventory_kit/models/inventory_report.py

@ -0,0 +1,362 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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_location_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_location_route on
stock_location_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()

42
all_in_one_inventory_kit/models/product_brand.py

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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="Products in a brand")
product_count = fields.Char(string='Product Count',
compute='_compute_get_count_products', store=True,
help="Count of the products")
@api.depends('member_ids')
def _compute_get_count_products(self):
"""Show count of products"""
self.product_count = len(self.member_ids)

38
all_in_one_inventory_kit/models/product_product.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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="Locations of the"
" products in stock")
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='')

51
all_in_one_inventory_kit/models/product_template.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

59
all_in_one_inventory_kit/models/res_config_settings.py

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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")

437
all_in_one_inventory_kit/models/stock_move.py

@ -0,0 +1,437 @@
# -*- coding: utf-8 -*-
###############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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="Product 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='_compute_cal_cw_demand',
help="Catch weight demand")
cw_reserved = fields.Float(string='CW-Reserved',
compute='_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 _compute_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
self.env.cr.execute('''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,))
top_product = self._cr.dictfetchall()
total_quantity = []
product_name = []
for record in top_product[:10]:
total_quantity.append(record['sum'])
product_name.append(record['name'])
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
self.env.cr.execute('''
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_picking_type.code = 'outgoing'
AND stock_move.create_date BETWEEN (now() - interval '10 day') AND now()
AND stock_move.company_id = %s
GROUP BY product_template.name
ORDER BY SUM(stock_move.product_uom_qty) DESC
''', (company_id,))
top_product = self.env.cr.fetchall()
total_quantity = []
product_name = []
for record in top_product[:10]:
total_quantity.append(record[1])
product_name.append(record[0])
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
self.env.cr.execute('''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,))
top_product = self._cr.dictfetchall()
total_quantity = []
product_name = []
for record in top_product[:10]:
total_quantity.append(record['sum'])
product_name.append(record['name'])
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
self.env.cr.execute('''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 '90 day')
and now() group by product_template.name ORDER BY sum DESC''',
(company_id,))
top_product = self._cr.dictfetchall()
total_quantity = []
product_name = []
for record in top_product[:10]:
total_quantity.append(record['sum'])
product_name.append(record['name'])
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().date()
start_last_year = datetime(now.year - 1, 1, 1)
end_last_year = datetime(now.year - 1, 12, 31, 23, 59, 59)
self.env.cr.execute('''
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
''', (company_id, start_last_year, end_last_year))
top_product = self.env.cr.dictfetchall()
total_quantity = []
product_name = []
for record in top_product[:10]:
total_quantity.append(record['sum'])
product_name.append(record['name'])
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

155
all_in_one_inventory_kit/models/stock_move_line.py

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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_without_package.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
self.env.cr.execute('''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))
product_move = self._cr.dictfetchall()
quantity_done = []
name = []
for record in product_move:
quantity_done.append(record['sum'])
name.append(record['name'])
value = {
'name': name,
'count': quantity_done,
}
return value

385
all_in_one_inventory_kit/models/stock_picking.py

@ -0,0 +1,385 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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',
help="Is invoice is created")
@api.onchange('barcode')
def _onchange_barcode(self):
""" Scanning the barcode """
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'
}
def action_open_picking_bills(self):
"""This is the function of the smart button which redirect to the
invoice related to the current picking"""
return {
'name': 'Bills',
'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

77
all_in_one_inventory_kit/models/stock_picking_return_line.py

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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",
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

85
all_in_one_inventory_kit/models/stock_quant.py

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

35
all_in_one_inventory_kit/models/stock_return_picking.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

50
all_in_one_inventory_kit/models/stock_scrap.py

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

66
all_in_one_inventory_kit/models/stock_valuation_layer.py

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

23
all_in_one_inventory_kit/reports/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

39
all_in_one_inventory_kit/reports/inventory_pdf_report.py

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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

274
all_in_one_inventory_kit/reports/inventory_pdf_report.xml

@ -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>

13
all_in_one_inventory_kit/reports/inventory_report.xml

@ -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>

11
all_in_one_inventory_kit/reports/product_product_stock_report.xml

@ -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>

37
all_in_one_inventory_kit/reports/product_stock_report.py

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Saneen K (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)])
}

115
all_in_one_inventory_kit/reports/product_stock_report_template.xml

@ -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>

43
all_in_one_inventory_kit/reports/stock_picking_report.xml

@ -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>

6
all_in_one_inventory_kit/security/ir.model.access.csv

@ -0,0 +1,6 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_wizard_stock_history_user,wizard.stock.history,model_wizard_stock_history,base.group_user,1,1,1,1
access_product_brand,access.product.brand,model_product_brand,base.group_user,1,1,1,1
access_dynamic_inventory_report,access.dynamic.inventory.report,model_dynamic_inventory_report,base.group_user,1,1,1,1
access_picking_invoice_wizard_manager_id,access.picking.invoice.wizard.manager,model_picking_invoice_wizard,base.group_erp_manager,1,1,1,1
access_picking_invoice_wizard_user_id,access.picking.invoice.wizard.user,model_picking_invoice_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_wizard_stock_history_user wizard.stock.history model_wizard_stock_history base.group_user 1 1 1 1
3 access_product_brand access.product.brand model_product_brand base.group_user 1 1 1 1
4 access_dynamic_inventory_report access.dynamic.inventory.report model_dynamic_inventory_report base.group_user 1 1 1 1
5 access_picking_invoice_wizard_manager_id access.picking.invoice.wizard.manager model_picking_invoice_wizard base.group_erp_manager 1 1 1 1
6 access_picking_invoice_wizard_user_id access.picking.invoice.wizard.user model_picking_invoice_wizard base.group_user 1 1 1 1

BIN
all_in_one_inventory_kit/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
all_in_one_inventory_kit/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
all_in_one_inventory_kit/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
all_in_one_inventory_kit/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
all_in_one_inventory_kit/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
all_in_one_inventory_kit/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
all_in_one_inventory_kit/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
all_in_one_inventory_kit/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
all_in_one_inventory_kit/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
all_in_one_inventory_kit/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
all_in_one_inventory_kit/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
all_in_one_inventory_kit/static/description/assets/modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
all_in_one_inventory_kit/static/description/assets/modules/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
all_in_one_inventory_kit/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
all_in_one_inventory_kit/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
all_in_one_inventory_kit/static/description/assets/modules/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
all_in_one_inventory_kit/static/description/assets/modules/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/17.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/18.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/19.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/20.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/21.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/22.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/23.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/24.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/25.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/26.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/27.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/28.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/29.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/30.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/31.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/33.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/34.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/35.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

BIN
all_in_one_inventory_kit/static/description/assets/screenshots/36.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save