Browse Source

Nov 29 : [ADD] Initial Commit 'purchase_dashboard_advanced'

pull/254/merge
RisvanaCybro 1 year ago
parent
commit
2787201bbb
  1. 49
      purchase_dashboard_advanced/README.rst
  2. 22
      purchase_dashboard_advanced/__init__.py
  3. 56
      purchase_dashboard_advanced/__manifest__.py
  4. 7
      purchase_dashboard_advanced/doc/RELEASE_NOTES.md
  5. 22
      purchase_dashboard_advanced/models/__init__.py
  6. 657
      purchase_dashboard_advanced/models/purchase_order.py
  7. BIN
      purchase_dashboard_advanced/static/description/assets/icons/check.png
  8. BIN
      purchase_dashboard_advanced/static/description/assets/icons/chevron.png
  9. BIN
      purchase_dashboard_advanced/static/description/assets/icons/cogs.png
  10. BIN
      purchase_dashboard_advanced/static/description/assets/icons/consultation.png
  11. BIN
      purchase_dashboard_advanced/static/description/assets/icons/ecom-black.png
  12. BIN
      purchase_dashboard_advanced/static/description/assets/icons/education-black.png
  13. BIN
      purchase_dashboard_advanced/static/description/assets/icons/hotel-black.png
  14. BIN
      purchase_dashboard_advanced/static/description/assets/icons/license.png
  15. BIN
      purchase_dashboard_advanced/static/description/assets/icons/lifebuoy.png
  16. BIN
      purchase_dashboard_advanced/static/description/assets/icons/manufacturing-black.png
  17. BIN
      purchase_dashboard_advanced/static/description/assets/icons/pos-black.png
  18. BIN
      purchase_dashboard_advanced/static/description/assets/icons/puzzle.png
  19. BIN
      purchase_dashboard_advanced/static/description/assets/icons/restaurant-black.png
  20. BIN
      purchase_dashboard_advanced/static/description/assets/icons/service-black.png
  21. BIN
      purchase_dashboard_advanced/static/description/assets/icons/trading-black.png
  22. BIN
      purchase_dashboard_advanced/static/description/assets/icons/training.png
  23. BIN
      purchase_dashboard_advanced/static/description/assets/icons/update.png
  24. BIN
      purchase_dashboard_advanced/static/description/assets/icons/user.png
  25. BIN
      purchase_dashboard_advanced/static/description/assets/icons/wrench.png
  26. BIN
      purchase_dashboard_advanced/static/description/assets/misc/categories.png
  27. BIN
      purchase_dashboard_advanced/static/description/assets/misc/check-box.png
  28. BIN
      purchase_dashboard_advanced/static/description/assets/misc/compass.png
  29. BIN
      purchase_dashboard_advanced/static/description/assets/misc/corporate.png
  30. BIN
      purchase_dashboard_advanced/static/description/assets/misc/customer-support.png
  31. BIN
      purchase_dashboard_advanced/static/description/assets/misc/cybrosys-logo.png
  32. BIN
      purchase_dashboard_advanced/static/description/assets/misc/features.png
  33. BIN
      purchase_dashboard_advanced/static/description/assets/misc/logo.png
  34. BIN
      purchase_dashboard_advanced/static/description/assets/misc/pictures.png
  35. BIN
      purchase_dashboard_advanced/static/description/assets/misc/pie-chart.png
  36. BIN
      purchase_dashboard_advanced/static/description/assets/misc/right-arrow.png
  37. BIN
      purchase_dashboard_advanced/static/description/assets/misc/star.png
  38. BIN
      purchase_dashboard_advanced/static/description/assets/misc/support.png
  39. BIN
      purchase_dashboard_advanced/static/description/assets/misc/whatsapp.png
  40. BIN
      purchase_dashboard_advanced/static/description/assets/modules/1.png
  41. BIN
      purchase_dashboard_advanced/static/description/assets/modules/2.jpg
  42. BIN
      purchase_dashboard_advanced/static/description/assets/modules/3.png
  43. BIN
      purchase_dashboard_advanced/static/description/assets/modules/4.png
  44. BIN
      purchase_dashboard_advanced/static/description/assets/modules/5.png
  45. BIN
      purchase_dashboard_advanced/static/description/assets/modules/6.png
  46. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/1.png
  47. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/2.png
  48. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/dashboard_community.png
  49. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/dashboard_enterprise.png
  50. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/dashboard_tiles.png
  51. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/gif.zip
  52. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/gif/1.png
  53. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/gif/2.png
  54. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/gif/3.png
  55. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/gif/4.png
  56. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/gif/5.png
  57. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/gif/6.png
  58. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/hero.gif
  59. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/pending_arrivals.png
  60. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/product_category_analysis.png
  61. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/purchase_vendor_analysis.png
  62. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/purchases_by_month.png
  63. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/tiles.png
  64. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/top_charts.png
  65. BIN
      purchase_dashboard_advanced/static/description/assets/screenshots/upcoming_arrivals.png
  66. BIN
      purchase_dashboard_advanced/static/description/banner.png
  67. BIN
      purchase_dashboard_advanced/static/description/icon.png
  68. 610
      purchase_dashboard_advanced/static/description/index.html
  69. 349
      purchase_dashboard_advanced/static/src/css/style.css
  70. 734
      purchase_dashboard_advanced/static/src/js/dashboard.js
  71. 309
      purchase_dashboard_advanced/static/src/xml/purchase_dashboard_templates.xml
  72. 13
      purchase_dashboard_advanced/views/purchase_dashboard_menus.xml

49
purchase_dashboard_advanced/README.rst

@ -0,0 +1,49 @@
.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
Purchase Dashboard
==================
A dashboard for keeping track and evaluate various aspects of spending on purchases.
Installation
============
- www.odoo.com/documentation/15.0/setup/install.html
- Install our custom addon
License
-------
General Public License, Version 3 (LGPL v3).
(https://www.gnu.org/licenses/lgpl-3.0-standalone.html)
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
-------
* Developers:(V15) Neethu U M,
Anfas Faisal K ,
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>`__

22
purchase_dashboard_advanced/__init__.py

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

56
purchase_dashboard_advanced/__manifest__.py

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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/>.
#
#############################################################################
{
'name': "Purchase Dashboard",
'version': '15.0.1.0.0',
'category': 'Purchases',
'summary': "Elevate your financial awareness with our comprehensive "
"Purchase Analysis Dashboard",
'description': "Empower your financial insights with our all-in-one "
"Purchase Analysis Dashboard. Effortlessly track and "
"evaluate purchase expenditures on a monthly and yearly "
"basis, identify top and priority products, and stay "
"informed about upcoming purchase details",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
'depends': ['purchase'],
'data': [
'views/purchase_dashboard_menus.xml'
],
'assets': {
'web.assets_backend': [
'purchase_dashboard_advanced/static/src/js/dashboard.js',
'purchase_dashboard_advanced/static/src/css/style.css',
'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.js',
],
'web.assets_qweb': [
'purchase_dashboard_advanced/static/src/xml/purchase_dashboard_templates.xml',
],
},
'images': ['static/description/banner.png'],
'license': "LGPL-3",
'installable': True,
'auto_install': False,
'application': False,
}

7
purchase_dashboard_advanced/doc/RELEASE_NOTES.md

@ -0,0 +1,7 @@
## Module <purchase_dashboard_advanced>
#### 02.11.2023
#### Version 15.0.1.0.0
#### ADD
- Initial commit for Purchase Dashboard

22
purchase_dashboard_advanced/models/__init__.py

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

657
purchase_dashboard_advanced/models/purchase_order.py

@ -0,0 +1,657 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.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 calendar
from datetime import datetime
from odoo import api, models
class PurchaseOrder(models.Model):
"""
Inherits the Purchase Order Model and Extends Its Functionality.
This class extends the Odoo Purchase Order model to provide custom methods
for retrieving various purchase-related data, including purchase data for
display in tiles, yearly, monthly, weekly, and today's purchase data,
top chart data, orders by month, purchase vendors, purchase vendor details,
pending purchase data, and upcoming purchase data.
"""
_inherit = 'purchase.order'
@api.model
def get_purchase_data(self):
"""
Get purchase data for display in tiles.
This method retrieves data related to purchase orders, including
the count of purchase orders in 'purchase' and 'done' states,
the total purchase amount, the count of priority orders, and
the total count of vendors associated with purchase orders.
Returns:
dict: A dictionary containing the following purchase data:
- 'purchase_orders': Count of purchase orders.
- 'purchase_amount': Total purchase amount.
- 'priority_orders': Count of priority orders.
- 'vendors': Total count of vendors.
"""
orders = self.env['purchase.order'].search_count([('state', 'in', [
'purchase', 'done'])])
priority_orders = self.env['purchase.order'].search_count([
('priority', '=', '1')])
vendor_count = self.env['purchase.order'].search_count([
('state', 'in', ['purchase', 'done'])])
return {
'purchase_orders': orders,
'purchase_amount': sum(order.amount_total for order in
self.env['purchase.order'].search(
[('state', 'in', ['purchase',
'done'])])),
'priority_orders': priority_orders,
'vendors': vendor_count
}
def get_yearly_data(self):
"""
Get yearly purchase data for the current company.
Returns:
dict: A dictionary containing yearly purchase data, including
purchase orders count, purchase amount, priority orders count, and
new vendor count compared to the previous year.
"""
company = self.env.company.id
current_year = datetime.now().year
# Query to get purchase orders count and amount for the current year
query = """
SELECT COUNT(*) as po_count, SUM(amount_total) as po_sum
FROM purchase_order
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR FROM date_order) = %s
"""
self.env.cr.execute(query, (company, current_year))
data = self.env.cr.dictfetchall()
# Query to get priority purchase orders count for the current year
query = """
SELECT COUNT(*) as po_count
FROM purchase_order
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR FROM date_order) = %s
AND priority = '1'
"""
self.env.cr.execute(query, (company, current_year))
priority_orders = self.env.cr.dictfetchall()
# Query to get vendor count for the previous year
query = """
SELECT COUNT(DISTINCT partner_id) as vendor_count
FROM purchase_order
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR FROM date_order) = %s - 1
"""
self.env.cr.execute(query, (company, current_year))
previous_vendors = self.env.cr.dictfetchall()[0]['vendor_count']
# Query to get vendor count for the current year
query = """
SELECT COUNT(DISTINCT partner_id) as vendor_count
FROM purchase_order
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR FROM date_order) = %s
"""
self.env.cr.execute(query, (company, current_year))
current_vendors = self.env.cr.dictfetchall()[0]['vendor_count']
# Calculate new vendors compared to the previous year
new_vendors = current_vendors - previous_vendors
yearly = {
'purchase_orders': data[0]['po_count'],
'purchase_amount': data[0]['po_sum'] or 0,
'priority_orders': priority_orders[0]['po_count'],
'vendors': new_vendors or 0,
}
return yearly
def get_monthly_data(self):
"""Get monthly purchase data for the current company.
Returns:
dict: A dictionary containing monthly purchase data, including
purchase orders count, purchase amount, priority orders count,
vendor count, and new vendor IDs for the current month.
"""
company = self.env.company.id
query = """
SELECT COUNT(*), SUM(amount_total)
FROM purchase_order po
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR from date_order) =
EXTRACT(YEAR from CURRENT_DATE)
AND EXTRACT(MONTH from date_order) =
EXTRACT(MONTH from CURRENT_DATE)
"""
self.env.cr.execute(query, (company,))
data = self.env.cr.dictfetchall()
query = """
SELECT COUNT(*)
FROM purchase_order po
WHERE company_id = %s
AND EXTRACT(YEAR from date_order) =
EXTRACT(YEAR from CURRENT_DATE)
AND EXTRACT(MONTH from date_order) =
EXTRACT(MONTH from CURRENT_DATE)
AND priority = '1'
"""
self.env.cr.execute(query, (company,))
priority_orders = self.env.cr.dictfetchall()
query = """
SELECT DISTINCT partner_id
FROM purchase_order po
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(month from date_order) <
EXTRACT(month FROM CURRENT_DATE)
"""
self.env.cr.execute(query, (company,))
previous_vendors = self.env.cr.dictfetchall()
previous = [rec['partner_id'] for rec in previous_vendors]
query = """
SELECT DISTINCT partner_id
FROM purchase_order po
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR from date_order) =
EXTRACT(YEAR FROM CURRENT_DATE)
AND EXTRACT(month from date_order) =
EXTRACT(month FROM CURRENT_DATE)
"""
self.env.cr.execute(query, (company,))
vendors = self.env.cr.dictfetchall()
new_vendors = [rec['partner_id'] for rec in vendors if
rec['partner_id'] not in previous]
monthly = {
'purchase_orders': data[0]['count'] if data else 0,
'purchase_amount': data[0]['sum'] if data else 0,
'priority_orders': priority_orders[0][
'count'] if priority_orders else 0,
'vendors': len(new_vendors),
'vendor_id': new_vendors,
}
return monthly
def get_weekly_data(self):
"""
Get weekly purchase data for the current company.
Returns:
dict: A dictionary containing weekly purchase data, including
purchase orders count, purchase amount, priority orders count, and
vendor count.
"""
company = self.env.company.id
query = """
SELECT COUNT(*), SUM(amount_total), COUNT(CASE WHEN priority = '1'
THEN 1 ELSE NULL END)
FROM purchase_order
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR from date_order) =
EXTRACT(YEAR from CURRENT_DATE)
AND EXTRACT(WEEK from date_order) =
EXTRACT(WEEK from CURRENT_DATE)
"""
self.env.cr.execute(query, [company])
data = self.env.cr.fetchone()
query = """
SELECT DISTINCT partner_id
FROM purchase_order
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(WEEK from date_order) <
EXTRACT(WEEK FROM CURRENT_DATE)
"""
self.env.cr.execute(query, [company])
previous_vendors = self.env.cr.dictfetchall()
previous = [rec['partner_id'] for rec in previous_vendors]
query = """
SELECT DISTINCT partner_id
FROM purchase_order
WHERE company_id = %s
AND state IN ('purchase', 'done')
AND EXTRACT(YEAR from date_order) =
EXTRACT(YEAR FROM CURRENT_DATE)
AND EXTRACT(WEEK from date_order) =
EXTRACT(WEEK FROM CURRENT_DATE)
"""
self.env.cr.execute(query, [company])
vendors = self.env.cr.dictfetchall()
new_vendors = [rec['partner_id'] for rec in vendors if rec[
'partner_id'] not in previous]
weekly = {
'purchase_orders': data[0],
'purchase_amount': data[1],
'priority_orders': data[2],
'vendors': len(new_vendors)
}
return weekly
def get_today_data(self):
"""Get today's purchase data for the current company.
Returns:
dict: A dictionary containing today's purchase data, including
purchase orders count, purchase amount, priority orders count,
vendor count, and vendor IDs for new vendors today.
"""
company = self.env.company.id
# Get data for today
query = """
SELECT
COUNT(*) AS purchase_orders,
SUM(amount_total) AS purchase_amount,
COUNT(*) FILTER (WHERE priority = '1') AS priority_orders
FROM purchase_order
WHERE
company_id = %s
AND state IN ('purchase', 'done')
AND date_order::date = CURRENT_DATE
"""
self.env.cr.execute(query, (company,))
today_data = self.env.cr.dictfetchall()[0]
# Get new vendors for today
query = """
SELECT DISTINCT po.partner_id
FROM purchase_order po
LEFT JOIN purchase_order prior_po
ON po.partner_id = prior_po.partner_id
AND prior_po.company_id = %s
AND prior_po.state IN ('purchase', 'done')
AND prior_po.date_order::date < CURRENT_DATE
WHERE
po.company_id = %s
AND po.state IN ('purchase', 'done')
AND po.date_order::date = CURRENT_DATE
AND prior_po.partner_id IS NULL
"""
self.env.cr.execute(query, (company, company))
new_vendors = [r['partner_id'] for r in self.env.cr.dictfetchall()]
return {
'purchase_orders': today_data['purchase_orders'],
'purchase_amount': today_data['purchase_amount'],
'priority_orders': today_data['priority_orders'],
'vendors': len(new_vendors),
'vendor_id': new_vendors,
}
@api.model
def get_select_mode_data(self, args):
"""Get data based on the selected filters
Returns:
dict or False: A dictionary containing the corresponding purchase
data based on the selected filter or False if the filter is invalid.
"""
data = {
'this_year': self.get_yearly_data,
'this_month': self.get_monthly_data,
'this_week': self.get_weekly_data,
'today': self.get_today_data,
}.get(args)
return data() if data else False
def execute_query(self, query, args):
""" Execute a database query and return the results based on the
provided arguments.
Returns:
list: A list of results based on the query and arguments."""
self._cr.execute(query)
results = self._cr.dictfetchall()
final = []
if args == 'top_product':
final = [[record.get('total_quantity') for record in results],
[record.get('product_name') for record in results]]
elif args == 'top_vendor':
final = [[record.get('count') for record in results],
[record.get('name') for record in results]]
elif args == 'top_rep':
final = [[record.get('count') for record in results],
[record.get('name') for record in results]]
return final
@api.model
def get_top_chart_data(self, args):
"""
Get top chart data (e.g., top products, top vendors,
top representatives).
Returns:
list: A list of top chart data, including quantities or counts and
names.
"""
company_id = self.env.company.id
if args == 'top_product':
query = '''
SELECT DISTINCT(product_template.name) as product_name,
SUM(product_qty) as total_quantity
FROM purchase_order_line
INNER JOIN product_product ON product_product.id =
purchase_order_line.product_id
INNER JOIN product_template ON product_product.product_tmpl_id =
product_template.id
WHERE purchase_order_line.company_id = %s
GROUP BY product_template.id
ORDER BY total_quantity DESC
LIMIT 10
''' % company_id
elif args == 'top_vendor':
query = '''
SELECT partner.name, COUNT(po.id) as count
FROM purchase_order po
JOIN res_partner partner ON po.partner_id = partner.id
WHERE po.company_id = %s
GROUP BY partner.name
ORDER BY count DESC
LIMIT 10
''' % company_id
elif args == 'top_rep':
query = '''
SELECT partner.name, COUNT(po.id) as count
FROM purchase_order po
JOIN res_users users ON po.user_id = users.id
JOIN res_partner partner ON users.partner_id = partner.id
WHERE po.company_id = %s
GROUP BY partner.name
ORDER BY count DESC
LIMIT 10
''' % company_id
final = self.execute_query(query, args)
return final
@api.model
def get_orders_by_month(self):
"""
Get monthly purchase orders count for the current company.
Returns:
dict: A dictionary containing monthly purchase orders count
and month names.
"""
query = """select count(*), EXTRACT(month from date_order) as dates
from purchase_order po
where company_id = %s and state = 'purchase'
group by dates""" % self.env.company.id
self.env.cr.execute(query, (self.env.company.id,))
cr = self.env.cr.dictfetchall()
month = []
for rec in cr:
month.append(int(rec['dates']))
rec.update({
'count': rec['count'],
'dates': calendar.month_name[int(rec['dates'])],
'month': int(rec['dates'])
})
for rec in range(1, 13):
if rec not in month:
cr.append({
'count': 0,
'dates': calendar.month_name[rec],
'month': rec
})
cr = sorted(cr, key=lambda i: i['month'])
return {
'count': [rec['count'] for rec in cr],
'dates': [rec['dates'] for rec in cr]
}
@api.model
def purchase_vendors(self):
"""Get a list of purchase vendors for the current company.
Returns:
dict: A dictionary containing partner IDs and partner names.
"""
company_id = self.env.company.id
query = """
SELECT partner.id, partner.name
FROM purchase_order po
INNER JOIN res_partner partner ON po.partner_id = partner.id
WHERE po.company_id = %s
GROUP BY partner.id
"""
self._cr.execute(query, (company_id,))
partners = self._cr.dictfetchall()
partner_ids = [partner['id'] for partner in partners]
partner_names = [partner['name'] for partner in partners]
return {'partner_id': partner_ids, 'partner_name': partner_names}
@api.model
def purchase_vendor_details(self, args):
"""
Get vendor analysis data for a specific vendor.
Returns:
dict: A dictionary containing purchase amount, purchase order count,
draft amount, draft order count, approve amount, approve order
count, cancel amount, cancel order count, and month dates.
"""
company_id = self.env.company.id
partner = int(args) if args else 1
query = """
SELECT count(po.id),SUM(po.amount_total), EXTRACT(MONTH from
po.date_order) as dates
FROM purchase_order po
JOIN res_partner ON res_partner.id = po.partner_id
WHERE po.company_id = %s and po.partner_id = %s
GROUP BY dates
"""
self._cr.execute(query, (company_id, partner))
partner_orders = self._cr.dictfetchall()
query_draft = """
SELECT count(po.id),SUM(po.amount_total), EXTRACT(MONTH from
po.date_order) as dates
FROM purchase_order po
JOIN res_partner ON res_partner.id = po.partner_id
WHERE po.state in ('draft', 'sent') and po.company_id = %s and
po.partner_id = %s
GROUP BY dates
"""
self._cr.execute(query_draft, (company_id, partner))
draft_orders = self._cr.dictfetchall()
approve_qry = """
SELECT count(po.id),SUM(po.amount_total), EXTRACT(MONTH from
po.date_order) as dates
FROM purchase_order po
JOIN res_partner ON res_partner.id = po.partner_id
WHERE po.state = 'to approve' and po.company_id = %s and
po.partner_id = %s
GROUP BY dates
"""
self._cr.execute(approve_qry, (company_id, partner))
approve_orders = self._cr.dictfetchall()
cancel_qry = """
SELECT count(po.id),SUM(po.amount_total), EXTRACT(MONTH from
po.date_order) as dates
FROM purchase_order po
JOIN res_partner ON res_partner.id = po.partner_id
WHERE po.state = 'cancel' and po.company_id =
%s and po.partner_id = %s
GROUP BY dates
"""
self._cr.execute(cancel_qry, (company_id, partner))
cancel_orders = self._cr.dictfetchall()
all_orders = {
'partner_orders': partner_orders, 'draft_orders': draft_orders,
'approve_orders': approve_orders, 'cancel_orders': cancel_orders}
for order_type, order_list in all_orders.items():
order_months = []
for rec in order_list:
order_months.append(int(rec.get('dates')))
for rec in range(1, 13):
if rec not in order_months:
vals = {'sum': 0.0, 'dates': rec, 'count': 0}
order_list.append(vals)
all_orders[order_type] = sorted(
order_list, key=lambda order: order['dates'])
value = {
'purchase_amount': [record.get('sum') for record in partner_orders],
'po_count': [record.get('count') for record in partner_orders],
'draft_amount': [record.get('sum') for record in draft_orders],
'draft_count': [record.get('count') for record in draft_orders],
'approve_amount': [record.get('sum') for record in approve_orders],
'approve_count': [record.get('count') for record in approve_orders],
'cancel_amount': [record.get('sum') for record in cancel_orders],
'cancel_count': [record.get('count') for record in cancel_orders],
'dates': [record.get('dates') for record in partner_orders],
}
return value
@api.model
def get_pending_purchase_data(self):
"""
Get pending purchase orders for the current company.
Returns:
dict: A dictionary containing pending purchase order details,
including order names, vendor names, amounts, dates, and states.
"""
company = self.env.company.id
query = """
SELECT po.name, po.id, rp.name as partner_name, po.date_planned,
po.amount_total, po.state
FROM purchase_order po
JOIN purchase_order_line pol ON pol.order_id = po.id
JOIN res_partner rp ON rp.id = po.partner_id
WHERE po.date_planned < CURRENT_DATE AND pol.qty_received <
pol.product_qty AND po.company_id = %s
GROUP BY po.id, rp.id
"""
self._cr.execute(query, (company,))
orders = self._cr.dictfetchall()
value = {
'order': [rec['name'] for rec in orders],
'vendor': [rec['partner_name'] for rec in orders],
'amount': [rec['amount_total'] for rec in orders],
'date': [rec['date_planned'] for rec in orders],
'state': [rec['state'] for rec in orders],
'data': [list(val for val in rec.values()) for rec in orders]
}
return value
@api.model
def get_upcoming_purchase_data(self):
"""
Get upcoming purchase orders for the current company.
Returns:
dict: A dictionary containing upcoming purchase order details,
including order names, vendor names, amounts, dates, and states.
"""
company = self.env.company.id
query = """
SELECT po.name, po.id, rp.name as partner_name, po.date_planned,
po.amount_total, po.state
FROM purchase_order po
JOIN purchase_order_line pol ON pol.order_id = po.id
JOIN res_partner rp ON rp.id = po.partner_id
WHERE po.date_planned > CURRENT_DATE AND pol.qty_received <
pol.product_qty AND po.company_id = %s
GROUP BY po.id, rp.id
"""
self._cr.execute(query, (company,))
orders = self._cr.dictfetchall()
value = {
'order': [rec['name'] for rec in orders],
'vendor': [rec['partner_name'] for rec in orders],
'amount': [rec['amount_total'] for rec in orders],
'date': [rec['date_planned'] for rec in orders],
'state': [rec['state'] for rec in orders],
'data': [list(val for val in rec.values()) for rec in orders],
}
return value
class PurchaseOrderLine(models.Model):
"""
Purchase Order Line Model for Extending Purchase Order Line
Functionality. This class extends the Odoo Purchase Order Line model
to add custom methods for product category analysis and retrieval of
product category data.
"""
_inherit = 'purchase.order.line'
@api.model
def product_categ_analysis(self):
"""
Perform product category analysis for purchase order lines. This
method retrieves and analyzes purchase order line data to provide
information on product categories and their corresponding
quantities.
"""
company_id = self.env.user.company_id.id
# Query to get products quantity by name
quantity_query = """
SELECT product_template.name,
SUM(pl.product_qty) as total_quantity
FROM purchase_order_line pl
JOIN product_product ON pl.product_id = product_product.id
JOIN product_template ON product_product.product_tmpl_id =
product_template.id
WHERE pl.company_id = %s
GROUP BY product_template.name
"""
self._cr.execute(quantity_query, (company_id,))
products_quantity = self._cr.fetchall()
# Extract name and quantity values from query result
name, quantity_done = zip(*products_quantity)
# Query to get category ids and names
category_query = """
SELECT pc.id, pc.name
FROM product_category pc
JOIN product_template pt ON pt.categ_id = pc.id
JOIN product_product pp ON pp.product_tmpl_id = pt.id
JOIN purchase_order_line pl ON pl.product_id = pp.id
WHERE pl.company_id = %s
GROUP BY pc.id, pc.name
"""
self._cr.execute(category_query, (company_id,))
categories = self._cr.fetchall()
# Extract category ids and names from query result
category_ids, category_names = zip(*categories)
# Create dictionary values to return
value = {'name': name, 'count': quantity_done}
new_value = {'category_id': category_ids,
'category_name': category_names}
return value, new_value
@api.model
def product_categ_data(self, args):
"""
Retrieve product category data for a specific category.
Returns:
dict: A dictionary containing product data for the specified
category, including product names and their quantities.
"""
category_id = int(args or 1)
company_id = self.env.company.id
query = """
SELECT product_template.name, SUM(pl.product_qty)
FROM purchase_order_line pl
INNER JOIN product_product ON pl.product_id = product_product.id
INNER JOIN product_template ON product_product.product_tmpl_id =
product_template.id
WHERE pl.company_id = %s AND product_template.categ_id = %s
GROUP BY product_template.name
"""
self._cr.execute(query, (company_id, category_id))
product_move = self._cr.dictfetchall()
value = {
'name': [record.get('name') for record in product_move],
'count': [record.get('sum') for record in product_move],
}
return value

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
purchase_dashboard_advanced/static/description/assets/modules/2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/dashboard_community.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/dashboard_enterprise.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/dashboard_tiles.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/gif.zip

Binary file not shown.

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/gif/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/gif/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/gif/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/gif/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/gif/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/gif/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/pending_arrivals.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/product_category_analysis.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/purchase_vendor_analysis.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/purchases_by_month.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/tiles.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/top_charts.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
purchase_dashboard_advanced/static/description/assets/screenshots/upcoming_arrivals.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
purchase_dashboard_advanced/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
purchase_dashboard_advanced/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

610
purchase_dashboard_advanced/static/description/index.html

@ -0,0 +1,610 @@
<div style="background-color: #714B67; min-height: 600px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" style="width: 42px; height: 42px;" />
<div>
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">Purchase Dashboard</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">Detailed Dashboard View For Purchase</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif"
style="width: 75%; height: auto; position: absolute; margin-left: auto; margin-right: auto; top: 45%; left: 12%; right: auto;" />
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Overview
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
A Dashboard for keeping track and evaluate various aspects of spending on purchases , We can track Monthly , yearly , top products , priority products and upcoming details of purchase.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Features
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center" style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Detailed view for purchases
</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Responsive views </span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Different types of graphs
</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Different types of tables for analysing the records </span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="row" id="screenshots">
<div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-image mr-2"></i>Screenshots
</h2>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Dashboard View for the Purchase Module</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
The Dashboard is available in the Purchase module with tiles and the Related graphs.
</p>
<img src="assets/screenshots/dashboard_enterprise.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
The Tiles display a list of the Purchase orders,Total amount, Priority orders and Vendors based on Today,This Week, This Month and This Year
</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
</p>
<img src="assets/screenshots/tiles.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Top Charts</h4>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
This is the pie graph for showing the Top Products, Top Vendors, Top Purchase Representatives
</p>
<img src="assets/screenshots/top_charts.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Purchases By Month</h4>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
This bar graph shows the purchases made in each month.
</p>
<img src="assets/screenshots/purchases_by_month.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Purchase Vendor Analysis</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
This is a line graph containing multiple attributes on it. This will show the purchases and its states based on the vendors.
</p>
<img src="assets/screenshots/purchase_vendor_analysis.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Product Category Analysis</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
This is a line graph used to plot the product category analysis. It will demonstrate the quantity of products based on the category selected.
</p>
<img src="assets/screenshots/product_category_analysis.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Pending Arrivals</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
There are pending purchase orders with partial deliveries, where some products have been delivered, but the rest are still awaiting delivery.
</p>
<img src="assets/screenshots/1.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<div class="col-lg-12 my-3">
<h4 class="mt-3"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Upcoming Arrivals</h4>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
This is the table of contents describing the purchase order that is yet to arrive.
</p>
<img src="assets/screenshots/2.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<!-- SUGGESTED PRODUCTS -->
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center"
style="text-align: center; padding: 2.5rem 1rem !important;">
<h2 style="color: #212529 !important;">Suggested Products</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/base_advanced_report_templates/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/1.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/purchase_down_payment/#" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/2.jpg">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/vendor_portal_odoo/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/section_wise_subtotal/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/product_brand_purchase/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/5.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/purchase_recurring_orders/#" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block w-100"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev" style="left:25px;width: 35px;color: #000;">
<span class="carousel-control-prev-icon"><i class="fa fa-chevron-left" style="font-size:24px"></i></span> </a>
<a class="carousel-control-next" href="#demo1" data-slide="next" style="right:25px;width: 35px;color: #000;">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right" style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px"
width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48" style="width: 42px; height: 42px;" />
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help? Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52" style="width: 52px; height: 52px;" />
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;" />
</div>
</div>
</div>
<!-- END OF SUPPORT -->
</div>

349
purchase_dashboard_advanced/static/src/css/style.css

@ -0,0 +1,349 @@
.oh_dashboards{
padding-top :15px;
background-color: #f8faff !important;
}
.oh-card h4 {
font-size: 1.1rem;
}
/* Widget One
---------------------------*/
.stat-content {
display: inline-block;
width: 66%;
}
.stat-icon{
display: inline-block;
}
.stat-widget-one .stat-icon {
vertical-align: top;
margin: auto;
width: 100%;
color: #01c490;
}
.stat-widget-one .stat-icon i {
font-size: 30px;
font-weight: 900;
display: inline-block;
color: #01c490;}
.stat-widget-one .stat-text {
font-size: 14px;
color: #868e96;
font-weight: bold;
}
.stat-widget-one .stat-digit {
font-size: 24px;
color: #02448b; }
.stat-count {
font-size: 20px;
text-align: center;
color: #00438b;}
.stat-title {
font-size: 17px;
text-align: center;
color: #00438b; }
.mb-0{
font-size: 20px;
position: relative;
text-align: center;
}
.mb-0 .dash-title {
font-size: 20px;
text-align: center;
color: rgba(255, 255, 255, 0.81);
}
.oh-card {
padding-top: 0px;
padding: 0px;
margin-bottom: 1.5rem;
border-radius: 0px;
box-shadow: none;
background: none;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
}
.oh-card:hover {
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
}
.oh-data {
margin-top: 4.5%;
}
.oh-data .stat-icon {
width: 30%;
height: 85px;
text-align: center;
background: #ff8762;
color: #fff;
width: 32%;
padding-top: 2%;
font-size: xxx-large;
}
.oh-data .oh-card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
}
.stat-widget-one .stat-text {
font-size: 14px;
color: #ff8762;
margin-top: 2.3rem;
margin-left: 1rem;
}
.stat-widget-one .stat-digit {
font-size: 26px;
color:#993232;
margin-left: 1rem;
margin-top: -1px;
font-family: initial
}
.stat-widget-one .stat-icon i {
font-size: 25px;
font-weight: 900;
display: inline-block;
color: #fff;
}
.stat-widget-one {
background-color: white;
text-align: left;
}
.stat-widget-one {
width: 100%;
}
.oh-data .stat-icon {
width: 30%;
height: 85px;
text-align: center;
padding-top: 2%;
}
h4 .stat-count {
font-size: 17px;
text-align: center;
color: #000 !important;
margin-top: 0px;
width: 100%;
float: left;
margin: 0;
}
.stat-head {
text-align: left !important;
font-weight: 300;
font-size: 15px;
margin-bottom: 25px;
margin-left: 24px;
width: 100%;
}
.oh-card-body {
display: flex;
justify-content: space-between;
align-items: center;
}
.o_action_manager{
overflow-y: scroll !important;
max-width:100%;
}
.stat_count{
margin-top: -89px;
margin-left: 35px;
font-size: 33px;
}
.stat-head {
text-align: left !important;
font-weight: 300;
font-size: 18px;
margin-bottom: 25px;
margin-left: 24px;
width: 100%;
margin-top: 57px;
color: black;
}
.top_chart{
height: fit-content;
}
.row.main-section {
margin-right: 0px; !important;
}
.chart-container {
border-radius: 0.3rem;
padding: 1rem;
margin: 1rem auto;
}
.chart-container.card-shadow {
height: 100%;
}
.half_chart.chart-container.card-shadow {
height: 49%;
}
#container {
height: 400px;
}
/*vendor analysis*/
#vendor_select {
position: absolute;
top: 1px;
right: 63px;
}
#vendor_selection {
position: absolute;
top: 33px;
background-color: #0d5820;
}
/*category analysis*/
#product_categ_select {
position: absolute;
top: 1px;
right: 63px;
}
#product_categ_selection {
position: absolute;
top: 33px;
background-color: #00000099;
}
/*table*/
.graph_details_table{
position: absolute;
top: 45px;
right: 15px;
background-color: white;
border-collapse: collapse;
border: 1px solid #ddd;
}
.graph_details_table th{
background-color:#67b7dc;
color: white;
width: 250px;
height: 30px;
}
.graph_details_table td{
border: 1px solid #ddd;
height: 20px;
}
.graph_details_table tr:nth-child(even){background-color: #f2f2f2;}
.graph_details_table tr:hover {background-color: #ddd;}
.chart-container h2 {
font-weight: 700;
font-size: 1.690rem;
}
.hr_notification {
background: #f6f7fa;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
height: 316px;
overflow-y: auto;
margin-bottom: 15px;
}
.hr_notification .media {
border-bottom: 1px solid #e6e6e6;
padding-bottom: 6px;
margin-bottom: 10px;
}
hr_notification .text-color.display-6 {
margin: 0px 0 3px;
color: #2d2d2d;
}
.hr_notification p {
margin: 0 0 1px;
color: #666;
font-size: 10px;
}
.chart_head {
font-size: 17px;
text-align: center;
padding: 12px 0;
color: #fff;
font-weight: 300;
background: #5ebade;
margin-bottom: 9px;
}
.hr_notification_head {
font-size: 17px;
text-align: center;
padding: 12px 0;
color: #fff;
font-weight: 300;
background: #5ebade;
margin-bottom: 9px;
}
@media (max-width: 767.98px) {
.oh-card{
width: 100% !important;
}
.dashboard_main_section .form-control{
width: 85% !important;
margin: 15px auto;
}
.sale_details{
position: relative;
top: 0px !important;
right: 0px !important;
}
.selling_product_graph_view{
margin-top: 5rem;
}
.hr_notification{
min-width: 90% !important;
}
}
.hr_notification{
min-width: 425.683px;
min-height: 316px;
max-width: 100%;
}
.media-body{
background: #466b8d;
float: left;
margin: 0;
width: 100%
}

734
purchase_dashboard_advanced/static/src/js/dashboard.js

@ -0,0 +1,734 @@
odoo.define('purchase_dashboard_advanced.PurchaseDashboard', function (require) {
'use strict';
var AbstractAction = require('web.AbstractAction');
var core = require('web.core');
var _t = core._t;
var QWeb = core.qweb;
var ajax = require('web.ajax');
var rpc = require('web.rpc');
var PurchaseDashboard = AbstractAction.extend({
template: 'PurchaseDashboard',
events: {
'click .purchase_order_all': 'purchase_order_all',
'click .po_priority_orders': 'po_priority_orders',
'change #select_mode': 'onchange_select_mode',
'change #select_chart': 'onchange_select_chart',
'change #product_categ_selection': 'onchange_product_categ',
'change #vendor_selection': 'onchange_vendor_selection',
},
init: function () {
/**
* Initializes an object with a list of dashboard template names.
*
* @returns {undefined}
*/
this._super.apply(this, arguments);
this.dashboard_templates = ['PurchaseMain', 'Top'];
},
start: function() {
/**
* Initializes the PurchaseDashboard and renders dashboards and graphs.
*
* @function
* @memberof PurchaseDashboard
* @returns {Promise<void>} A Promise that resolves when rendering is complete.
*/
var self = this;
this.set("title", 'PurchaseDashboard');
return this._super().then(function() {
self.render_dashboards();
self.render_graphs();
});
},
willStart: function() {
/**
* Executes a series of asynchronous operations and returns a Promise that resolves when all operations are complete.
*
* @returns {Promise} A Promise that resolves when all asynchronous operations are complete.
*/
var self = this;
return $.when(ajax.loadLibs(this), this._super()).then(function() {
return self.fetch_data();
});
},
render_graphs: function(){
/**
* Renders the graphs for the PurchaseDashboard.
*
* @function
* @memberof PurchaseDashboard
* @returns {void}
*/
var self = this;
self.render_top_product();
self.render_line_chart();
self.render_product_categ_analysis();
self.render_fusion_chart();
},
render_dashboards: function() {
/**
* Renders the dashboards for the PurchaseDashboard.
*
* @function
* @memberof PurchaseDashboard
* @returns {void}
*/
var self = this;
_.each(this.dashboard_templates, function(template) {
self.$el.find('.o_purchase_dashboard').append(QWeb.render(template, {widget: self}));
});
},
purchase_order_all: function(e) {
/**
* Handles the click event of the "Purchase Order All" button, opening a list view of purchase orders.
*
* @function
* @memberof PurchaseDashboard
* @param {MouseEvent} e - The click event.
* @returns {void}
*/
var self = this;
e.stopPropagation();
e.preventDefault();
if(this.purchase_orders) {
var options = {
on_reverse_breadcrumb: self.on_reverse_breadcrumb,
};
self.do_action({
name: _t("Purchase Order"),
type: 'ir.actions.act_window',
res_model: 'purchase.order',
view_mode: 'tree,form',
views: [[false, 'list'],[false, 'form']],
domain: [['state','in', ['purchase', 'done']]],
target: 'current'
}, options)
}
},
render_line_chart: function(e) {
var self=this
/**
* Renders a line chart of purchase orders by month.
*
* @function
* @memberof PurchaseDashboard
* @param {MouseEvent} e - The click event (optional).
* @returns {void}
*/
rpc.query({
model: "purchase.order",
method: 'get_orders_by_month',
}).then(function (arrays) {
var ctx = self.el.querySelector("#canvas");
var month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
var count = arrays.count;
new Chart(ctx, {
type: 'bar',
data: {
labels: month,
datasets: [{
label: 'Count',
data: count,
backgroundColor: '#ac3973',
borderColor: '#ac3973',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'bar',
fill: false
}]
},
options: {
scales: {
y: {
beginAtZero: true
},
},
responsive: true,
maintainAspectRatio: false,
}
});
});
},
render_product_categ_analysis: function(e) {
/**
Render the product category analysis chart based on the purchase order lines.
@function
@name render_product_categ_analysis
@memberof PurchaseDashboardWidget
@param {Event} e - The event object.
@returns {void}
*/
var self = this
rpc.query({
model: "purchase.order.line",
method: 'product_categ_analysis',
}).then(function (result) {
var ctx = self.$el.find("#product_categ_purchases");
var count = result[0].count
var category_name = result[1].category_name
var category_id = result[1].category_id
var count = 0;
Object.entries(result[1].category_name).forEach(([key, value]) => {
if(count == 0){
self.$el.find('#product_categ_selection').append('<option id="'+key+'" value="'+category_id[count]+'" selected="selected">'+value+'</option>')
count++;
}else{
self.$el.find('#product_categ_selection').append('<option id="'+key+'" value="'+category_id[count]+'">'+value+'</option>')
count++;
}
});
self.$el.find('#product_categ_table').hide();
var option = self.$el.find( "#product_categ_selection" ).val();
rpc.query({
model: "purchase.order.line",
method: "product_categ_data",
args: [option]
}).then(function(result) {
var ctx = self.$el.find("#product_categ_purchases");
var name = result.name
var count = result.count;
new Chart(ctx, {
type: 'line',
data: {
labels: name,
datasets: [{
label: 'Quantity Done',
data: count,
backgroundColor: '#003f5c',
borderColor: '#003f5c',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
}]
},
options: {
scales: {
y: {
beginAtZero: true
},
},
responsive: true,
maintainAspectRatio: false,
}
});
});
});
},
po_priority_orders: function(e) {
/**
Renders priority purchase orders based on the priority field value.
@param {Event} e - The click event.
*/
var self = this;
e.stopPropagation();
e.preventDefault();
if(this.priority_orders) {
var options = {
on_reverse_breadcrumb: self.on_reverse_breadcrumb,
};
self.do_action({
name: _t("Priority Order"),
type: 'ir.actions.act_window',
res_model: 'purchase.order',
view_mode: 'tree,form',
views: [[false, 'list'],[false, 'form']],
domain: [['priority','=', 1]],
target: 'current'
}, options)
}
},
onchange_select_mode: function(e) {
/**
Handles onchange event of select mode dropdown and fetches data from server accordingly
@param {Event} e - Event object
@returns {void}
*/
var option = e.target.value
var self = this
rpc.query({
model: 'purchase.order',
method: 'get_select_mode_data',
args: [option]
}).then(function (result) {
self.$el.find('#purchase_order').empty()
self.$el.find('#amount').empty()
self.$el.find('#priority').empty()
self.$el.find('#partner').empty()
self.$el.find('#purchase_orders').empty()
self.$el.find('#purchase_amount').empty()
self.$el.find('#priority_orders').empty()
self.$el.find('#vendors').empty()
self.$el.find('#purchase_orders').append(result['purchase_orders'])
self.$el.find('#purchase_amount').append(result['purchase_amount'])
self.$el.find('#priority_orders').append(result['priority_orders'])
self.$el.find('#vendors').append(result['vendors'])
});
},
fetch_data: function() {
/**
Fetches purchase data and assigns it to the corresponding properties of the current object.
@returns {Promise} A Promise that resolves with the fetched data.
*/
var self = this
var fetchMonthlyData = this._rpc({
model: 'purchase.order',
method: "get_monthly_data",
args: ['this_month']
})
.then(function (result) {
self.purchase_orders = result['purchase_orders']
self.purchase_amount = result['purchase_amount']
self.priority_orders = result['priority_orders']
self.vendors = result['vendors']
});
var fetchPendingPurchaseData = self._rpc({
model: 'purchase.order',
method: 'get_pending_purchase_data'
}).then(function (res) {
var order = Object.values(res['order'])
var vendor = Object.values(res['vendor'])
var amount = Object.values(res['amount'])
var date = Object.values(res['date'])
var state = Object.values(res['state'])
self.data = res['data']
});
var test = this
var fetchUpcomingPurchaseData = self._rpc({
model: 'purchase.order',
method: 'get_upcoming_purchase_data'
}).then((res) => {
var order = Object.values(res['order'])
var vendor = Object.values(res['vendor'])
var amount = Object.values(res['amount'])
var date = Object.values(res['date'])
var state = Object.values(res['state'])
self.upcoming_data = res['data']
});
return $.when(fetchMonthlyData, fetchPendingPurchaseData, fetchUpcomingPurchaseData)
},
onchange_select_chart: function (e) {
/**
Function to handle the onchange event of select chart
@param {Event} e - The event object
*/
var option = e.target.value
var self = this
var ctx = self.$el.find(".top_pie_chart");
var background_color = [];
rpc.query({
model: "purchase.order",
method: 'get_top_chart_data',
args: [option]
}).then(function (arrays) {
arrays[0].forEach((div) => {
var randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
background_color.push(randomColor)
});
var randomColor= background_color
var data = {
labels : arrays[1],
datasets: [{
label: "",
data: arrays[0],
backgroundColor:randomColor,
borderColor:randomColor,
borderWidth: 1
},]
};
//options
var options = {
responsive: true,
title: false,
legend: {
display: true,
position: "right",
labels: {
fontColor: "#333",
fontSize: 16
}
},
scales: {
yAxes: [{
gridLines: {
color: "rgba(0, 0, 0, 0)",
display: false,
},
ticks: {
min: 0,
display: false,
}
}]
}
};
if (window.myCharts_top_priority != undefined)
window.myCharts_top_priority.destroy();
window.myCharts_top_priority = new Chart(ctx, {
type: "doughnut",
data: data,
options: options
});
});
},
onchange_product_categ: function (events) {
/**
Function to handle the change in product category and display the data related to the product category.
@param {Event} events - The event object.
*/
var option = events.target.value;
var self = this
rpc.query({
model: "purchase.order.line",
method: "product_categ_data",
args: [option]
}).then(function(result) {
var ctx = self.$el.find("#product_categ_purchases");
var name = result.name
var count = result.count;
var index = 0;
self.$el.find('#product_categ_table td').remove();
Object.entries(result.count).forEach(([key, value]) => {
self.$el.find('#product_categ_table').append('<tr><td>'+name[index]+'</td><td>'+value+'</td></tr>')
index++;
});
self.$el.find('#product_categ_table').hide();
new Chart(ctx, {
type: 'line',
data: {
labels: name,
datasets: [{
label: 'Quantity',
data: count,
backgroundColor: '#003f5c',
borderColor: '#003f5c',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
}]
},
options: {
scales: {
y: {
beginAtZero: true
},
},
responsive: true,
maintainAspectRatio: false,
}
});
});
},
render_top_product: function() {
/**
Render top products chart.
@function
@name render_top_product
@memberof module:purchases_dashboard
@returns {void}
*/
var self = this
var ctx = self.$el.find(".top_pie_chart");
var background_color = [];
rpc.query({
model: "purchase.order",
method: 'get_top_chart_data',
args: ['top_product']
}).then(function (arrays) {
arrays[0].forEach((div) => {
var randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
background_color.push(randomColor)
});
var randomColor= background_color
var data = {
labels : arrays[1],
datasets: [{
label: "",
data: arrays[0],
backgroundColor:randomColor,
borderColor:randomColor,
borderWidth: 1
},]
};
var options = {
responsive: true,
title: false,
legend: {
display: true,
position: "right",
labels: {
fontColor: "#333",
fontSize: 16
}
},
scales: {
yAxes: [{
gridLines: {
color: "rgba(0, 0, 0, 0)",
display: false,
},
ticks: {
min: 0,
display: false,
}
}]
}
};
window.myCharts_top_priority = new Chart(ctx, {
type: "doughnut",
data: data,
options: options
});
});
},
render_fusion_chart: function(e) {
/**
Renders a Fusion chart by making a RPC call to retrieve purchase vendor data
@function
@param {Object} e - Event object
@returns {void}
*/
var self = this
rpc.query({
model: "purchase.order",
method: 'purchase_vendors',
}).then(function (result) {
var ctx = self.$el.find("#purchase_vendors");
var partner_id = result.partner_id;
var partner_name = result.partner_name;
var count = 0;
Object.entries(result.partner_name).forEach(([key, value]) => {
if(count == 0){
self.$el.find('#vendor_selection').append('<option id="'+key+'" value="'+partner_id[count]+'" selected="selected">'+value+'</option>')
count++;
}else{
self.$el.find('#vendor_selection').append('<option id="'+key+'" value="'+partner_id[count]+'">'+value+'</option>')
count++;
}
});
var option = self.$el.find( "#vendor_selection" ).val();
rpc.query({
model: "purchase.order",
method: 'purchase_vendor_details',
args: [option]
}).then(function (result) {
self.$el.find("#purchase_vendors").empty();
var ctx = self.$el.find("#purchase_vendors");
if (result) {
self.$el.find('#purchase_vendors').append('<div class="graph_canvas" style="margin-top: 30px;"><canvas id="partner_graph" height="500px" width="150px"/></div>')
var ctx = self.$("#partner_graph");
var name = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
var sum = result.purchase_amount
var po_count = result.po_count
var draft_total = result.draft_amount
var draft_count = result.draft_count
var approve_amount = result.approve_amount
var approve_count = result.approve_count
var cancel_amount = result.cancel_amount
var cancel_count = result.cancel_count
var index = 0;
if (window.myChart_year != undefined)
window.myChart_year.destroy();
window.myChart_year = new Chart(ctx, {
type: 'line',
data: {
labels: name,
datasets: [
{
label: 'Purchase Order Total',
data: sum,
backgroundColor: '#0000ff',
borderColor: '#0000ff',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
{
label: 'Draft Order Total',
data: draft_total,
backgroundColor: '#71d927',
borderColor: '#71d927',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
{
label: 'To Approve',
data: approve_amount,
backgroundColor: '#ff0066',
borderColor: '#ff0066',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
{
label: 'Cancelled Orders',
data: cancel_amount,
backgroundColor: '#ffff1a',
borderColor: '#ffff1a',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
]
},
options: {
scales: {
y: {
beginAtZero: true
},
},
responsive: true,
maintainAspectRatio: false,
}
});
}
});
});
},
onchange_vendor_selection: function(events) {
/**
Function to handle the change event of vendor selection dropdown.
@param {Event} events - The change event object
*/
var option = events.target.value;
var self = this
rpc.query({
model: "purchase.order",
method: 'purchase_vendor_details',
args: [option]
}).then(function(result) {
self.$("#purchase_vendors").empty();
var ctx = self.$el.find("#purchase_vendors");
if (result) {
self.$el.find('#purchase_vendors').append('<div class="graph_canvas" style="margin-top: 30px;"><canvas id="partner_graph" height="500px" width="150px"/></div>')
var ctx = self.$el.find("#partner_graph");
var name = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
var sum = result.purchase_amount
var po_count = result.po_count
var draft_total = result.draft_amount
var draft_count = result.draft_count
var approve_amount = result.approve_amount
var approve_count = result.approve_count
var cancel_amount = result.cancel_amount
var cancel_count = result.cancel_count
var index = 0;
if (window.myChart_year != undefined)
window.myChart_year.destroy(); window.myChart_year = new Chart(ctx, {
type: 'line',
data: {
labels: name,
datasets: [
{
label: 'Purchase Order Total',
data: sum,
backgroundColor: '#0000ff',
borderColor: '#0000ff',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
{
label: 'Draft Order Total',
data: draft_total,
backgroundColor: '#71d927',
borderColor: '#71d927',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
{
label: 'To Approve',
data: approve_amount,
backgroundColor: '#ff0066',
borderColor: '#ff0066',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
{
label: 'Cancelled Orders',
data: cancel_amount,
backgroundColor: '#ffff1a',
borderColor: '#ffff1a',
barPercentage: 0.5,
barThickness: 6,
maxBarThickness: 8,
minBarLength: 0,
borderWidth: 1,
type: 'line',
fill: false
},
]
},
options: {
scales: {
y: {
beginAtZero: true
},
},
responsive: true,
maintainAspectRatio: false,
}
});
}
});
},
});
core.action_registry.add('purchase_dashboard', PurchaseDashboard);
return PurchaseDashboard;
});

309
purchase_dashboard_advanced/static/src/xml/purchase_dashboard_templates.xml

@ -0,0 +1,309 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Purchase Dashboard view-->
<template id="template" xml:space="preserve">
<t t-name="PurchaseDashboard">
<div class="oh_dashboards">
<div class="container-fluid my-5 o_purchase_dashboard"/>
</div>
</t>
<t t-name="PurchaseMain">
<section class="dashboard_main" id="main_section">
<div class="col-sm-12 mb-4">
<div class="row">
<div class="col-12 col-sm-12 col-md-8">
<h2 class="section-header">Purchase Dashboard</h2>
</div>
<!-- Filters for tiles -->
<div class="col-12 col-sm-12 col-md-4">
<form class="form-group">
<select id="select_mode" class="form-control">
<option id="this_year" value="this_year">This Year</option>
<option id="this_month" value="this_month"
selected="">This Month</option>
<option id="this_week" value="this_week">This Week</option>
<option id="today" value="today">Today</option>
</select>
</form>
</div>
<!-- Tiles -->
<div class="col-sm-12 mb-3">
<div class="row">
<div class="col-md-3 col-sm-5 purchase_order_all oh-data">
<div class="oh-card" style="width: 288px;">
<div class="oh-card-body">
<div class="stat-widget-one">
<div class="stat-icon"
style="background:#ff4d94"><i class="fa fa-shopping-cart"/></div>
<div class="stat-content">
<div class="stat-head">Purchase Orders</div>
<div class="stat_count"
id="purchase_orders">
<span id="purchase_order"><t t-esc="widget.purchase_orders"/></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-sm-5 purchase_order_all oh-data">
<div class="oh-card" style="width: 288px;">
<div class="oh-card-body">
<div class="stat-widget-one">
<div class="stat-icon"
style="background:#99e6ff"><i class="fa fa-money"/></div>
<div class="stat-content">
<div class="stat-head">Total Amount</div>
<div class="stat_count"
id="purchase_amount">
<span id="amount">
<t t-esc="widget.purchase_amount"/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-sm-5 po_priority_orders oh-data">
<div class="oh-card" style="width: 288px;">
<div class="oh-card-body">
<div class="stat-widget-one">
<div class="stat-icon"
style="background:#aaff80"><i class="fa fa-star"/></div>
<div class="stat-content">
<div class="stat-head">Priority Orders</div>
<div class="stat_count"
id="priority_orders">
<span id="priority">
<t t-esc="widget.priority_orders"/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-sm-5 po_vendors oh-data">
<div class="oh-card" style="width: 288px;">
<div class="oh-card-body">
<div class="stat-widget-one">
<div class="stat-icon"
style="background:#bf80ff"><i class="fa fa-users"/></div>
<div class="stat-content">
<div class="stat-head">Vendors</div>
<div class="stat_count"
id="vendors">
<span id="partner">
<t t-esc="widget.vendors"/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</t>
<t t-name="Top">
<div class="col-xs-12 col-sm-12 col-lg-12 col-md-12">
<div class="row main-section">
<div class="col-sm-6 col-lg-6 top_chart">
<div class="chart_head"
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 700;background: #0b3c38b0;">
Top Charts
</div>
<div class="top_chart_pie_div half_chart chart-container card-shadow">
<!-- Filters for tiles -->
<div class="col-8 col-sm-8 col-md-4">
<form class="form-group">
<select id="select_chart" class="form-control">
<option id="top_product" value="top_product"
selected="">Top Product</option>
<option id="top_vendor" value="top_vendor">Top Vendor</option>
<option id="top_rep" value="top_rep">Top Purchase Rep.</option>
</select>
</form>
</div>
<div class="graph_canvas">
<canvas class="top_pie_chart" width="200"
height="120"/>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-6" id="col-graph">
<div class="chart_head"
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 700;background: #05102eb3;">
Purchases By Month
</div>
<div id="chart">
<canvas id="canvas" width="400" height="400"/>
</div>
</div>
</div>
</div>
<br/>
<div class="col-xs-12 col-sm-12 col-lg-12 col-md-12">
<div class="row main-section">
<div class="col-sm-6 col-lg-6">
<div class="purchase_prod_categ chart-container card-shadow">
<div class="chart_head"
style="font-size: 17px;text-align: left;padding: 12px 0;color: #fff;font-weight: 700;background: #669731d4;">
Purchases Vendor Analysis
</div>
<div class="form-group col-4" style="padding: 12px 0;"
id="vendor_select">
<select id="vendor_selection"
class="btn btn-primary"/>
</div>
<div style="height: 20px; max-height: 20px;"
id="purchase_vendors"/>
</div>
</div>
<div class="col-sm-6 col-lg-6">
<div class="purchase_prod_categ chart-container card-shadow"
id="tiles">
<div class="chart_head"
style="font-size: 17px;text-align: left;padding: 12px 0;color: #fff;font-weight: 700;background: #137660c2;">
Product Category Analysis
</div>
<div style="height: 20px; max-height: 20px;"
class="d-flex justify-content-between align-items-center">
<div class="form-group col-4"
id="product_categ_select">
<select id="product_categ_selection"
class="btn btn-primary"/>
</div>
</div>
<div class="graph_canvas" style="margin-top: 30px;">
<canvas id="product_categ_purchases" height="500px"
width="150px"/>
</div>
</div>
</div>
</div>
</div>
<br/>
<div class="col-xs-12 col-sm-12 col-lg-12 col-md-12">
<div class="row main-section">
<div class="col-sm-6 col-lg-6">
<div class="hr_notification" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
height: 316px;overflow-y: auto;margin-bottom: 15px;">
<div class="hr_notification_head"
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 700;background: #044e64a3;">
Pending Arrivals
</div>
<div class="col-sm-12 col-lg-12" style="padding:0;">
<div class="text-color">
<div class="media"
id="purchase_details_orders">
<div>
<table class="table table-sm"
id="pending_analysis">
<tr>
<th>Order</th>
<th>Vendor</th>
<th>Amount</th>
<th>Date Planned</th>
<th>State</th>
</tr>
<t t-foreach="widget.data"
t-as="rec">
<tr>
<td><t t-esc="rec[0]"/></td>
<td><t t-esc="rec[2]"/></td>
<td><t t-esc="rec[4]"/></td>
<td><t t-esc="rec[3]"/></td>
<td>
<t t-if="rec[5] == 'draft'">
RFQ
</t>
<t t-if="rec[5] == 'sent'">
RFQ Sent
</t>
<t t-if="rec[5] == 'to approve'">
To Approve
</t>
<t t-if="rec[5] == 'purchase'">
Purchase Order
</t>
<t t-if="rec[5] == 'done'">
Locked
</t>
<t t-if="rec[5] == 'cancel'">
Cancelled
</t>
</td>
</tr>
</t>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-6">
<div class="pending_purchases" style="background: #fff;transition: transform 0.2s ease, box-shadow 0.2s ease;will-change: transform, box-shadow;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06);
height: 316px;overflow-y: auto;margin-bottom: 15px;">
<div class="hr_notification_head"
style="font-size: 17px;text-align: center;padding: 12px 0;color: #fff;font-weight: 700;background: #214c17bf;">
Upcoming Arrivals
</div>
<div class="col-sm-12 col-lg-12" style="padding:0;">
<div class="text-color">
<div class="media"
id="upcoming_details_orders">
<div>
<table class="table table-sm"
id="upcoming_analysis">
<tr>
<th>Order</th>
<th>Vendor</th>
<th>Amount</th>
<th>Date Planned</th>
<th>State</th>
</tr>
<t t-foreach="widget.upcoming_data"
t-as="rec">
<tr>
<td><t t-esc="rec[0]"/></td>
<td><t t-esc="rec[2]"/></td>
<td><t t-esc="rec[4]"/></td>
<td><t t-esc="rec[3]"/></td>
<td>
<t t-if="rec[5] == 'draft'">
RFQ
</t>
<t t-if="rec[5] == 'sent'">
RFQ Sent
</t>
<t t-if="rec[5] == 'to approve'">
To Approve
</t>
<t t-if="rec[5] == 'purchase'">
Purchase Order
</t>
<t t-if="rec[5] == 'done'">
Locked
</t>
<t t-if="rec[5] == 'cancel'">
Cancelled
</t>
</td>
</tr>
</t>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</t>
</template>

13
purchase_dashboard_advanced/views/purchase_dashboard_menus.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--Client action for dashboard-->
<record id="action_dashboard_purchase" model="ir.actions.client">
<field name="name">Purchase</field>
<field name="tag">purchase_dashboard</field>
</record>
<!--MenuAction-->
<menuitem id="purchase_dashboard_menu"
name="Dashboard" action="action_dashboard_purchase"
parent="purchase.menu_purchase_root"
sequence="-1"/>
</odoo>
Loading…
Cancel
Save