Browse Source

[ADD] Initial Commit

pull/195/head
Ajmal Cybro 4 years ago
parent
commit
af842d3a2e
  1. 41
      export_stockinfo_xls/README.rst
  2. 24
      export_stockinfo_xls/__init__.py
  3. 54
      export_stockinfo_xls/__manifest__.py
  4. 22
      export_stockinfo_xls/controllers/__init__.py
  5. 57
      export_stockinfo_xls/controllers/main.py
  6. 11
      export_stockinfo_xls/doc/RELEASE_NOTES.md
  7. 24
      export_stockinfo_xls/models/__init__.py
  8. 41
      export_stockinfo_xls/models/res_partner.py
  9. 249
      export_stockinfo_xls/models/wizard.py
  10. 3
      export_stockinfo_xls/security/ir.model.access.csv
  11. BIN
      export_stockinfo_xls/static/description/assets/icons/check.png
  12. BIN
      export_stockinfo_xls/static/description/assets/icons/chevron.png
  13. BIN
      export_stockinfo_xls/static/description/assets/icons/cogs.png
  14. BIN
      export_stockinfo_xls/static/description/assets/icons/consultation.png
  15. BIN
      export_stockinfo_xls/static/description/assets/icons/ecom-black.png
  16. BIN
      export_stockinfo_xls/static/description/assets/icons/education-black.png
  17. BIN
      export_stockinfo_xls/static/description/assets/icons/hotel-black.png
  18. BIN
      export_stockinfo_xls/static/description/assets/icons/license.png
  19. BIN
      export_stockinfo_xls/static/description/assets/icons/lifebuoy.png
  20. BIN
      export_stockinfo_xls/static/description/assets/icons/logo.png
  21. BIN
      export_stockinfo_xls/static/description/assets/icons/manufacturing-black.png
  22. BIN
      export_stockinfo_xls/static/description/assets/icons/pos-black.png
  23. BIN
      export_stockinfo_xls/static/description/assets/icons/puzzle.png
  24. BIN
      export_stockinfo_xls/static/description/assets/icons/restaurant-black.png
  25. BIN
      export_stockinfo_xls/static/description/assets/icons/service-black.png
  26. BIN
      export_stockinfo_xls/static/description/assets/icons/trading-black.png
  27. BIN
      export_stockinfo_xls/static/description/assets/icons/training.png
  28. BIN
      export_stockinfo_xls/static/description/assets/icons/update.png
  29. BIN
      export_stockinfo_xls/static/description/assets/icons/user.png
  30. BIN
      export_stockinfo_xls/static/description/assets/icons/wrench.png
  31. BIN
      export_stockinfo_xls/static/description/assets/modules/approval_image.png
  32. BIN
      export_stockinfo_xls/static/description/assets/modules/budget_image.png
  33. BIN
      export_stockinfo_xls/static/description/assets/modules/export_image.png
  34. BIN
      export_stockinfo_xls/static/description/assets/modules/magento_image.png
  35. BIN
      export_stockinfo_xls/static/description/assets/modules/pos_image.png
  36. BIN
      export_stockinfo_xls/static/description/assets/modules/shopify_image.png
  37. BIN
      export_stockinfo_xls/static/description/assets/screenshots/hero.png
  38. BIN
      export_stockinfo_xls/static/description/assets/screenshots/stock_xlsx1.png
  39. BIN
      export_stockinfo_xls/static/description/assets/screenshots/stock_xlsx2.png
  40. BIN
      export_stockinfo_xls/static/description/banner.png
  41. BIN
      export_stockinfo_xls/static/description/icon.png
  42. 602
      export_stockinfo_xls/static/description/index.html
  43. 21
      export_stockinfo_xls/static/src/js/action_manager.js
  44. 49
      export_stockinfo_xls/views/wizard_view.xml
  45. 39
      hr_zk_attendance/README.rst
  46. 22
      hr_zk_attendance/__init__.py
  47. 43
      hr_zk_attendance/__manifest__.py
  48. 14
      hr_zk_attendance/data/download_data.xml
  49. 7
      hr_zk_attendance/doc/RELEASE_NOTES.md
  50. 25
      hr_zk_attendance/models/__init__.py
  51. 106
      hr_zk_attendance/models/machine_analysis.py
  52. 208
      hr_zk_attendance/models/zk_machine.py
  53. 118
      hr_zk_attendance/models/zkattendance.py
  54. 63
      hr_zk_attendance/models/zkconnect.py
  55. 71
      hr_zk_attendance/models/zkconst.py
  56. 82
      hr_zk_attendance/models/zkdevice.py
  57. 56
      hr_zk_attendance/models/zkextendfmt.py
  58. 61
      hr_zk_attendance/models/zkextendoplog.py
  59. 44
      hr_zk_attendance/models/zkface.py
  60. 156
      hr_zk_attendance/models/zklib.py
  61. 23
      hr_zk_attendance/models/zkos.py
  62. 23
      hr_zk_attendance/models/zkpin.py
  63. 43
      hr_zk_attendance/models/zkplatform.py
  64. 23
      hr_zk_attendance/models/zkserialnumber.py
  65. 23
      hr_zk_attendance/models/zkssr.py
  66. 50
      hr_zk_attendance/models/zktime.py
  67. 140
      hr_zk_attendance/models/zkuser.py
  68. 23
      hr_zk_attendance/models/zkversion.py
  69. 23
      hr_zk_attendance/models/zkworkcode.py
  70. 4
      hr_zk_attendance/security/ir.model.access.csv
  71. BIN
      hr_zk_attendance/static/description/assets/icons/check.png
  72. BIN
      hr_zk_attendance/static/description/assets/icons/chevron.png
  73. BIN
      hr_zk_attendance/static/description/assets/icons/cogs.png
  74. BIN
      hr_zk_attendance/static/description/assets/icons/consultation.png
  75. BIN
      hr_zk_attendance/static/description/assets/icons/ecom-black.png
  76. BIN
      hr_zk_attendance/static/description/assets/icons/education-black.png
  77. BIN
      hr_zk_attendance/static/description/assets/icons/hotel-black.png
  78. BIN
      hr_zk_attendance/static/description/assets/icons/license.png
  79. BIN
      hr_zk_attendance/static/description/assets/icons/lifebuoy.png
  80. BIN
      hr_zk_attendance/static/description/assets/icons/manufacturing-black.png
  81. BIN
      hr_zk_attendance/static/description/assets/icons/pos-black.png
  82. BIN
      hr_zk_attendance/static/description/assets/icons/puzzle.png
  83. BIN
      hr_zk_attendance/static/description/assets/icons/restaurant-black.png
  84. BIN
      hr_zk_attendance/static/description/assets/icons/service-black.png
  85. BIN
      hr_zk_attendance/static/description/assets/icons/trading-black.png
  86. BIN
      hr_zk_attendance/static/description/assets/icons/training.png
  87. BIN
      hr_zk_attendance/static/description/assets/icons/update.png
  88. BIN
      hr_zk_attendance/static/description/assets/icons/user.png
  89. BIN
      hr_zk_attendance/static/description/assets/icons/wrench.png
  90. BIN
      hr_zk_attendance/static/description/assets/modules/approval_image.png
  91. BIN
      hr_zk_attendance/static/description/assets/modules/budget_image.png
  92. BIN
      hr_zk_attendance/static/description/assets/modules/gantt_image.png
  93. BIN
      hr_zk_attendance/static/description/assets/modules/library_image.png
  94. BIN
      hr_zk_attendance/static/description/assets/modules/pos_order_image.png
  95. BIN
      hr_zk_attendance/static/description/assets/modules/whatsapp_image.gif
  96. BIN
      hr_zk_attendance/static/description/assets/screenshots/hero.gif
  97. BIN
      hr_zk_attendance/static/description/assets/screenshots/hero.png
  98. BIN
      hr_zk_attendance/static/description/assets/screenshots/machine-IP.png
  99. BIN
      hr_zk_attendance/static/description/assets/screenshots/screenshot1.png
  100. BIN
      hr_zk_attendance/static/description/assets/screenshots/screenshot2.png

41
export_stockinfo_xls/README.rst

@ -0,0 +1,41 @@
Export Product Stock in Excel v15
=================================
This module helps you to take current stock report for all products in each warehouse.
Configuration
=============
* No additional configurations needed
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
-------
* Developers: Cybrosys Techno Solutions odoo@cybrosys.com
Version 15: Midilaj V K @cybrosys
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>`__

24
export_stockinfo_xls/__init__.py

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

54
export_stockinfo_xls/__manifest__.py

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2021-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Midilaj (<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': 'Export Product Stock in Excel',
'version': '15.0.1.0.0',
'live_test_url': 'https://www.youtube.com/watch?v=9ae4GkApHQM',
'summary': "Current Stock Report for all Products in each Warehouse",
'description': "Current Stock Report for all Products in each Warehouse, Odoo 13,Odoo13",
'category': 'Warehouse',
'author': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com',
'depends': [
'base',
'stock',
'sale',
'purchase',
],
'data': [
'views/wizard_view.xml',
'security/ir.model.access.csv',
],
'images': ['static/description/banner.png'],
'assets': {
'web.assets_backend': [
'export_stockinfo_xls/static/src/js/action_manager.js',
],
},
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'auto_install': False,
}

22
export_stockinfo_xls/controllers/__init__.py

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

57
export_stockinfo_xls/controllers/main.py

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2020-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Midilaj (<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 json
from odoo import http
from odoo.http import content_disposition, request
from odoo.addons.web.controllers.main import _serialize_exception
from odoo.tools import html_escape
class XLSXReportController(http.Controller):
@http.route('/xlsx_reports', type='http', auth='user', methods=['POST'], csrf=False)
def get_report_xlsx(self, model, options, output_format, report_name, **kw):
uid = request.session.uid
report_obj = request.env[model].with_user(uid)
options = json.loads(options)
token = 'dummy-because-api-expects-one'
try:
if output_format == 'xlsx':
response = request.make_response(
None,
headers=[
('Content-Type', 'application/vnd.ms-excel'),
('Content-Disposition', content_disposition(report_name + '.xlsx'))
]
)
report_obj.get_xlsx_report(options, response)
response.set_cookie('fileToken', token)
return response
except Exception as e:
se = _serialize_exception(e)
error = {
'code': 200,
'message': 'Odoo Server Error',
'data': se
}
return request.make_response(html_escape(json.dumps(error)))

11
export_stockinfo_xls/doc/RELEASE_NOTES.md

@ -0,0 +1,11 @@
## Module <export_stockinfo_xls>
#### 04.10.2021
#### Version 15.0.1.0.0
#### ADD
Initial Commit Export Product Stock in Excel

24
export_stockinfo_xls/models/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2020-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Midilaj (<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 res_partner
from . import wizard

41
export_stockinfo_xls/models/res_partner.py

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2020-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Midilaj (<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 odoo import models, fields
class Partner(models.Model):
_inherit = 'res.partner'
supplier_id = fields.Many2many('wizard.stock.history', 'supp_wiz_rel', 'wiz', 'supp', invisible=True)
class Category(models.Model):
_inherit = 'product.category'
obj = fields.Many2many('wizard.stock.history', 'categ_wiz_rel', 'wiz', 'categ', invisible=True)
class Warehouse(models.Model):
_inherit = 'stock.warehouse'
obj = fields.Many2many('wizard.stock.history', 'wh_wiz_rel', 'wiz', 'wh', invisible=True)

249
export_stockinfo_xls/models/wizard.py

@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2020-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Midilaj (<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 time
from datetime import date, datetime
import pytz
import json
import datetime
import io
from odoo import api, fields, models, _
from odoo.tools import date_utils
try:
from odoo.tools.misc import xlsxwriter
except ImportError:
import xlsxwriter
class StockReport(models.TransientModel):
_name = "wizard.stock.history"
_description = "Current Stock History"
warehouse = fields.Many2many('stock.warehouse', 'wh_wiz_rel', 'wh', 'wiz', string='Warehouse', required=True)
category = fields.Many2many('product.category', 'categ_wiz_rel', 'categ', 'wiz', string='Warehouse')
def export_xls(self):
data = {
'ids': self.ids,
'model': self._name,
'warehouse': self.warehouse.ids,
'category': self.category.ids,
}
return {
'type': 'ir.actions.report',
'data': {'model': 'wizard.stock.history',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': 'Current Stock History',
},
'report_type': 'stock_xlsx'
}
def get_warehouse(self, data):
wh = data.warehouse.mapped('id')
obj = self.env['stock.warehouse'].search([('id', 'in', wh)])
l1 = []
l2 = []
for j in obj:
l1.append(j.name)
l2.append(j.id)
return l1, l2
def get_lines(self, data, warehouse):
lines = []
categ_id = data.mapped('id')
if categ_id:
categ_products = self.env['product.product'].search([('categ_id', 'in', categ_id)])
else:
categ_products = self.env['product.product'].search([])
product_ids = tuple([pro_id.id for pro_id in categ_products])
sale_query = """
SELECT sum(s_o_l.product_uom_qty) AS product_uom_qty, s_o_l.product_id FROM sale_order_line AS s_o_l
JOIN sale_order AS s_o ON s_o_l.order_id = s_o.id
WHERE s_o.state IN ('sale','done')
AND s_o.warehouse_id = %s
AND s_o_l.product_id in %s group by s_o_l.product_id"""
purchase_query = """
SELECT sum(p_o_l.product_qty) AS product_qty, p_o_l.product_id FROM purchase_order_line AS p_o_l
JOIN purchase_order AS p_o ON p_o_l.order_id = p_o.id
INNER JOIN stock_picking_type AS s_p_t ON p_o.picking_type_id = s_p_t.id
WHERE p_o.state IN ('purchase','done')
AND s_p_t.warehouse_id = %s AND p_o_l.product_id in %s group by p_o_l.product_id"""
params = warehouse, product_ids if product_ids else (0, 0)
self._cr.execute(sale_query, params)
sol_query_obj = self._cr.dictfetchall()
self._cr.execute(purchase_query, params)
pol_query_obj = self._cr.dictfetchall()
for obj in categ_products:
sale_value = 0
purchase_value = 0
for sol_product in sol_query_obj:
if sol_product['product_id'] == obj.id:
sale_value = sol_product['product_uom_qty']
for pol_product in pol_query_obj:
if pol_product['product_id'] == obj.id:
purchase_value = pol_product['product_qty']
virtual_available = obj.with_context({'warehouse': warehouse}).virtual_available
outgoing_qty = obj.with_context({'warehouse': warehouse}).outgoing_qty
incoming_qty = obj.with_context({'warehouse': warehouse}).incoming_qty
available_qty = virtual_available + outgoing_qty - incoming_qty
value = available_qty * obj.standard_price
vals = {
'sku': obj.default_code,
'name': obj.name,
'category': obj.categ_id.name,
'cost_price': obj.standard_price,
'available': available_qty,
'virtual': virtual_available,
'incoming': incoming_qty,
'outgoing': outgoing_qty,
'net_on_hand': obj.with_context({'warehouse': warehouse}).qty_available,
'total_value': value,
'sale_value': sale_value,
'purchase_value': purchase_value,
}
lines.append(vals)
return lines
def get_xlsx_report(self, data, response):
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
lines = self.browse(data['ids'])
d = lines.category
get_warehouse = self.get_warehouse(lines)
count = len(get_warehouse[0]) * 11 + 6
comp = self.env.user.company_id.name
sheet = workbook.add_worksheet('Stock Info')
format0 = workbook.add_format({'font_size': 20, 'align': 'center', 'bold': True})
format1 = workbook.add_format({'font_size': 14, 'align': 'vcenter', 'bold': True})
format11 = workbook.add_format({'font_size': 12, 'align': 'center', 'bold': True})
format21 = workbook.add_format({'font_size': 10, 'align': 'center', 'bold': True})
format3 = workbook.add_format({'bottom': True, 'top': True, 'font_size': 12})
format4 = workbook.add_format({'font_size': 12, 'align': 'left', 'bold': True})
font_size_8 = workbook.add_format({'font_size': 8, 'align': 'center'})
font_size_8_l = workbook.add_format({'font_size': 8, 'align': 'left'})
font_size_8_r = workbook.add_format({'font_size': 8, 'align': 'right'})
red_mark = workbook.add_format({'font_size': 8, 'bg_color': 'red'})
justify = workbook.add_format({'font_size': 12})
format3.set_align('center')
justify.set_align('justify')
format1.set_align('center')
red_mark.set_align('center')
sheet.merge_range(1, 7, 2, 10, 'Product Stock Info', format0)
sheet.merge_range(3, 7, 3, 10, comp, format11)
w_house = ', '
cat = ', '
c = []
d1 = d.mapped('id')
if d1:
for i in d1:
c.append(self.env['product.category'].browse(i).name)
cat = cat.join(c)
sheet.merge_range(4, 0, 4, 1, 'Category(s) : ', format4)
sheet.merge_range(4, 2, 4, 3 + len(d1), cat, format4)
sheet.merge_range(5, 0, 5, 1, 'Warehouse(s) : ', format4)
w_house = w_house.join(get_warehouse[0])
sheet.merge_range(5, 2, 5, 3 + len(get_warehouse[0]), w_house, format4)
user = self.env['res.users'].browse(self.env.uid)
tz = pytz.timezone(user.tz if user.tz else 'UTC')
times = pytz.utc.localize(datetime.datetime.now()).astimezone(tz)
sheet.merge_range('A8:G8', 'Report Date: ' + str(times.strftime("%Y-%m-%d %H:%M %p")), format1)
sheet.merge_range(7, 7, 7, count, 'Warehouses', format1)
sheet.merge_range('A9:G9', 'Product Information', format11)
w_col_no = 6
w_col_no1 = 7
for i in get_warehouse[0]:
w_col_no = w_col_no + 11
sheet.merge_range(8, w_col_no1, 8, w_col_no, i, format11)
w_col_no1 = w_col_no1 + 11
sheet.write(9, 0, 'SKU', format21)
sheet.merge_range(9, 1, 9, 3, 'Name', format21)
sheet.merge_range(9, 4, 9, 5, 'Category', format21)
sheet.write(9, 6, 'Cost Price', format21)
p_col_no1 = 7
for i in get_warehouse[0]:
sheet.write(9, p_col_no1, 'Available', format21)
sheet.write(9, p_col_no1 + 1, 'Virtual', format21)
sheet.write(9, p_col_no1 + 2, 'Incoming', format21)
sheet.write(9, p_col_no1 + 3, 'Outgoing', format21)
sheet.merge_range(9, p_col_no1 + 4, 9, p_col_no1 + 5, 'Net On Hand', format21)
sheet.merge_range(9, p_col_no1 + 6, 9, p_col_no1 + 7, 'Total Sold', format21)
sheet.merge_range(9, p_col_no1 + 8, 9, p_col_no1 + 9, 'Total Purchased', format21)
sheet.write(9, p_col_no1 + 10, 'Valuation', format21)
p_col_no1 = p_col_no1 + 11
prod_row = 10
prod_col = 0
for i in get_warehouse[1]:
get_line = self.get_lines(d, i)
for each in get_line:
sheet.write(prod_row, prod_col, each['sku'], font_size_8)
sheet.merge_range(prod_row, prod_col + 1, prod_row, prod_col + 3, each['name'], font_size_8_l)
sheet.merge_range(prod_row, prod_col + 4, prod_row, prod_col + 5, each['category'], font_size_8_l)
sheet.write(prod_row, prod_col + 6, each['cost_price'], font_size_8_r)
prod_row = prod_row + 1
break
prod_row = 10
prod_col = 7
for i in get_warehouse[1]:
get_line = self.get_lines(d, i)
for each in get_line:
if each['available'] < 0:
sheet.write(prod_row, prod_col, each['available'], red_mark)
else:
sheet.write(prod_row, prod_col, each['available'], font_size_8)
if each['virtual'] < 0:
sheet.write(prod_row, prod_col + 1, each['virtual'], red_mark)
else:
sheet.write(prod_row, prod_col + 1, each['virtual'], font_size_8)
if each['incoming'] < 0:
sheet.write(prod_row, prod_col + 2, each['incoming'], red_mark)
else:
sheet.write(prod_row, prod_col + 2, each['incoming'], font_size_8)
if each['outgoing'] < 0:
sheet.write(prod_row, prod_col + 3, each['outgoing'], red_mark)
else:
sheet.write(prod_row, prod_col + 3, each['outgoing'], font_size_8)
if each['net_on_hand'] < 0:
sheet.merge_range(prod_row, prod_col + 4, prod_row, prod_col + 5, each['net_on_hand'], red_mark)
else:
sheet.merge_range(prod_row, prod_col + 4, prod_row, prod_col + 5, each['net_on_hand'], font_size_8)
if each['sale_value'] < 0:
sheet.merge_range(prod_row, prod_col + 6, prod_row, prod_col + 7, each['sale_value'], red_mark)
else:
sheet.merge_range(prod_row, prod_col + 6, prod_row, prod_col + 7, each['sale_value'], font_size_8)
if each['purchase_value'] < 0:
sheet.merge_range(prod_row, prod_col + 8, prod_row, prod_col + 9, each['purchase_value'], red_mark)
else:
sheet.merge_range(prod_row, prod_col + 8, prod_row, prod_col + 9, each['purchase_value'],
font_size_8)
if each['total_value'] < 0:
sheet.write(prod_row, prod_col + 10, each['total_value'], red_mark)
else:
sheet.write(prod_row, prod_col + 10, each['total_value'], font_size_8_r)
prod_row = prod_row + 1
prod_row = 10
prod_col = prod_col + 11
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()

3
export_stockinfo_xls/security/ir.model.access.csv

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_wizard_stock_history_user,wizard.stock.history,model_wizard_stock_history,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_wizard_stock_history_user wizard.stock.history model_wizard_stock_history base.group_user 1 1 1 1

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
export_stockinfo_xls/static/description/assets/icons/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
export_stockinfo_xls/static/description/assets/modules/approval_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
export_stockinfo_xls/static/description/assets/modules/budget_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
export_stockinfo_xls/static/description/assets/modules/export_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
export_stockinfo_xls/static/description/assets/modules/magento_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
export_stockinfo_xls/static/description/assets/modules/pos_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
export_stockinfo_xls/static/description/assets/modules/shopify_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
export_stockinfo_xls/static/description/assets/screenshots/hero.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

BIN
export_stockinfo_xls/static/description/assets/screenshots/stock_xlsx1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
export_stockinfo_xls/static/description/assets/screenshots/stock_xlsx2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

BIN
export_stockinfo_xls/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
export_stockinfo_xls/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

602
export_stockinfo_xls/static/description/index.html

@ -0,0 +1,602 @@
<div class="container" style="padding: 1rem !important; margin-bottom: 1rem !important;">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between"
style="border-bottom: 1px solid #d5d5d5;">
<div class="my-3">
<img src="./assets/icons/logo.png" style="width: auto !important; height: 40px !important;">
</div>
<div class="my-3 d-flex align-items-center">
<div
style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
</div>
</div>
<div class="container" style="padding: 0rem 1.5rem 4rem !important">
<div class="row" style="height: 900px !important;">
<div class="col-sm-12 col-md-12 col-lg-12"
style="padding: 4rem 1rem !important; background-color: #714B67 !important; height: 600px !important; border-radius: 20px !important;">
<h1
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #FFFFFF !important; font-size: 3.5rem !important; text-align: center !important;">
Current Stock XLS</h1>
<p
style="font-family: 'Montserrat', sans-serif !important; font-weight: 300 !important; color: #FFFFFF !important; font-size: 1.4rem !important; text-align: center !important;">
Current Stock Report for all Products in each Warehouse
</p>
<img src="./assets/screenshots/hero.png" class="img-responsive" width="100%" height="auto" />
</div>
</div>
<div class="row">
<div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin-bottom: 2rem !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-compass mr-2"></i>Explore this module
</h2>
</div>
<div class="col-md-6">
<a href="#overview" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Overview</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
Learn more about this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right" style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#features" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Features</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
View features of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right" style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#screenshots" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Screenshots</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
See key screenshots of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right" style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
</div>
<div class="row" id="overview">
<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-pie-chart mr-2"></i>Overview
</h2>
</div>
<div class="col-mg-12 pl-3">
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important; line-height: 30px !important;">
This module helps to print Current Stock Report for all Products in each Warehouse with XLS</p>
</div>
</div>
<div class="row" id="features">
<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-star mr-2"></i>Features
</h2>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Community &amp; Enterprise Support</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Available in Odoo 14.0 Community and Enterprise.</p>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Current Stock XLS</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Current Stock Report for all Products in each Warehouse.</p>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Select category for products</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Get your stock valuation details</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Negative stock will be highlighted in "red" cells.</h4>
</div>
</div>
</div>
<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;">
Export Stock Info Wizard</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Go to Inventory -> Reports -> Current stock in Excel. Now a wizard will appear on your screen.
Please enter the warehouses which you want to take the report.
You can also select category for products(It is Optional). Then Click "Export Product with Stock
Info" button. Then You will get the corresponding report in XLS.</p>
<img src="assets/screenshots/stock_xlsx1.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;">
Stock Info Excel Report</h4>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Per warehouse you can get Available Qty, Virtual Qty, Incoming Qty, Outgoing Qty, Net On Hand Qty,
Total Sold & Total Purchased Qty.
You can get your stock valuation details too.
Negative stock will be highlighted in "red" cells.
</p>
<img src="assets/screenshots/stock_xlsx2.png" class="img-responsive img-thumbnail border" width="100%"
height="auto" />
</div>
</div>
<!-- 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/14.0/export_stockinfo_xls/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/export_image.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/14.0/dashboard_pos/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/pos_image.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/14.0/product_approval_management/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/approval_image.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/14.0/base_account_budget/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/budget_image.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/14.0/shopify_odoo_connector/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/shopify_image.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/14.0/odoo11_magento2/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/magento_image.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 SUGGESTED PRODUCTS -->
<!-- OUR SERVICES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Services</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
</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: #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>
</section>
<!-- END OF END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Industries</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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>
</section>
<!-- END OF END OF OUR INDUSTRIES -->
<!-- FOOTER -->
<!-- Footer Section -->
<section class="container" style="margin: 5rem auto 2rem;">
<div class="row" style="max-width:1540px;">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Need Help?</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" />
</div>
</div>
<!-- Contact Cards -->
<div class="row d-flex justify-content-center align-items-center"
style="max-width:1540px; margin: 0 auto 2rem auto;">
<div class="col-lg-12" style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; ">
<div class="row mt-4">
<div class="col-lg-6">
<a href="mailto:odoo@cybrosys.com" target="_blank" class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i
class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a>
</div>
<div class="col-lg-6">
<a href="https://api.whatsapp.com/send?phone=918606827707" target="_blank"
class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #25D366; color: #FFF; border-radius: 4px;"><i
class="fa fa-whatsapp mr-2"></i>WhatsApp</a>
</div>
</div>
</div>
</div>
<!-- End of Contact Cards -->
</section>
<!-- Footer -->
<section class="oe_container" style="padding: 2rem 3rem 1rem;">
<div class="row" style="max-width:1540px; margin: 0 auto; margin-right: 3rem; ">
<!-- Logo -->
<div class="col-lg-12 d-flex justify-content-center align-items-center" style="margin-top: 3rem;">
<img src="https://www.cybrosys.com/images/logo.png" width="200px" height="auto" />
</div>
<!-- End of Logo -->
<div class="col-lg-12">
<hr
style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;">
<!-- End of Footer Section -->
</div>
</div>
</section>
<!-- END OF FOOTER -->
</div>

21
export_stockinfo_xls/static/src/js/action_manager.js

@ -0,0 +1,21 @@
/** @odoo-module */
import { registry } from "@web/core/registry";
import { download } from "@web/core/network/download";
import framework from 'web.framework';
import session from 'web.session';
registry.category("ir.actions.report handlers").add("stock_xlsx", async (action) => {
if (action.report_type === 'stock_xlsx') {
framework.blockUI();
var def = $.Deferred();
session.get_file({
url: '/xlsx_reports',
data: action.data,
success: def.resolve.bind(def),
error: (error) => this.call('crash_manager', 'rpc_error', error),
complete: framework.unblockUI,
});
return def;
}
});

49
export_stockinfo_xls/views/wizard_view.xml

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model='ir.ui.view' id='wizard_form'>
<field name="name">wizard.stock.history.form</field>
<field name="model">wizard.stock.history</field>
<field name="arch" type="xml">
<form string="Wizard">
<group string="Warehouse">
<field name="warehouse" widget="many2many_tags"/>
</group>
<notebook>
<page string="Category">
<field name="category">
<tree>
<field name="name"/>
</tree>
</field>
</page>
</notebook>
<footer>
<button name="export_xls" type="object" default_focus="1"
string="Export Product with Stock Info" class="oe_highlight"
context="{'xls_export':1}" icon="fa-download"/>
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record model='ir.actions.act_window' id='wizard_act'>
<field name="name">Export product stock in Excel</field>
<field name="res_model">wizard.stock.history</field>
<field name="type">ir.actions.act_window</field>
<field name="view_mode">form</field>
<field name="view_id" ref="wizard_form"/>
<field name="target">new</field>
</record>
<menuitem name="Current stock in Excel"
parent="stock.menu_warehouse_report"
id="export_excel"
action="wizard_act"
sequence="3"/>
</data>
</odoo>

39
hr_zk_attendance/README.rst

@ -0,0 +1,39 @@
Biometric Device Integration v15
================================
This Cybrosys's module integrates Odoo attendance with biometric device attendance.
Features
========
* Integrates biometric device(Face+Thumb) with HR attendance.
* Managing attendance automatically
* Keeps zk machine history in Odoo
* Option to configure multiple zk devices
* Option to clear all zk history from both device and Odoo
Technical Notes
===============
Used Libraries:
*This integration is only applicable for the the device ZKteco model 'uFace 202' & 'iFace990'
* zklib
you can install zklib library using "sudo pip install zklib"
Compatible Devices
*ZKteco model 'uFace 202'
*ZKteco model 'iFace990'
Author
=======
* Cybrosys Techno Solutions <https://www.cybrosys.com>
Credits
=======
Developer: Niyas Raphy @ Cybrosys, odoo@cybrosys.com V11
Developer: Jesni Banu @ cybrosys, odoo@cybrosys.com V10
Developer: Basith @ Cybrosys, odoo@cybrosys.com V12
Developer: Varsha Vivek @ Cybrosys, odoo@cybrosys.com V13
Developer: Ijaz Ahammed @ Cybrosys, odoo@cybrosys.com V14
Developer: Noushid Khan @ Cybrosys, odoo@cybrosys.com V15
Developer: Mostafa Shokiel , mostafa.shokiel@gmail.com

22
hr_zk_attendance/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
from . import models

43
hr_zk_attendance/__manifest__.py

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2021-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
{
'name': 'Biometric Device Integration',
'version': '15.0.1.0.0',
'summary': """Integrating Biometric Device (Model: ZKteco uFace 202) With HR Attendance (Face + Thumb)""",
'description': """This module integrates Odoo with the biometric device(Model: ZKteco uFace 202),odoo15,odoo,hr,attendance""",
'category': 'Generic Modules/Human Resources',
'author': 'Cybrosys Techno Solutions, Mostafa Shokiel',
'company': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
'depends': ['base_setup', 'hr_attendance'],
'data': [
'security/ir.model.access.csv',
'views/zk_machine_view.xml',
'views/zk_machine_attendance_view.xml',
'data/download_data.xml'
],
'images': ['static/description/banner.png'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

14
hr_zk_attendance/data/download_data.xml

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<odoo noupdate="1">
<record forcecreate="True" id="cron_download_data" model="ir.cron">
<field name="name">Download Data</field>
<field eval="True" name="active"/>
<field name="user_id" ref="base.user_admin"/>
<field name="interval_number">10</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="model_id" ref="hr_zk_attendance.model_zk_machine"/>
<field name="state">code</field>
<field name="code">model.cron_download()</field>
</record>
</odoo>

7
hr_zk_attendance/doc/RELEASE_NOTES.md

@ -0,0 +1,7 @@
## Module <hr_zk_attendance>
#### 03.10.2021
#### Version 15.0.1.0.0
##### ADD
- Initial commit

25
hr_zk_attendance/models/__init__.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
from . import zk_machine
from . import machine_analysis
from . import zklib

106
hr_zk_attendance/models/machine_analysis.py

@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
from odoo import tools
from odoo import models, fields, api, _
class HrEmployee(models.Model):
_inherit = 'hr.employee'
device_id = fields.Char(string='Biometric Device ID')
class ZkMachine(models.Model):
_name = 'zk.machine.attendance'
_inherit = 'hr.attendance'
@api.constrains('check_in', 'check_out', 'employee_id')
def _check_validity(self):
"""overriding the __check_validity function for employee attendance."""
pass
device_id = fields.Char(string='Biometric Device ID')
punch_type = fields.Selection([('0', 'Check In'),
('1', 'Check Out'),
('2', 'Break Out'),
('3', 'Break In'),
('4', 'Overtime In'),
('5', 'Overtime Out')],
string='Punching Type')
attendance_type = fields.Selection([('1', 'Finger'),
('15', 'Face'),
('2','Type_2'),
('3','Password'),
('4','Card')], string='Category')
punching_time = fields.Datetime(string='Punching Time')
address_id = fields.Many2one('res.partner', string='Working Address')
class ReportZkDevice(models.Model):
_name = 'zk.report.daily.attendance'
_auto = False
_order = 'punching_day desc'
name = fields.Many2one('hr.employee', string='Employee')
punching_day = fields.Datetime(string='Date')
address_id = fields.Many2one('res.partner', string='Working Address')
attendance_type = fields.Selection([('1', 'Finger'),
('15', 'Face'),
('2','Type_2'),
('3','Password'),
('4','Card')],
string='Category')
punch_type = fields.Selection([('0', 'Check In'),
('1', 'Check Out'),
('2', 'Break Out'),
('3', 'Break In'),
('4', 'Overtime In'),
('5', 'Overtime Out')], string='Punching Type')
punching_time = fields.Datetime(string='Punching Time')
def init(self):
tools.drop_view_if_exists(self._cr, 'zk_report_daily_attendance')
query = """
create or replace view zk_report_daily_attendance as (
select
min(z.id) as id,
z.employee_id as name,
z.write_date as punching_day,
z.address_id as address_id,
z.attendance_type as attendance_type,
z.punching_time as punching_time,
z.punch_type as punch_type
from zk_machine_attendance z
join hr_employee e on (z.employee_id=e.id)
GROUP BY
z.employee_id,
z.write_date,
z.address_id,
z.attendance_type,
z.punch_type,
z.punching_time
)
"""
self._cr.execute(query)

208
hr_zk_attendance/models/zk_machine.py

@ -0,0 +1,208 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2020-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
import pytz
import sys
import datetime
import logging
import binascii
from . import zklib
from .zkconst import *
from struct import unpack
from odoo import api, fields, models
from odoo import _
from odoo.exceptions import UserError, ValidationError
_logger = logging.getLogger(__name__)
try:
from zk import ZK, const
except ImportError:
_logger.error("Please Install pyzk library.")
_logger = logging.getLogger(__name__)
class HrAttendance(models.Model):
_inherit = 'hr.attendance'
device_id = fields.Char(string='Biometric Device ID')
class ZkMachine(models.Model):
_name = 'zk.machine'
name = fields.Char(string='Machine IP', required=True)
port_no = fields.Integer(string='Port No', required=True)
address_id = fields.Many2one('res.partner', string='Working Address')
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id.id)
def device_connect(self, zk):
try:
conn = zk.connect()
return conn
except:
return False
def clear_attendance(self):
for info in self:
try:
machine_ip = info.name
zk_port = info.port_no
timeout = 30
try:
zk = ZK(machine_ip, port=zk_port, timeout=timeout, password=0, force_udp=False, ommit_ping=False)
except NameError:
raise UserError(_("Please install it with 'pip3 install pyzk'."))
conn = self.device_connect(zk)
if conn:
conn.enable_device()
clear_data = zk.get_attendance()
if clear_data:
# conn.clear_attendance()
self._cr.execute("""delete from zk_machine_attendance""")
conn.disconnect()
raise UserError(_('Attendance Records Deleted.'))
else:
raise UserError(_('Unable to clear Attendance log. Are you sure attendance log is not empty.'))
else:
raise UserError(
_('Unable to connect to Attendance Device. Please use Test Connection button to verify.'))
except:
raise ValidationError(
'Unable to clear Attendance log. Are you sure attendance device is connected & record is not empty.')
def getSizeUser(self, zk):
"""Checks a returned packet to see if it returned CMD_PREPARE_DATA,
indicating that data packets are to be sent
Returns the amount of bytes that are going to be sent"""
command = unpack('HHHH', zk.data_recv[:8])[0]
if command == CMD_PREPARE_DATA:
size = unpack('I', zk.data_recv[8:12])[0]
print("size", size)
return size
else:
return False
def zkgetuser(self, zk):
"""Start a connection with the time clock"""
try:
users = zk.get_users()
print(users)
return users
except:
return False
@api.model
def cron_download(self):
machines = self.env['zk.machine'].search([])
for machine in machines :
machine.download_attendance()
def download_attendance(self):
_logger.info("++++++++++++Cron Executed++++++++++++++++++++++")
zk_attendance = self.env['zk.machine.attendance']
att_obj = self.env['hr.attendance']
for info in self:
machine_ip = info.name
zk_port = info.port_no
timeout = 15
try:
zk = ZK(machine_ip, port=zk_port, timeout=timeout, password=0, force_udp=False, ommit_ping=False)
except NameError:
raise UserError(_("Pyzk module not Found. Please install it with 'pip3 install pyzk'."))
conn = self.device_connect(zk)
if conn:
# conn.disable_device() #Device Cannot be used during this time.
try:
user = conn.get_users()
except:
user = False
try:
attendance = conn.get_attendance()
except:
attendance = False
if attendance:
for each in attendance:
atten_time = each.timestamp
atten_time = datetime.strptime(atten_time.strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S')
local_tz = pytz.timezone(
self.env.user.partner_id.tz or 'GMT')
local_dt = local_tz.localize(atten_time, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)
utc_dt = utc_dt.strftime("%Y-%m-%d %H:%M:%S")
atten_time = datetime.strptime(
utc_dt, "%Y-%m-%d %H:%M:%S")
atten_time = fields.Datetime.to_string(atten_time)
if user:
for uid in user:
if uid.user_id == each.user_id:
get_user_id = self.env['hr.employee'].search(
[('device_id', '=', each.user_id)])
if get_user_id:
duplicate_atten_ids = zk_attendance.search(
[('device_id', '=', each.user_id), ('punching_time', '=', atten_time)])
if duplicate_atten_ids:
continue
else:
zk_attendance.create({'employee_id': get_user_id.id,
'device_id': each.user_id,
'attendance_type': str(each.status),
'punch_type': str(each.punch),
'punching_time': atten_time,
'address_id': info.address_id.id})
att_var = att_obj.search([('employee_id', '=', get_user_id.id),
('check_out', '=', False)])
print('ddfcd', str(each.status))
if each.punch == 0: #check-in
if not att_var:
att_obj.create({'employee_id': get_user_id.id,
'check_in': atten_time})
if each.punch == 1: #check-out
if len(att_var) == 1:
att_var.write({'check_out': atten_time})
else:
att_var1 = att_obj.search([('employee_id', '=', get_user_id.id)])
if att_var1:
att_var1[-1].write({'check_out': atten_time})
else:
print('ddfcd', str(each.status))
print('user', uid.name)
employee = self.env['hr.employee'].create(
{'device_id': each.user_id, 'name': uid.name})
zk_attendance.create({'employee_id': employee.id,
'device_id': each.user_id,
'attendance_type': str(each.status),
'punch_type': str(each.punch),
'punching_time': atten_time,
'address_id': info.address_id.id})
att_obj.create({'employee_id': employee.id,
'check_in': atten_time})
else:
pass
# zk.enableDevice()
conn.disconnect
return True
else:
raise UserError(_('Unable to get the attendance log, please try again later.'))
else:
raise UserError(_('Unable to connect, please check the parameters and network connections.'))

118
hr_zk_attendance/models/zkattendance.py

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
import binascii
from struct import pack, unpack
from .zkconst import *
def getSizeAttendance(self):
"""Checks a returned packet to see if it returned CMD_PREPARE_DATA,
indicating that data packets are to be sent
Returns the amount of bytes that are going to be sent"""
command = unpack('HHHH', self.data_recv[:8])[0]
if command == CMD_PREPARE_DATA:
size = unpack('I', self.data_recv[8:12])[0]
return size
else:
return False
def reverseHex(hexstr):
tmp = ''
for i in reversed(range(int(len(hexstr)/2))):
tmp += hexstr[i*2:(i*2)+2]
return tmp
def zkgetattendance(self):
"""Start a connection with the time clock"""
command = CMD_ATTLOG_RRQ
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
if getSizeAttendance(self):
bytes = getSizeAttendance(self)
while bytes > 0:
data_recv, addr = self.zkclient.recvfrom(1032)
self.attendancedata.append(data_recv)
bytes -= 1024
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
data_recv = self.zkclient.recvfrom(8)
attendance = []
if len(self.attendancedata) > 0:
# The first 4 bytes don't seem to be related to the user
for x in range(len(self.attendancedata)):
if x > 0:
self.attendancedata[x] = self.attendancedata[x][8:]
attendancedata = b''.join( self.attendancedata )
attendancedata = attendancedata[14:]
while len(attendancedata) > 40:
uid, state, timestamp, space = unpack( '24s1s4s11s', attendancedata.ljust(40)[:40] )
# Clean up some messy characters from the user name
#uid = unicode(uid.strip('\x00|\x01\x10x'), errors='ignore')
uid = uid.split(b'\x00', 1)[0].decode('utf-8')
#print "%s, %s, %s" % (uid, state, decode_time( int( reverseHex( timestamp.encode('hex') ), 16 ) ) )
attendance.append( ( uid, int( binascii.hexlify(state), 16 ), decode_time( int( reverseHex( binascii.hexlify(timestamp).decode('utf-8')), 16 ) ) ) )
attendancedata = attendancedata[40:]
return attendance
except:
return False
def zkclearattendance(self):
"""Start a connection with the time clock"""
command = CMD_CLEAR_ATTLOG
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

63
hr_zk_attendance/models/zkconnect.py

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
from struct import pack, unpack
from .zkconst import *
def zkconnect(self):
"""Start a connection with the time clock"""
command = CMD_CONNECT
command_string = ''
chksum = 0
session_id = 0
reply_id = -1 + USHRT_MAX
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.checkValid( self.data_recv )
except:
return False
def zkdisconnect(self):
"""Disconnect from the clock"""
command = CMD_EXIT
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
self.data_recv, addr = self.zkclient.recvfrom(1024)
return self.checkValid( self.data_recv )

71
hr_zk_attendance/models/zkconst.py

@ -0,0 +1,71 @@
from datetime import datetime, date
USHRT_MAX = 65535
CMD_CONNECT = 1000
CMD_EXIT = 1001
CMD_ENABLEDEVICE = 1002
CMD_DISABLEDEVICE = 1003
CMD_ACK_OK = 2000
CMD_ACK_ERROR = 2001
CMD_ACK_DATA = 2002
CMD_PREPARE_DATA = 1500
CMD_DATA = 1501
CMD_USERTEMP_RRQ = 9
CMD_ATTLOG_RRQ = 13
CMD_CLEAR_DATA = 14
CMD_CLEAR_ATTLOG = 15
CMD_WRITE_LCD = 66
CMD_GET_TIME = 201
CMD_SET_TIME = 202
CMD_VERSION = 1100
CMD_DEVICE = 11
CMD_CLEAR_ADMIN = 20
CMD_SET_USER = 8
LEVEL_USER = 0
LEVEL_ADMIN = 14
def encode_time(t):
"""Encode a timestamp send at the timeclock
copied from zkemsdk.c - EncodeTime"""
d = ( (t.year % 100) * 12 * 31 + ((t.month - 1) * 31) + t.day - 1) *\
(24 * 60 * 60) + (t.hour * 60 + t.minute) * 60 + t.second
return d
def decode_time(t):
"""Decode a timestamp retrieved from the timeclock
copied from zkemsdk.c - DecodeTime"""
second = t % 60
t = t / 60
minute = t % 60
t = t / 60
hour = t % 24
t = t / 24
day = t % 31+1
t = t / 31
month = t % 12+1
t = t / 12
year = t + 2000
d = datetime(int(year), int(month), int(day), int(hour), int(minute), int(second))
return d

82
hr_zk_attendance/models/zkdevice.py

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
from struct import pack, unpack
from .zkconst import *
def zkdevicename(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = '~DeviceName'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False
def zkenabledevice(self):
"""Start a connection with the time clock"""
command = CMD_ENABLEDEVICE
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False
def zkdisabledevice(self):
"""Start a connection with the time clock"""
command = CMD_DISABLEDEVICE
command_string = '\x00\x00'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

56
hr_zk_attendance/models/zkextendfmt.py

@ -0,0 +1,56 @@
def zkextendfmt(self):
try:
test = self.exttrynumber
except:
self.exttrynumber = 1
data_seq=[ self.data_recv.encode("hex")[4:6], self.data_recv.encode("hex")[6:8] ]
#print data_seq
if self.exttrynumber == 1:
plus1 = 0
plus2 = 0
else:
plus1 = -1
plus2 = +1
desc = ": +"+hex( int('99', 16)+plus1 ).lstrip('0x')+", +"+hex(int('b1', 16)+plus2).lstrip("0x")
self.data_seq1 = hex( int( data_seq[0], 16 ) + int( '99', 16 ) + plus1 ).lstrip("0x")
self.data_seq2 = hex( int( data_seq[1], 16 ) + int( 'b1', 16 ) + plus2 ).lstrip("0x")
if len(self.data_seq1) >= 3:
#self.data_seq2 = hex( int( self.data_seq2, 16 ) + int( self.data_seq1[:1], 16) ).lstrip("0x")
self.data_seq1 = self.data_seq1[-2:]
if len(self.data_seq2) >= 3:
#self.data_seq1 = hex( int( self.data_seq1, 16 ) + int( self.data_seq2[:1], 16) ).lstrip("0x")
self.data_seq2 = self.data_seq2[-2:]
if len(self.data_seq1) <= 1:
self.data_seq1 = "0"+self.data_seq1
if len(self.data_seq2) <= 1:
self.data_seq2 = "0"+self.data_seq2
counter = hex( self.counter ).lstrip("0x")
if len(counter):
counter = "0" + counter
#print self.data_seq1+" "+self.data_seq2+desc
data = "0b00"+self.data_seq1+self.data_seq2+self.id_com+counter+"007e457874656e64466d7400"
self.zkclient.sendto(data.decode("hex"), self.address)
#print data
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
except:
if self.exttrynumber == 1:
self.exttrynumber = 2
tmp = zkextendfmt(self)
if len(tmp) < 1:
self.exttrynumber = 1
self.id_com = self.data_recv.encode("hex")[8:12]
self.counter = self.counter+1
#print self.data_recv.encode("hex")
return self.data_recv[8:]

61
hr_zk_attendance/models/zkextendoplog.py

@ -0,0 +1,61 @@
def zkextendoplog(self, index=0):
try:
test = self.extlogtrynumber
except:
self.extlogtrynumber = 1
data_seq = [ self.data_recv.encode("hex")[4:6], self.data_recv.encode("hex")[6:8] ]
if index==0:
self.data_seq1 = hex( int( data_seq[0], 16 ) + int( '104', 16 ) ).lstrip("0x")
self.data_seq2 = hex( int( data_seq[1], 16 ) + int( '19', 16 ) ).lstrip("0x")
desc = ": +104, +19"
header="0b00"
elif index==1:
self.data_seq1 = hex( abs( int( data_seq[0], 16 ) - int( '2c', 16 ) ) ).lstrip("0x")
self.data_seq2 = hex( abs( int( data_seq[1], 16 ) - int( '2', 16 ) ) ).lstrip("0x")
desc = ": -2c, -2"
header="d107"
elif index>=2:
self.data_seq1 = hex( abs( int( data_seq[0], 16 ) - int( '2c', 16 ) ) ).lstrip("0x")
self.data_seq2 = hex( abs( int( data_seq[1], 16 ) - int( '2', 16 ) ) ).lstrip("0x")
desc = ": -2c, -2"
header="ffff"
#print self.data_seq1+" "+self.data_seq2
if len(self.data_seq1) >= 3:
self.data_seq2 = hex( int( self.data_seq2, 16 ) + int( self.data_seq1[:1], 16) ).lstrip("0x")
self.data_seq1 = self.data_seq1[-2:]
if len(self.data_seq2) >= 3:
self.data_seq1 = hex( int( self.data_seq1, 16 ) + int( self.data_seq2[:1], 16) ).lstrip("0x")
self.data_seq2 = self.data_seq2[-2:]
if len(self.data_seq1) <= 1:
self.data_seq1 = "0"+self.data_seq1
if len(self.data_seq2) <= 1:
self.data_seq2 = "0"+self.data_seq2
counter = hex( self.counter ).lstrip("0x")
if len(counter):
counter = "0" + counter
#print self.data_seq1+" "+self.data_seq2+desc
data = header+self.data_seq1+self.data_seq2+self.id_com+counter+"00457874656e644f504c6f6700"
self.zkclient.sendto(data.decode("hex"), self.address)
#print data
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
except:
bingung=1
if self.extlogtrynumber == 1:
self.extlogtrynumber = 2
zkextendoplog(self)
self.id_com = self.data_recv.encode("hex")[8:12]
self.counter = self.counter+1
#print self.data_recv.encode("hex")
return self.data_recv[8:]

44
hr_zk_attendance/models/zkface.py

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
###################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2018-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: cybrosys(<https://www.cybrosys.com>)
#
# This program is free software: you can modify
# it under the terms of the GNU Affero General Public License (AGPL) as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
from struct import pack, unpack
from .zkconst import *
def zkfaceon(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = 'FaceFunOn'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

156
hr_zk_attendance/models/zklib.py

@ -0,0 +1,156 @@
from socket import *
from .zkconnect import *
from .zkversion import *
from .zkos import *
from .zkextendfmt import *
from .zkextendoplog import *
from .zkplatform import *
from .zkworkcode import *
from .zkssr import *
from .zkpin import *
from .zkface import *
from .zkserialnumber import *
from .zkdevice import *
from .zkuser import *
from .zkattendance import *
from .zktime import *
class ZKLib:
def __init__(self, ip, port):
self.address = (ip, port)
self.zkclient = socket(AF_INET, SOCK_DGRAM)
self.zkclient.settimeout(3)
self.session_id = 0
self.userdata = []
self.attendancedata = []
def createChkSum(self, p):
"""This function calculates the chksum of the packet to be sent to the
time clock
Copied from zkemsdk.c"""
l = len(p)
chksum = 0
while l > 1:
chksum += unpack('H', pack('BB', p[0], p[1]))[0]
p = p[2:]
if chksum > USHRT_MAX:
chksum -= USHRT_MAX
l -= 2
if l:
chksum = chksum + p[-1]
while chksum > USHRT_MAX:
chksum -= USHRT_MAX
chksum = ~chksum
while chksum < 0:
chksum += USHRT_MAX
return pack('H', chksum)
def createHeader(self, command, chksum, session_id, reply_id,
command_string):
"""This function puts a the parts that make up a packet together and
packs them into a byte string"""
buf = pack('HHHH', command, chksum, session_id, reply_id) + command_string.encode(encoding='utf_8', errors='strict')
buf = unpack('8B'+'%sB' % len(command_string), buf)
chksum = unpack('H', self.createChkSum(buf))[0]
#print unpack('H', self.createChkSum(buf))
reply_id += 1
if reply_id >= USHRT_MAX:
reply_id -= USHRT_MAX
buf = pack('HHHH', command, chksum, session_id, reply_id)
return buf + command_string.encode(encoding='utf_8', errors='strict')
def checkValid(self, reply):
"""Checks a returned packet to see if it returned CMD_ACK_OK,
indicating success"""
command = unpack('HHHH', reply[:8])[0]
if command == CMD_ACK_OK:
return True
else:
return False
def connect(self):
return zkconnect(self)
def disconnect(self):
return zkdisconnect(self)
def version(self):
return zkversion(self)
def osversion(self):
return zkos(self)
def extendFormat(self):
return zkextendfmt(self)
def extendOPLog(self, index=0):
return zkextendoplog(self, index)
def platform(self):
return zkplatform(self)
def fmVersion(self):
return zkplatformVersion(self)
def workCode(self):
return zkworkcode(self)
def ssr(self):
return zkssr(self)
def pinWidth(self):
return zkpinwidth(self)
def faceFunctionOn(self):
return zkfaceon(self)
def serialNumber(self):
return zkserialnumber(self)
def deviceName(self):
return zkdevicename(self)
def disableDevice(self):
return zkdisabledevice(self)
def enableDevice(self):
return zkenabledevice(self)
def getUser(self):
return zkgetuser(self)
def setUser(self, uid, userid, name, password, role):
return zksetuser(self, uid, userid, name, password, role)
def clearUser(self):
return zkclearuser(self)
def clearAdmin(self):
return zkclearadmin(self)
def getAttendance(self):
return zkgetattendance(self)
def clearAttendance(self):
return zkclearattendance(self)
def setTime(self, t):
return zksettime(self, t)
def getTime(self):
return zkgettime(self)

23
hr_zk_attendance/models/zkos.py

@ -0,0 +1,23 @@
from struct import pack, unpack
from .zkconst import *
def zkos(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = '~OS'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

23
hr_zk_attendance/models/zkpin.py

@ -0,0 +1,23 @@
from struct import pack, unpack
from .zkconst import *
def zkpinwidth(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = '~PIN2Width'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

43
hr_zk_attendance/models/zkplatform.py

@ -0,0 +1,43 @@
from struct import pack, unpack
from .zkconst import *
def zkplatform(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = '~Platform'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False
def zkplatformVersion(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = '~ZKFPVersion'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

23
hr_zk_attendance/models/zkserialnumber.py

@ -0,0 +1,23 @@
from struct import pack, unpack
from .zkconst import *
def zkserialnumber(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = '~SerialNumber'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

23
hr_zk_attendance/models/zkssr.py

@ -0,0 +1,23 @@
from struct import pack, unpack
from .zkconst import *
def zkssr(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = '~SSR'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

50
hr_zk_attendance/models/zktime.py

@ -0,0 +1,50 @@
from struct import pack, unpack
from .zkconst import *
def reverseHex(hexstr):
tmp = ''
for i in reversed(range(len(hexstr)/2)):
tmp += hexstr[i*2:(i*2)+2]
return tmp
def zksettime(self, t):
"""Start a connection with the time clock"""
command = CMD_SET_TIME
command_string = pack('I',encode_time(t))
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False
def zkgettime(self):
"""Start a connection with the time clock"""
command = CMD_GET_TIME
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return decode_time( int( reverseHex( self.data_recv[8:].encode("hex") ), 16 ) )
except:
return False

140
hr_zk_attendance/models/zkuser.py

@ -0,0 +1,140 @@
from struct import pack, unpack
from .zkconst import *
def getSizeUser(self):
"""Checks a returned packet to see if it returned CMD_PREPARE_DATA,
indicating that data packets are to be sent
Returns the amount of bytes that are going to be sent"""
command = unpack('HHHH', self.data_recv[:8])[0]
if command == CMD_PREPARE_DATA:
size = unpack('I', self.data_recv[8:12])[0]
return size
else:
return False
def zksetuser(self, uid, userid, name, password, role):
"""Start a connection with the time clock"""
command = CMD_SET_USER
command_string = pack('sxs8s28ss7sx8s16s', chr( uid ), chr(role), password, name, chr(1), '', userid, '' )
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False
def zkgetuser(self):
"""Start a connection with the time clock"""
command = CMD_USERTEMP_RRQ
command_string = '\x05'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
if getSizeUser(self):
bytes = getSizeUser(self)
while bytes > 0:
data_recv, addr = self.zkclient.recvfrom(1032)
self.userdata.append(data_recv)
bytes -= 1024
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
data_recv = self.zkclient.recvfrom(8)
users = {}
if len(self.userdata) > 0:
# The first 4 bytes don't seem to be related to the user
for x in range(len(self.userdata)):
if x > 0:
self.userdata[x] = self.userdata[x][8:]
userdata = ''.join( self.userdata )
userdata = userdata[11:]
while len(userdata) > 72:
uid, role, password, name, userid = unpack( '2s2s8s28sx31s', userdata.ljust(72)[:72] )
uid = int( uid.encode("hex"), 16)
# Clean up some messy characters from the user name
password = password.split('\x00', 1)[0]
password = unicode(password.strip('\x00|\x01\x10x'), errors='ignore')
#uid = uid.split('\x00', 1)[0]
userid = unicode(userid.strip('\x00|\x01\x10x'), errors='ignore')
name = name.split('\x00', 1)[0]
if name.strip() == "":
name = uid
users[uid] = (userid, name, int( role.encode("hex"), 16 ), password)
#print("%d, %s, %s, %s, %s" % (uid, userid, name, int( role.encode("hex"), 16 ), password))
userdata = userdata[72:]
return users
except:
return False
def zkclearuser(self):
"""Start a connection with the time clock"""
command = CMD_CLEAR_DATA
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False
def zkclearadmin(self):
"""Start a connection with the time clock"""
command = CMD_CLEAR_ADMIN
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

23
hr_zk_attendance/models/zkversion.py

@ -0,0 +1,23 @@
from struct import pack, unpack
from .zkconst import *
def zkversion(self):
"""Start a connection with the time clock"""
command = CMD_VERSION
command_string = ''
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

23
hr_zk_attendance/models/zkworkcode.py

@ -0,0 +1,23 @@
from struct import pack, unpack
from .zkconst import *
def zkworkcode(self):
"""Start a connection with the time clock"""
command = CMD_DEVICE
command_string = 'WorkCode'
chksum = 0
session_id = self.session_id
reply_id = unpack('HHHH', self.data_recv[:8])[3]
buf = self.createHeader(command, chksum, session_id,
reply_id, command_string)
self.zkclient.sendto(buf, self.address)
#print buf.encode("hex")
try:
self.data_recv, addr = self.zkclient.recvfrom(1024)
self.session_id = unpack('HHHH', self.data_recv[:8])[2]
return self.data_recv[8:]
except:
return False

4
hr_zk_attendance/security/ir.model.access.csv

@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_hr_zk_machine_user,zk.machine.hr_biometric_machine,model_zk_machine,hr_attendance.group_hr_attendance_user,1,1,1,1
access_hr_zk_machine_user1,zk.machine.hr_biometric_machine1,model_zk_machine_attendance,hr_attendance.group_hr_attendance_user,1,1,1,1
access_hr_zk_machine_user2,zk.machine.hr_biometric_machine2,model_zk_report_daily_attendance,hr_attendance.group_hr_attendance_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_hr_zk_machine_user zk.machine.hr_biometric_machine model_zk_machine hr_attendance.group_hr_attendance_user 1 1 1 1
3 access_hr_zk_machine_user1 zk.machine.hr_biometric_machine1 model_zk_machine_attendance hr_attendance.group_hr_attendance_user 1 1 1 1
4 access_hr_zk_machine_user2 zk.machine.hr_biometric_machine2 model_zk_report_daily_attendance hr_attendance.group_hr_attendance_user 1 1 1 1

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
hr_zk_attendance/static/description/assets/modules/approval_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
hr_zk_attendance/static/description/assets/modules/budget_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
hr_zk_attendance/static/description/assets/modules/gantt_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
hr_zk_attendance/static/description/assets/modules/library_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
hr_zk_attendance/static/description/assets/modules/pos_order_image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
hr_zk_attendance/static/description/assets/modules/whatsapp_image.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

BIN
hr_zk_attendance/static/description/assets/screenshots/hero.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
hr_zk_attendance/static/description/assets/screenshots/machine-IP.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
hr_zk_attendance/static/description/assets/screenshots/screenshot1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
hr_zk_attendance/static/description/assets/screenshots/screenshot2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

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

Loading…
Cancel
Save