@ -0,0 +1,35 @@ |
|||||
|
Biometric Device Integration v11 |
||||
|
================================ |
||||
|
This Cybrosys's module integrates Odoo attendance with biometric device attendance. |
||||
|
|
||||
|
Features |
||||
|
======== |
||||
|
* Ingrates 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 |
||||
|
Developer: Jesni Banu @ cybrosys, odoo@cybrosys.com |
||||
|
Developer: Mostafa Shokiel , mostafa.shokiel@gmail.com |
||||
|
|
@ -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 |
@ -0,0 +1,45 @@ |
|||||
|
# -*- 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/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
{ |
||||
|
'name': 'Biometric Device Integration', |
||||
|
'version': '11.0.1.0.0', |
||||
|
'summary': """Integrating Biometric Device With HR Attendance (Face + Thumb)""", |
||||
|
'description': 'This module integrates Odoo with the biometric device(Model: ZKteco uFace 202)', |
||||
|
'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.gif'], |
||||
|
'license': 'AGPL-3', |
||||
|
'demo': [], |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
<?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_root" /> |
||||
|
<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> |
@ -0,0 +1,6 @@ |
|||||
|
## Module <hr_zk_attendance> |
||||
|
|
||||
|
#### 24.04.2019 |
||||
|
#### Version 11.0.1.0.0 |
||||
|
##### ADD |
||||
|
- Initial commit |
@ -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 |
||||
|
|
@ -0,0 +1,105 @@ |
|||||
|
# -*- 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.Date(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') |
||||
|
self._cr.execute(""" |
||||
|
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 |
||||
|
) |
||||
|
""") |
||||
|
|
||||
|
|
@ -0,0 +1,280 @@ |
|||||
|
# -*- 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 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__) |
||||
|
|
||||
|
|
||||
|
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) |
||||
|
|
||||
|
@api.multi |
||||
|
def device_connect(self, zk): |
||||
|
command = CMD_CONNECT |
||||
|
command_string = '' |
||||
|
chksum = 0 |
||||
|
session_id = 0 |
||||
|
reply_id = -1 + USHRT_MAX |
||||
|
buf = zk.createHeader(command, chksum, session_id, |
||||
|
reply_id, command_string) |
||||
|
zk.zkclient.sendto(buf, zk.address) |
||||
|
try: |
||||
|
zk.data_recv, addr = zk.zkclient.recvfrom(1024) |
||||
|
zk.session_id = unpack('HHHH', zk.data_recv[:8])[2] |
||||
|
command = unpack('HHHH', zk.data_recv[:8])[0] |
||||
|
if command == 2005: |
||||
|
conn = True |
||||
|
else: |
||||
|
conn = False |
||||
|
except: |
||||
|
conn = False |
||||
|
return conn |
||||
|
|
||||
|
@api.multi |
||||
|
def clear_attendance(self): |
||||
|
for info in self: |
||||
|
try: |
||||
|
machine_ip = info.name |
||||
|
port = info.port_no |
||||
|
zk = zklib.ZKLib(machine_ip, port) |
||||
|
conn = self.device_connect(zk) |
||||
|
if conn: |
||||
|
zk.enableDevice() |
||||
|
clear_data = zk.getAttendance() |
||||
|
if clear_data: |
||||
|
zk.clearAttendance() |
||||
|
self._cr.execute("""delete from zk_machine_attendance""") |
||||
|
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.')) |
||||
|
except: |
||||
|
raise ValidationError('Warning !!! Machine is not connected') |
||||
|
|
||||
|
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] |
||||
|
return size |
||||
|
else: |
||||
|
return False |
||||
|
|
||||
|
def zkgetuser(self, zk): |
||||
|
"""Start a connection with the time clock""" |
||||
|
command = CMD_USERTEMP_RRQ |
||||
|
command_string = '\x05' |
||||
|
chksum = 0 |
||||
|
session_id = zk.session_id |
||||
|
reply_id = unpack('HHHH', zk.data_recv[:8])[3] |
||||
|
|
||||
|
buf = zk.createHeader(command, chksum, session_id, reply_id, command_string) |
||||
|
zk.zkclient.sendto(buf, zk.address) |
||||
|
try: |
||||
|
zk.data_recv, addr = zk.zkclient.recvfrom(1024) |
||||
|
|
||||
|
if self.getSizeUser(zk): |
||||
|
bytes = self.getSizeUser(zk) |
||||
|
|
||||
|
while bytes > 0: |
||||
|
data_recv, addr = zk.zkclient.recvfrom(1032) |
||||
|
zk.userdata.append(data_recv) |
||||
|
bytes -= 1024 |
||||
|
|
||||
|
zk.session_id = unpack('HHHH', zk.data_recv[:8])[2] |
||||
|
data_recv = zk.zkclient.recvfrom(8) |
||||
|
|
||||
|
users = {} |
||||
|
if len(zk.userdata) > 0: |
||||
|
userdata = zk.userdata[0] |
||||
|
userdata = userdata[11:] |
||||
|
while len(userdata) > 72: |
||||
|
uid, role, password, name, userid = unpack('2s2s8s28sx31s', userdata.ljust(72)[:72]) |
||||
|
uid = int(binascii.hexlify(uid), 16) |
||||
|
# Clean up some messy characters from the user name |
||||
|
password = password.split(b'\x00', 1)[0] |
||||
|
password = str(password.strip(b'\x00|\x01\x10x|\x000').decode('utf-8')) |
||||
|
# uid = uid.split('\x00', 1)[0] |
||||
|
userid = str(userid.strip(b'\x00|\x01\x10x|\x000|\x9aC').decode('utf-8')) |
||||
|
name = name.split(b'\x00', 1)[0].decode('utf-8') |
||||
|
if name.strip() == "": |
||||
|
name = uid |
||||
|
users[uid] = (userid, name, int(binascii.hexlify(role), 16), password) |
||||
|
userdata = userdata[72:] |
||||
|
return users |
||||
|
except: |
||||
|
return False |
||||
|
|
||||
|
@api.model |
||||
|
def cron_download(self): |
||||
|
machines = self.env['zk.machine'].search([]) |
||||
|
for machine in machines : |
||||
|
machine.download_attendance() |
||||
|
|
||||
|
@api.multi |
||||
|
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 |
||||
|
port = info.port_no |
||||
|
zk = zklib.ZKLib(machine_ip, port) |
||||
|
conn = self.device_connect(zk) |
||||
|
if conn: |
||||
|
zk.enableDevice() |
||||
|
user = self.zkgetuser(zk) |
||||
|
command = CMD_ATTLOG_RRQ |
||||
|
command_string = '' |
||||
|
chksum = 0 |
||||
|
session_id = zk.session_id |
||||
|
reply_id = unpack('HHHH', zk.data_recv[:8])[3] |
||||
|
buf = zk.createHeader(command, chksum, session_id, |
||||
|
reply_id, command_string) |
||||
|
zk.zkclient.sendto(buf, zk.address) |
||||
|
try: |
||||
|
zk.data_recv, addr = zk.zkclient.recvfrom(1024) |
||||
|
command = unpack('HHHH', zk.data_recv[:8])[0] |
||||
|
if command == CMD_PREPARE_DATA: |
||||
|
size = unpack('I', zk.data_recv[8:12])[0] |
||||
|
zk_size = size |
||||
|
else: |
||||
|
zk_size = False |
||||
|
if zk_size: |
||||
|
bytes = zk_size |
||||
|
while bytes > 0: |
||||
|
data_recv, addr = zk.zkclient.recvfrom(1032) |
||||
|
zk.attendancedata.append(data_recv) |
||||
|
bytes -= 1024 |
||||
|
zk.session_id = unpack('HHHH', zk.data_recv[:8])[2] |
||||
|
data_recv = zk.zkclient.recvfrom(8) |
||||
|
attendance = [] |
||||
|
if len(zk.attendancedata) > 0: |
||||
|
# The first 4 bytes don't seem to be related to the user |
||||
|
for x in xrange(len(zk.attendancedata)): |
||||
|
if x > 0: |
||||
|
zk.attendancedata[x] = zk.attendancedata[x][8:] |
||||
|
attendancedata = b''.join(zk.attendancedata) |
||||
|
attendancedata = attendancedata[14:] |
||||
|
while len(attendancedata) > 0: |
||||
|
uid, state, timestamp, space = unpack('24s1s4s11s', attendancedata.ljust(40)[:40]) |
||||
|
pls = unpack('c', attendancedata[29:30]) |
||||
|
uid = uid.split(b'\x00', 1)[0].decode('utf-8') |
||||
|
tmp = '' |
||||
|
for i in reversed(range(int(len(binascii.hexlify(timestamp)) / 2))): |
||||
|
tmp += binascii.hexlify(timestamp).decode('utf-8')[i * 2:(i * 2) + 2] |
||||
|
attendance.append((uid, int(binascii.hexlify(state), 16), |
||||
|
decode_time(int(tmp, 16)), unpack('HHHH', space[:8])[0])) |
||||
|
|
||||
|
attendancedata = attendancedata[40:] |
||||
|
except Exception as e: |
||||
|
_logger.info("++++++++++++Exception++++++++++++++++++++++", e) |
||||
|
attendance = False |
||||
|
if attendance: |
||||
|
for each in attendance: |
||||
|
atten_time = each[2] |
||||
|
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 user[uid][0] == str(each[0]): |
||||
|
get_user_id = self.env['hr.employee'].search( |
||||
|
[('device_id', '=', str(each[0]))]) |
||||
|
if get_user_id: |
||||
|
duplicate_atten_ids = zk_attendance.search( |
||||
|
[('device_id', '=', str(each[0])), ('punching_time', '=', atten_time)]) |
||||
|
if duplicate_atten_ids: |
||||
|
continue |
||||
|
else: |
||||
|
zk_attendance.create({'employee_id': get_user_id.id, |
||||
|
'device_id': each[0], |
||||
|
'attendance_type': str(each[1]), |
||||
|
'punch_type': str(each[3]), |
||||
|
'punching_time': atten_time, |
||||
|
'address_id': info.address_id.id}) |
||||
|
att_var = att_obj.search([('employee_id', '=', get_user_id.id), |
||||
|
('check_out', '=', False)]) |
||||
|
if each[3] == 0: #check-in |
||||
|
if not att_var: |
||||
|
att_obj.create({'employee_id': get_user_id.id, |
||||
|
'check_in': atten_time}) |
||||
|
if each[3] == 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: |
||||
|
employee = self.env['hr.employee'].create( |
||||
|
{'device_id': str(each[0]), 'name': user[uid][1]}) |
||||
|
zk_attendance.create({'employee_id': employee.id, |
||||
|
'device_id': each[0], |
||||
|
'attendance_type': str(each[1]), |
||||
|
'punch_type': str(each[3]), |
||||
|
'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() |
||||
|
zk.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.')) |
@ -0,0 +1,119 @@ |
|||||
|
# -*- 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( xrange( 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) |
||||
|
#print buf.encode("hex") |
||||
|
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 xrange(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 |
@ -0,0 +1,64 @@ |
|||||
|
# -*- 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 ) |
||||
|
|
@ -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 |
||||
|
|
@ -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 |
@ -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:] |
@ -0,0 +1,62 @@ |
|||||
|
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] ] |
||||
|
#print data_seq |
||||
|
|
||||
|
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:] |
@ -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 |
||||
|
|
@ -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) |
@ -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 |
@ -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 |
||||
|
|
@ -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 |
||||
|
|
@ -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 |
||||
|
|
@ -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 |
||||
|
|
@ -0,0 +1,50 @@ |
|||||
|
from struct import pack, unpack |
||||
|
from .zkconst import * |
||||
|
|
||||
|
|
||||
|
def reverseHex(hexstr): |
||||
|
tmp = '' |
||||
|
for i in reversed( xrange( 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 |
@ -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 xrange(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 |
@ -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 |
||||
|
|
@ -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 |
||||
|
|
|
After Width: | Height: | Size: 537 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 219 KiB |
After Width: | Height: | Size: 176 KiB |
After Width: | Height: | Size: 170 KiB |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 172 KiB |
After Width: | Height: | Size: 230 KiB |
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,408 @@ |
|||||
|
<section class="oe_container" style="background-image:url(https://www.cybrosys.com/images/odoo-index-header-banner.png);background-repeat:no-repeat;background-size:100%;padding: 4% 0% 2% 15%;background-position-y: -107px;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="font-size: 35px;color: #fff;font-weight: 900;text-transform: uppercase;text-align: left;margin: 0;margin-bottom: 16px;"> |
||||
|
HR Biometric Device Integration |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="font-size: 25px;color: #fff;font-weight: 600;text-align: left;opacity: 1;margin: 0 !important;"> |
||||
|
This Module Integrates Biometric Device With HR Attendance |
||||
|
</h3> |
||||
|
<h5 class="oe_slogan" style="text-align: left;background: #fff;width: 293px;padding: 10px;color: #080808 !important;opacity: 1 !important;font-weight: 600;font-size: 20px;"> |
||||
|
<a style="color: #080808 !important;" href="https://www.cybrosys.com" target="_blank">Cybrosys Technologies</a> |
||||
|
</h5> |
||||
|
<a style="color: #080808 !important;" href="https://www.cybrosys.com" target="_blank"> |
||||
|
<div style="width: 215px;margin-left: 57%;text-align: center;background: #ffffff;height: 215px;border-radius: 100%;display: flex;justify-content: center;align-items: center;box-shadow: 0 0 12px 4px #00000059;"> |
||||
|
<img src="https://www.cybrosys.com/images/cybro-logo-oca.png" alt="cybrosys technologies" style="width: 180px;"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 1% 0% 3% 15%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Overview |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
Automation is an implementation factor for a successful ERP. |
||||
|
Using this module, HR attendance can be automated via integrating Thumb / Face detection device with Odoo. One can configure a user both from thumbing device or Odoo employee form. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="background-image:url(https://www.cybrosys.com/images/odoo-index-banner.png); background-repeat:no-repeat; background-size:cover;padding: 10% 0% 25% 15%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Features |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Integrates biometric device(Face+Thumb) with HR attendance. |
||||
|
|
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Option to keep the device attendance log in Odoo. |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Option to clear the device attendance log from both device and Odoo. |
||||
|
|
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Automating HR attendance. |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Option to configure multiple devices. |
||||
|
|
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
This module will support with ZKteco model 'uFace 202', ZKteco model 'iFace990' |
||||
|
</h3> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 3% 0% 0% 15%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Biometric Device Configuration |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Here you can configure your all devices with it's IP address and port number. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="hr_zk_attendance_cybrosys_1.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Download/Clear Device Attendance Log |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
After configuration, you can download your device attendance log into Odoo through |
||||
|
'Download' button.If the device is connected, then the Odoo will download all device |
||||
|
attendance log. |
||||
|
Otherwise, the Odoo will display you a warning message as follow. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="hr_zk_attendance_cybrosys_2.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div><img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
You can also clear all attendance log from both Odoo and device via 'Clear' button. |
||||
|
If the device is not connected it will display you a warning message as follow. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="hr_zk_attendance_cybrosys_3.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Biometric Device Attendance Log |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Here you can see all device attendance log |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="hr_zk_attendance_cybrosys_4.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
HR Attendance |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div><img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Here, Odoo automatically generates HR attendance log while downloading the device attendance. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="hr_zk_attendance_cybrosys_5.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Employee Configuration |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
You can update existing employees with the 'Device Id' which are the id in the biometric device. |
||||
|
If there is no match with the biometric device id then system will automatically create corresponding employee. |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="hr_zk_attendance_cybrosys_6.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Note:- This integration is only applicable for the device ZKteco model 'uFace 202'<br/> |
||||
|
Please install zklib library (sudo pip install zklib) |
||||
|
</h3> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 7px 0% 0% 3%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<a style="color: #080808 !important;" href="https://apps.odoo.com/apps/modules/browse?search=cybrosys" target="_blank"><img src="https://www.cybrosys.com/images/view-more-apps.jpg" alt="cybrosys technologies" style="width: 100%;margin-bottom: 50px;"/></a> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 1% 0% 0% 3%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Our Services |
||||
|
</h2> |
||||
|
<div style="display:flex;padding-top: 20px;justify-content: space-between;"> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-customization-and-installation/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-customization.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-customization-and-installation/" target="_blank"> |
||||
|
Odoo Customization |
||||
|
</a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-implementation/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-erp-implementation.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-implementation/" target="_blank"> |
||||
|
Odoo Implementation </a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-integration/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-erp-integration.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-integration/" target="_blank"> |
||||
|
Odoo Integration |
||||
|
</a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-support/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-erp-support.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-support/" target="_blank"> |
||||
|
Odoo Support</a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/hire-odoo-developer/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/hire-odoo-developer.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/hire-odoo-developer/" target="_blank"> |
||||
|
Hire Odoo Developers</a> |
||||
|
</h3> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 1% 0% 0% 3%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Our Industries |
||||
|
</h2> |
||||
|
<div style="display:flex;justify-content: space-between;flex-wrap:wrap;"> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/best-trading-erp/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-1.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/best-trading-erp/" target="_blank"> |
||||
|
Trading |
||||
|
</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Easily procure and sell your products. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/manufacturing-erp-software/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-2.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/manufacturing-erp-software/" target="_blank"> |
||||
|
Manufacturing</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Plan, track and schedule your operations. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/restaurant-management/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-3.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/restaurant-management/" target="_blank"> |
||||
|
Restaurant</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Run your bar or restaurant methodical. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/pos/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-4.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/pos/" target="_blank"> |
||||
|
POS</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Easy configuring and convivial selling. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/ecommerce-website/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-5.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 0px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/ecommerce-website/" target="_blank"> |
||||
|
E-commerce & Website</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Mobile friendly, awe-inspiring product pages. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/hotel-management-erp/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-6.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/hotel-management-erp/" target="_blank"> |
||||
|
Hotel Management</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
An all-inclusive hotel management application. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/education-erp-software/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-7.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/education-erp-software/" target="_blank"> |
||||
|
Education</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
A Collaborative platform for educational management. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/service-management/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-8.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/service-management/" target="_blank"> |
||||
|
Service Management</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Keep track of services and invoice accordingly. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="background-image:url(https://www.cybrosys.com/images/odoo-index-footer-bg.png); background-repeat:no-repeat; background-size:100%;padding: 13% 0% 6% 0%;"> |
||||
|
<div class="oe_slogan" style="margin-top:10px !important;margin-bottom: 0px;"> |
||||
|
<div> |
||||
|
<a style="color: #5c5c5c !important;border-radius: 0;background: none;border: none;background: #fff;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62, 57, 107, 0.05);border-radius: 30px;font-size: 12px;padding: 9px 26px;margin-right: 9px;width: 200px;text-transform: capitalize;" class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" href="mailto:odoo@cybrosys.com"><i class="fa fa-envelope"></i> Email us </a> |
||||
|
<a style="color: #5c5c5c !important;border-radius: 0;background: none;border: none;background: #fff;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62, 57, 107, 0.05);border-radius: 30px;font-size: 12px;padding: 9px 26px;margin-right: 9px;width: 200px;text-transform: capitalize;" class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com/contact/"><i class="fa fa-phone"></i> Contact Us </a> |
||||
|
<a style="color: #5c5c5c !important;border-radius: 0;background: none;border: none;background: #fff;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62, 57, 107, 0.05);border-radius: 30px;font-size: 12px;padding: 9px 26px;margin-right: 9px;width: 200px;text-transform: capitalize;" class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com/contact/"><i class="fa fa-check-square"></i> Request Customization </a> |
||||
|
</div> |
||||
|
<br> |
||||
|
<img src="https://www.cybrosys.com/images/logo.png" style="width: 190px; margin-bottom: 25px;margin-top: 30px;" class="center-block"> |
||||
|
<div> |
||||
|
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px; ;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
@ -0,0 +1,71 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Customize Attendance Report --> |
||||
|
<record id="inherited_view_attendance_tree" model="ir.ui.view"> |
||||
|
<field name="name">inherited_hr.attendance.tree</field> |
||||
|
<field name="model">hr.attendance</field> |
||||
|
<field name="inherit_id" ref="hr_attendance.view_attendance_tree"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Employee attendances"> |
||||
|
<field name="worked_hours" type="measure"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="inherited_hr_attendance_view_filter" model="ir.ui.view"> |
||||
|
<field name="name">inherited_hr_attendance_view_filter</field> |
||||
|
<field name="model">hr.attendance</field> |
||||
|
<field name="inherit_id" ref="hr_attendance.hr_attendance_view_filter"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Hr Attendance Search"> |
||||
|
<group expand="0" string="Group By"> |
||||
|
<separator/> |
||||
|
<filter name="date" string="Date" context="{'group_by':'check_in:day'}"/> |
||||
|
|
||||
|
</group> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_zk_report_daily_attendance_search" model="ir.ui.view"> |
||||
|
<field name="name">zk.report.daily.attendance.search</field> |
||||
|
<field name="model">zk.report.daily.attendance</field> |
||||
|
<field name="arch" type="xml" > |
||||
|
<search string="Hr Attendance Search"> |
||||
|
<filter icon="terp-stock_align_left_24" string="My Attendance" name="my_attendance" domain="[('name.user_id.id', '=', uid)]" /> |
||||
|
<filter name="today" string="Today" domain="[('punching_time', '>=', datetime.datetime.now().replace(hour=0, minute=0, second=0)),('punching_time', '<=', datetime.datetime.now().replace(hour=23, minute=59, second=59))]" /> |
||||
|
<filter string="Current Month" domain="[('punching_time', '>=', datetime.datetime.now().strftime('%Y-%m-01'))]" /> |
||||
|
<separator/> |
||||
|
|
||||
|
<field name="name"/> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_zk_report_daily_attendance_tree" model="ir.ui.view"> |
||||
|
<field name="name">zk.report.daily.attendance.tree</field> |
||||
|
<field name="model">zk.report.daily.attendance</field> |
||||
|
<field name="arch" type="xml" > |
||||
|
<tree string="Attendance" create="false" delete="false" colors="green:punch_type in ('0');red:punch_type in ('1');"> |
||||
|
<field name="punching_day"/> |
||||
|
<field name="name"/> |
||||
|
<field name="punch_type"/> |
||||
|
<field name="attendance_type"/> |
||||
|
<field name="punching_time"/> |
||||
|
<field name="address_id"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_zk_report_daily_attendance" model="ir.actions.act_window"> |
||||
|
<field name="name">Attendance Analysis</field> |
||||
|
<field name="res_model">zk.report.daily.attendance</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree</field> |
||||
|
<field name="context">{'search_default_my_attendance':1}</field> |
||||
|
<field name="search_view_id" ref="view_zk_report_daily_attendance_search" /> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="menu_zk_attendance_view" name="Attendance log" action="action_zk_report_daily_attendance" parent="zk_machine_menu" |
||||
|
sequence="2" groups="hr_attendance.group_hr_attendance_user"/> |
||||
|
</odoo> |
@ -0,0 +1,69 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<record id="view_zk_machine_form" model="ir.ui.view"> |
||||
|
<field name="name">zk.machine.form</field> |
||||
|
<field name="model">zk.machine</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Biometric Device"> |
||||
|
<header> |
||||
|
<button name="clear_attendance" type="object" string="Clear Data" class="oe_highlight" |
||||
|
icon="fa-remove " confirm="Are you sure you want to do this?"/> |
||||
|
<button name="download_attendance" type="object" string="Download Data" class="oe_highlight" |
||||
|
icon="fa-download " confirm="Are you sure you want to do this?" /> |
||||
|
</header> |
||||
|
<sheet> |
||||
|
<div class="oe_title"> |
||||
|
<label for="name" /> |
||||
|
<h1> |
||||
|
<field name="name" placeholder="Machine IP"/> |
||||
|
</h1> |
||||
|
</div> |
||||
|
<group> |
||||
|
<group> |
||||
|
<field name="port_no"/> |
||||
|
<field name="address_id"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="company_id" groups="base.group_multi_company"/> |
||||
|
</group> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_zk_machine_tree" model="ir.ui.view"> |
||||
|
<field name="name">zk.machine.tree</field> |
||||
|
<field name="model">zk.machine</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Biometric Machine"> |
||||
|
<field name="name"/> |
||||
|
<field name="port_no"/> |
||||
|
<field name="address_id"/> |
||||
|
<field name="company_id" groups="base.group_multi_company"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="zk_machine_action" model="ir.actions.act_window"> |
||||
|
<field name="name">Attendances</field> |
||||
|
<field name="res_model">zk.machine</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="hr_employee_inherit_form_view" model="ir.ui.view"> |
||||
|
<field name="name">hr.employee.form</field> |
||||
|
<field name="model">hr.employee</field> |
||||
|
<field name="inherit_id" ref="hr.view_employee_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<field name="user_id" position="after"> |
||||
|
<field name="device_id"/> |
||||
|
</field> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="zk_machine_menu" parent="hr_attendance.menu_hr_attendance_root" sequence="50" name="Biometric Manager" /> |
||||
|
<menuitem id="zk_machine_sub_menu" parent="zk_machine_menu" name="Device Configuration" action="zk_machine_action" sequence="1"/> |
||||
|
</odoo> |
||||
|
|
@ -0,0 +1,32 @@ |
|||||
|
Product Return In POS |
||||
|
===================== |
||||
|
POS Order Return. |
||||
|
|
||||
|
Installation |
||||
|
============ |
||||
|
- www.odoo.com/documentation/11.0/setup/install.html |
||||
|
- Install our custom addon |
||||
|
|
||||
|
License |
||||
|
======= |
||||
|
GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 (AGPLv3) |
||||
|
(http://www.gnu.org/licenses/agpl.html) |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
* Cybrosys Techno Solutions <https://www.cybrosys.com> |
||||
|
|
||||
|
|
||||
|
Developer: Anusha P P - odoo@cybrosys.com |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit https://www.cybrosys.com. |
||||
|
|
@ -0,0 +1 @@ |
|||||
|
from . import models |
@ -0,0 +1,41 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# Copyright (C) 2017-TODAY Cybrosys Technologies(<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 <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
{ |
||||
|
'name': 'Product Return In POS', |
||||
|
'version': '11.0.0.1.0', |
||||
|
'category': 'Point of Sale', |
||||
|
'summary': 'POS Order Return', |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'images': ['static/description/banner.jpg'], |
||||
|
'website': 'https://www.cybrosys.com', |
||||
|
'depends': ['point_of_sale'], |
||||
|
'data': [ |
||||
|
'views/return.xml', |
||||
|
'views/pos_template.xml', |
||||
|
], |
||||
|
'qweb': ['static/src/xml/*.xml'], |
||||
|
'license': 'AGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
|
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
## Module <product_return_pos> |
||||
|
|
||||
|
#### 24.04.2019 |
||||
|
#### Version 11.0.1.0.0 |
||||
|
##### ADD |
||||
|
- Initial commit for Product Return In POS |
@ -0,0 +1,3 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import pos_return |
@ -0,0 +1,66 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from odoo import models, api, fields |
||||
|
|
||||
|
|
||||
|
class PosOrderReturn(models.Model): |
||||
|
_inherit = 'pos.order' |
||||
|
|
||||
|
return_ref = fields.Char(string='Return Ref', readonly=True, copy=False) |
||||
|
return_status = fields.Selection([ |
||||
|
('nothing_return', 'Nothing Returned'), |
||||
|
('partialy_return', 'Partialy Returned'), |
||||
|
('fully_return', 'Fully Returned') |
||||
|
], string="Return Status", default='nothing_return', |
||||
|
readonly=True, copy=False, help="Return status of Order") |
||||
|
|
||||
|
@api.model |
||||
|
def get_lines(self, ref): |
||||
|
result = [] |
||||
|
order_id = self.search([('pos_reference', '=', ref)], limit=1) |
||||
|
if order_id: |
||||
|
lines = self.env['pos.order.line'].search([('order_id', '=', order_id.id)]) |
||||
|
for line in lines: |
||||
|
if line.qty - line.returned_qty > 0: |
||||
|
new_vals = { |
||||
|
'product_id': line.product_id.id, |
||||
|
'product': line.product_id.name, |
||||
|
'qty': line.qty - line.returned_qty, |
||||
|
'price_unit': line.price_unit, |
||||
|
'discount': line.discount, |
||||
|
'line_id': line.id, |
||||
|
} |
||||
|
result.append(new_vals) |
||||
|
|
||||
|
return [result] |
||||
|
|
||||
|
def _order_fields(self, ui_order): |
||||
|
order = super(PosOrderReturn, self)._order_fields(ui_order) |
||||
|
if 'return_ref' in ui_order.keys() and ui_order['return_ref']: |
||||
|
order['return_ref'] = ui_order['return_ref'] |
||||
|
parent_order = self.search([('pos_reference', '=', ui_order['return_ref'])], limit=1) |
||||
|
|
||||
|
updated_lines = ui_order['lines'] |
||||
|
ret = 0 |
||||
|
qty = 0 |
||||
|
for uptd in updated_lines: |
||||
|
line = self.env['pos.order.line'].search([('order_id', '=', parent_order.id), |
||||
|
('id', '=', uptd[2]['line_id'])], limit=1) |
||||
|
if line: |
||||
|
line.returned_qty += -(uptd[2]['qty']) |
||||
|
for line in parent_order.lines: |
||||
|
qty += line.qty |
||||
|
ret += line.returned_qty |
||||
|
if qty-ret == 0: |
||||
|
if parent_order: |
||||
|
parent_order.return_status = 'fully_return' |
||||
|
elif ret: |
||||
|
if qty > ret: |
||||
|
if parent_order: |
||||
|
parent_order.return_status = 'partialy_return' |
||||
|
return order |
||||
|
|
||||
|
|
||||
|
class PosOrderLineReturn(models.Model): |
||||
|
_inherit = 'pos.order.line' |
||||
|
|
||||
|
returned_qty = fields.Integer(string='Returned Qty', digits=0, readonly=True) |
After Width: | Height: | Size: 110 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 37 KiB |
@ -0,0 +1,361 @@ |
|||||
|
<section class="oe_container" style="background-image:url(https://www.cybrosys.com/images/odoo-index-header-banner.png);background-repeat:no-repeat;background-size:100%;padding: 4% 0% 2% 15%;background-position-y: -107px;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="font-size: 35px;color: #fff;font-weight: 900;text-transform: uppercase;text-align: left;margin: 0;margin-bottom: 16px;"> |
||||
|
Product Return In POS |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="font-size: 25px;color: #fff;font-weight: 600;text-align: left;opacity: 1;margin: 0 !important;"> |
||||
|
Manages Product Return From POS Frontend |
||||
|
</h3> |
||||
|
<h5 class="oe_slogan" style="text-align: left;background: #fff;width: 293px;padding: 10px;color: #080808 !important;opacity: 1 !important;font-weight: 600;font-size: 20px;"> |
||||
|
<a style="color: #080808 !important;" href="https://www.cybrosys.com" target="_blank">Cybrosys Technologies</a> |
||||
|
</h5> |
||||
|
<a style="color: #080808 !important;" href="https://www.cybrosys.com" target="_blank"> |
||||
|
<div style="width: 215px;margin-left: 57%;text-align: center;background: #ffffff;height: 215px;border-radius: 100%;display: flex;justify-content: center;align-items: center;box-shadow: 0 0 12px 4px #00000059;"> |
||||
|
<img src="https://www.cybrosys.com/images/cybro-logo-oca.png" alt="cybrosys technologies" style="width: 180px;"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 1% 0% 3% 15%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Overview |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
This app will help you to return the products from POS user interface. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="background-image:url(https://www.cybrosys.com/images/odoo-index-banner.png); background-repeat:no-repeat; background-size:cover;padding: 10% 0% 25% 15%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Features |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Manage Product Return through POS interface. |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style="text-align: left;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 18px;"> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Track Return Reference and Status |
||||
|
</h3> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 3% 0% 0% 15%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Screenshots |
||||
|
</h2> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Create a normal order. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="pos_return_cybrosys_1.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Click on Return Button In order to return products. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="pos_return_cybrosys_2.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div><img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Select the order and click on Return. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="pos_return_cybrosys_3.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div> |
||||
|
<img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
Return some of the products. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="pos_return_cybrosys_4.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="text-align: left;padding: 5% 0% 0% 0%;font-size: 16px;width: 90%;margin: 0;margin-top: 14px;color: #000 !important;opacity: 1 !important;line-height: 24px;"> |
||||
|
<div><img src="https://www.cybrosys.com/images/ico-tick.png"> |
||||
|
We get the return reference and status of the return from backend also. |
||||
|
</div> |
||||
|
</h3> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<img src="pos_return_cybrosys_5.png" alt="" style="width: 95%;"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 7px 0% 0% 3%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<a style="color: #080808 !important;" href="https://apps.odoo.com/apps/modules/browse?search=cybrosys" target="_blank"><img src="https://www.cybrosys.com/images/view-more-apps.jpg" alt="cybrosys technologies" style="width: 100%;margin-bottom: 50px;"/></a> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 1% 0% 0% 3%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Our Services |
||||
|
</h2> |
||||
|
<div style="display:flex;padding-top: 20px;justify-content: space-between;"> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-customization-and-installation/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-customization.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-customization-and-installation/" target="_blank"> |
||||
|
Odoo Customization |
||||
|
</a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-implementation/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-erp-implementation.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-implementation/" target="_blank"> |
||||
|
Odoo Implementation </a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-integration/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-erp-integration.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-integration/" target="_blank"> |
||||
|
Odoo Integration |
||||
|
</a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-support/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-erp-support.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo-erp-support/" target="_blank"> |
||||
|
Odoo Support</a> |
||||
|
</h3> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 18%;"> |
||||
|
|
||||
|
<div style="width:75px;height:75px;background:#fff; border-radius:100%;margin: auto;"> |
||||
|
<a href="https://www.cybrosys.com/hire-odoo-developer/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/hire-odoo-developer.png" style="width: 100%;border-radius: 100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
<h3 class="oe_slogan" style="font-weight: 800;text-align: center;font-size: 14px;width: 100%;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;"> |
||||
|
<a href="https://www.cybrosys.com/hire-odoo-developer/" target="_blank"> |
||||
|
Hire Odoo Developers</a> |
||||
|
</h3> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="padding: 1% 0% 0% 3%;"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<h2 class="oe_slogan" style="text-align: left;font-size: 28px;font-weight: 600;margin: 0px !important;"> |
||||
|
Our Industries |
||||
|
</h2> |
||||
|
<div style="display:flex;justify-content: space-between;flex-wrap:wrap;"> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/best-trading-erp/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-1.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/best-trading-erp/" target="_blank"> |
||||
|
Trading |
||||
|
</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Easily procure and sell your products. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/manufacturing-erp-software/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-2.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/manufacturing-erp-software/" target="_blank"> |
||||
|
Manufacturing</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Plan, track and schedule your operations. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/restaurant-management/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-3.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/restaurant-management/" target="_blank"> |
||||
|
Restaurant</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Run your bar or restaurant methodical. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/pos/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-4.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/pos/" target="_blank"> |
||||
|
POS</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Easy configuring and convivial selling. |
||||
|
</h3> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/ecommerce-website/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-5.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 0px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/ecommerce-website/" target="_blank"> |
||||
|
E-commerce & Website</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Mobile friendly, awe-inspiring product pages. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/hotel-management-erp/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-6.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/hotel-management-erp/" target="_blank"> |
||||
|
Hotel Management</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
An all-inclusive hotel management application. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/education-erp-software/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-7.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/education-erp-software/" target="_blank"> |
||||
|
Education</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
A Collaborative platform for educational management. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="flex-basis: 32%;padding-top: 20px;"> |
||||
|
|
||||
|
<div style="width:30%; float:left;"> |
||||
|
<div style="width:75px;height:75px;background:#CE2D48; border-radius:100%;float: left;text-align: left;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/service-management/" target="_blank"> |
||||
|
<img src="https://www.cybrosys.com/images/odoo-index-industry-8.png" alt="Odoo Industry" style=" border-radius: 100%;width:100%;"/> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="width:70%;float:left;"> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 14px;font-weight:800;width: auto;margin: 0;margin-top: 14px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 4px;margin-left: 16px;"> |
||||
|
<a href="https://www.cybrosys.com/odoo/industries/service-management/" target="_blank"> |
||||
|
Service Management</a> |
||||
|
</h3> |
||||
|
<h3 class="oe_slogan" style=" text-align: left;font-size: 13px;width: auto;margin: 0;margin-top:5px;color: #000 !important;margin-top: 5px;opacity: 1 !important;line-height: 17px;float: left;margin-top: 5px;margin-left: 16px;"> |
||||
|
Keep track of services and invoice accordingly. |
||||
|
</h3> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section class="oe_container" style="background-image:url(https://www.cybrosys.com/images/odoo-index-footer-bg.png); background-repeat:no-repeat; background-size:100%;padding: 13% 0% 6% 0%;"> |
||||
|
<div class="oe_slogan" style="margin-top:10px !important;margin-bottom: 0px;"> |
||||
|
<div> |
||||
|
<a style="color: #5c5c5c !important;border-radius: 0;background: none;border: none;background: #fff;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62, 57, 107, 0.05);border-radius: 30px;font-size: 12px;padding: 9px 26px;margin-right: 9px;width: 200px;text-transform: capitalize;" class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" href="mailto:odoo@cybrosys.com"><i class="fa fa-envelope"></i> Email us </a> |
||||
|
<a style="color: #5c5c5c !important;border-radius: 0;background: none;border: none;background: #fff;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62, 57, 107, 0.05);border-radius: 30px;font-size: 12px;padding: 9px 26px;margin-right: 9px;width: 200px;text-transform: capitalize;" class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com/contact/"><i class="fa fa-phone"></i> Contact Us </a> |
||||
|
<a style="color: #5c5c5c !important;border-radius: 0;background: none;border: none;background: #fff;box-shadow: 0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62, 57, 107, 0.05);border-radius: 30px;font-size: 12px;padding: 9px 26px;margin-right: 9px;width: 200px;text-transform: capitalize;" class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com/contact/"><i class="fa fa-check-square"></i> Request Customization </a> |
||||
|
</div> |
||||
|
<br> |
||||
|
<img src="https://www.cybrosys.com/images/logo.png" style="width: 190px; margin-bottom: 25px;margin-top: 30px;" class="center-block"> |
||||
|
<div> |
||||
|
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px; ;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;height: 35px;padding-top: 7px;font-size: 21px;margin-right: 6px;border-radius: 100%;"></i></a></td> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
|
||||
|
|
After Width: | Height: | Size: 372 KiB |
After Width: | Height: | Size: 252 KiB |
After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 88 KiB |
@ -0,0 +1,50 @@ |
|||||
|
.return-screen .return-button { |
||||
|
color: #f0f0f0; |
||||
|
display: inline-block; |
||||
|
box-sizing: border-box; |
||||
|
-moz-box-sizing: border-box; |
||||
|
/* height: 20px; */ |
||||
|
padding: 4px 8px; |
||||
|
margin: 3px; |
||||
|
margin-bottom: 0px; |
||||
|
margin-right: 2px; |
||||
|
padding-top: 0px; |
||||
|
background: #8b8b8b; |
||||
|
border-top-left-radius: 3px; |
||||
|
border-top-right-radius: 3px; |
||||
|
vertical-align: top; |
||||
|
line-height: 20px; |
||||
|
text-align: center; |
||||
|
box-shadow: 0px -5px 10px -6px rgb(82,82,82) inset; |
||||
|
cursor: pointer; |
||||
|
min-width: 45px; |
||||
|
} |
||||
|
.return-screen .order-list tr.highlight{ |
||||
|
transition: all 150ms linear; |
||||
|
background: rgb(110,200,155) !important; |
||||
|
color: white; |
||||
|
} |
||||
|
.return-screen .order-list td tr.lowlight{ |
||||
|
transition: all 150ms linear; |
||||
|
background: rgb(216, 238, 227); |
||||
|
} |
||||
|
.return-screen .order-list tr.lowlight:nth-child(even){ |
||||
|
transition: all 150ms linear; |
||||
|
background: rgb(227, 246, 237); |
||||
|
} |
||||
|
|
||||
|
.return-screen .searchbox{ |
||||
|
right: auto; |
||||
|
margin-left: 90px; |
||||
|
margin-top:8px; |
||||
|
left: 50%; |
||||
|
} |
||||
|
.reprint_order_screen .searchbox input{ |
||||
|
width: 120px; |
||||
|
} |
||||
|
|
||||
|
.return-screen .order-list{ |
||||
|
font-size: 15px; |
||||
|
width: 100%; |
||||
|
line-height: 40px; |
||||
|
} |
@ -0,0 +1,417 @@ |
|||||
|
odoo.define('product_return_pos.return',function(require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var models = require('point_of_sale.models'); |
||||
|
var screens = require('point_of_sale.screens'); |
||||
|
var ScreenWidget = screens.ScreenWidget; |
||||
|
var gui = require('point_of_sale.gui'); |
||||
|
var core = require('web.core'); |
||||
|
var QWeb = core.qweb; |
||||
|
var PopupWidget = require('point_of_sale.popups'); |
||||
|
var rpc = require('web.rpc'); |
||||
|
var _t = require('web.core')._t; |
||||
|
var session = require('web.session'); |
||||
|
models.load_models({ |
||||
|
model: 'pos.order', |
||||
|
fields: ['name', 'partner_id','date_order','amount_total', 'amount_tax', |
||||
|
'pos_reference','lines','state','session_id','company_id','return_ref','return_status'], |
||||
|
loaded: function(self, orders){ |
||||
|
self.orders = orders; |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
model: 'pos.order.line', |
||||
|
fields: ['product_id','qty','price_unit','price_subtotal_incl','order_id','discount','returned_qty'], |
||||
|
loaded: function(self,order_lines){ |
||||
|
self.order_line = []; |
||||
|
for (var i = 0; i < order_lines.length; i++) { |
||||
|
self.order_line[i] = order_lines[i]; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
var ReturnWidget = PopupWidget.extend({ |
||||
|
template:'ReturnWidget', |
||||
|
|
||||
|
init: function(parent, options){ |
||||
|
this._super(parent, options); |
||||
|
this.options = {}; |
||||
|
this.pos_reference = ""; |
||||
|
|
||||
|
}, |
||||
|
show: function(options){ |
||||
|
this._super(options); |
||||
|
this.render_list(options); |
||||
|
|
||||
|
}, |
||||
|
events: { |
||||
|
'click .button.cancel': 'click_cancel', |
||||
|
'click .button.confirm': 'click_confirm', |
||||
|
}, |
||||
|
render_list:function(options){ |
||||
|
$("#table-body").empty(); |
||||
|
var lines = []; |
||||
|
this.pos_reference = options.ref |
||||
|
rpc.query({ |
||||
|
model: 'pos.order', |
||||
|
method: 'get_lines', |
||||
|
args: [options.ref], |
||||
|
}).then(function (result) { |
||||
|
lines = result[0]; |
||||
|
for(var j=0;j < lines.length; j++){ |
||||
|
var product_line = lines[j]; |
||||
|
var rows = ""; |
||||
|
var id = product_line.product_id |
||||
|
var price_unit = product_line.price_unit; |
||||
|
var name =product_line.product; |
||||
|
var qty = product_line.qty; |
||||
|
var line_id = product_line.line_id; |
||||
|
var discount = product_line.discount; |
||||
|
rows += "<tr><td>" + id + "</td><td>" + price_unit +" </td><td>" + name + "</td><td>" + qty + "</td><td>" + discount + "</td><td>" + line_id + "</td></tr>"; |
||||
|
$(rows).appendTo("#list tbody"); |
||||
|
var rows = document.getElementById('list').rows; |
||||
|
for (var row = 0; row < rows.length; row++) { |
||||
|
var cols = rows[row].cells; |
||||
|
cols[0].style.display = 'none'; |
||||
|
cols[1].style.display = 'none'; |
||||
|
cols[5].style.display = 'none'; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
var table = document.getElementById('list'); |
||||
|
var tr = table.getElementsByTagName("tr"); |
||||
|
for (var i = 1; i < tr.length; i++) { |
||||
|
var td = document.createElement('td'); |
||||
|
var input = document.createElement('input'); |
||||
|
input.setAttribute("type", "text"); |
||||
|
input.setAttribute("value", 0); |
||||
|
input.setAttribute("id", "text"+i); |
||||
|
td.appendChild(input); |
||||
|
tr[i].appendChild(td); |
||||
|
|
||||
|
} |
||||
|
}).fail(function () { |
||||
|
alert("NO DATA") |
||||
|
}); |
||||
|
}, |
||||
|
click_confirm: function(){ |
||||
|
|
||||
|
var self = this; |
||||
|
var myTable = document.getElementById('list').tBodies[0]; |
||||
|
var count = 0; |
||||
|
var c = 1; |
||||
|
|
||||
|
for (r=0, n = myTable.rows.length; r < n; r++) { |
||||
|
var row = myTable.rows[r] |
||||
|
var return_qty = document.getElementById("text"+c).value |
||||
|
if (row.cells[3].innerHTML < return_qty){ |
||||
|
count +=1 |
||||
|
} |
||||
|
c = c+1 |
||||
|
} |
||||
|
if (count > 0){ |
||||
|
alert('Please check the Returned Quantity,it is higher than purchased') |
||||
|
} |
||||
|
else{ |
||||
|
c = 1; |
||||
|
// OrderSuper.prototype.set_client.call(this, this.client);
|
||||
|
for (var r=0, n = myTable.rows.length; r < n; r++) { |
||||
|
row = myTable.rows[r] |
||||
|
return_qty = document.getElementById("text"+c).value; |
||||
|
var product = this.pos.db.get_product_by_id(row.cells[0].innerHTML); |
||||
|
if (!product) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (return_qty > 0){ |
||||
|
this.pos.get_order().add_product(product, { |
||||
|
price: row.cells[1].innerHTML, |
||||
|
quantity: -(return_qty), |
||||
|
discount:row.cells[4].innerHTML, |
||||
|
merge: false, |
||||
|
extras: {return_ref: this.pos_reference, |
||||
|
label:row.cells[5].innerHTML}, |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
c = c+1 |
||||
|
|
||||
|
} |
||||
|
|
||||
|
if (this.options.client){ |
||||
|
this.pos.get_order().set_client(self.pos.db.get_partner_by_id(this.options.client)); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
this.gui.close_popup(); |
||||
|
self.gui.show_screen('products'); |
||||
|
|
||||
|
}, |
||||
|
click_cancel: function(){ |
||||
|
this.gui.close_popup(); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
gui.define_popup({name:'ReturnWidget', widget: ReturnWidget}); |
||||
|
|
||||
|
var OrderListScreenWidget = ScreenWidget.extend({ |
||||
|
template:'OrderListScreenWidget', |
||||
|
init: function(parent, options){ |
||||
|
this._super(parent, options); |
||||
|
}, |
||||
|
show: function(){ |
||||
|
var self = this; |
||||
|
this._super(); |
||||
|
this.renderElement(); |
||||
|
this.$('.back').click(function(){ |
||||
|
self.gui.back(); |
||||
|
}); |
||||
|
var orders = this.pos.orders; |
||||
|
this.render_list(orders); |
||||
|
var search_timeout = null; |
||||
|
this.$('.searchbox input').on('keypress',function(event){ |
||||
|
clearTimeout(search_timeout); |
||||
|
|
||||
|
var searchbox = this; |
||||
|
|
||||
|
search_timeout = setTimeout(function(){ |
||||
|
self.perform_search(searchbox.value, event.which === 13); |
||||
|
},70); |
||||
|
}); |
||||
|
|
||||
|
this.$('.searchbox .search-clear').click(function(){ |
||||
|
self.clear_search(); |
||||
|
}); |
||||
|
this.$('.return_order').click(function(e){ |
||||
|
var order = $(e.target).closest("tr").data('id'); |
||||
|
self.return_order(order); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
hide: function () { |
||||
|
this._super(); |
||||
|
}, |
||||
|
get_orders: function(){ |
||||
|
return this.gui.get_current_screen_param('orders'); |
||||
|
}, |
||||
|
perform_search: function(query, associate_result){ |
||||
|
var orders; |
||||
|
if(query){ |
||||
|
orders = this.search_order(query); |
||||
|
this.render_list(orders); |
||||
|
}else{ |
||||
|
orders = this.pos.orders; |
||||
|
this.render_list(orders); |
||||
|
} |
||||
|
}, |
||||
|
search_order: function(query){ |
||||
|
try { |
||||
|
var re = RegExp(query, 'i'); |
||||
|
}catch(e){ |
||||
|
return []; |
||||
|
} |
||||
|
var results = []; |
||||
|
for (var order_id in this.pos.orders){ |
||||
|
var r = re.exec(this.pos.orders[order_id]['name']+ '|'+ this.pos.orders[order_id]['partner_id'][1]); |
||||
|
if(r){ |
||||
|
results.push(this.pos.orders[order_id]); |
||||
|
} |
||||
|
} |
||||
|
return results; |
||||
|
}, |
||||
|
clear_search: function(){ |
||||
|
var orders = this.pos.orders; |
||||
|
this.render_list(orders); |
||||
|
this.$('.searchbox input')[0].value = ''; |
||||
|
this.$('.searchbox input').focus(); |
||||
|
}, |
||||
|
render_list: function(orders){ |
||||
|
var contents = this.$el[0].querySelector('.order-list-contents'); |
||||
|
contents.innerHTML = ""; |
||||
|
for(var i = 0, len = Math.min(orders.length,1000); i < len; i++){ |
||||
|
var order = orders[i]; |
||||
|
var orderline_html = QWeb.render('OrderLine',{widget: this, order:order}); |
||||
|
var orderline = document.createElement('tbody'); |
||||
|
orderline.innerHTML = orderline_html; |
||||
|
orderline = orderline.childNodes[1]; |
||||
|
contents.appendChild(orderline); |
||||
|
} |
||||
|
}, |
||||
|
return_order:function(order_id){ |
||||
|
var self = this; |
||||
|
var order = this.get_order_by_id(order_id); |
||||
|
var client = '' |
||||
|
if (order.partner_id){ |
||||
|
client = order.partner_id[0]; |
||||
|
} |
||||
|
if (order && order.return_status ==='fully_return'){ |
||||
|
self.gui.show_popup('error',_t('This is a fully returned order')); |
||||
|
} |
||||
|
else if (order && order.return_ref) { |
||||
|
self.gui.show_popup('error',_t('This is a returned order')); |
||||
|
} |
||||
|
else{ |
||||
|
console.log(order.pos_reference,client) |
||||
|
self.gui.show_popup('ReturnWidget',{ref: order.pos_reference,client:client}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}, |
||||
|
get_order_by_id: function(id){ |
||||
|
var orders = this.pos.orders; |
||||
|
for (var i in orders){ |
||||
|
if (orders[i].id === id){ |
||||
|
return orders[i]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
gui.define_screen({name:'orderlist', widget: OrderListScreenWidget}); |
||||
|
var ReturnButton = screens.ActionButtonWidget.extend({ |
||||
|
template: 'ReturnButton', |
||||
|
button_click: function(){ |
||||
|
var orders = this.pos.orders; |
||||
|
this.gui.show_screen('orderlist',{orders:orders}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
screens.define_action_button({ |
||||
|
'name': 'return', |
||||
|
'widget': ReturnButton |
||||
|
}); |
||||
|
var _super_orderline = models.Orderline; |
||||
|
models.Orderline = models.Orderline.extend({ |
||||
|
|
||||
|
set_line_id: function(line_id){ |
||||
|
this.line_id = line_id; |
||||
|
}, |
||||
|
export_as_JSON: function(){ |
||||
|
var json = _super_orderline.prototype.export_as_JSON.apply(this,arguments); |
||||
|
json.line_id = this.line_id; |
||||
|
return json; |
||||
|
}, |
||||
|
init_from_JSON: function(json){ |
||||
|
_super_orderline.prototype.init_from_JSON.apply(this,arguments); |
||||
|
this.line_id = json.line_id; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
var _super = models.Order; |
||||
|
models.Order = models.Order.extend({ |
||||
|
|
||||
|
add_product: function (product, options) { |
||||
|
|
||||
|
var order = this.pos.get_order(); |
||||
|
_super.prototype.add_product.call(this, product, options); |
||||
|
if (options !== undefined) { |
||||
|
if (options.extras !== undefined) { |
||||
|
for (var prop in options.extras) { |
||||
|
if (prop === 'return_ref') { |
||||
|
this.return_ref = options.extras['return_ref'] |
||||
|
this.trigger('change', this); |
||||
|
} |
||||
|
if (prop === 'label') { |
||||
|
order.selected_orderline.set_line_id(options.extras['label']); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
export_as_JSON: function(){ |
||||
|
var json = _super.prototype.export_as_JSON.apply(this,arguments); |
||||
|
json.return_ref = this.return_ref; |
||||
|
return json; |
||||
|
}, |
||||
|
init_from_JSON: function(json){ |
||||
|
_super.prototype.init_from_JSON.apply(this,arguments); |
||||
|
this.return_ref = json.return_ref; |
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
models.PosModel = models.PosModel.extend({ |
||||
|
_save_to_server: function (orders, options) { |
||||
|
if (!orders || !orders.length) { |
||||
|
var result = $.Deferred(); |
||||
|
result.resolve([]); |
||||
|
return result; |
||||
|
} |
||||
|
var fields = _.find(this.models,function(model){ return model.model === 'pos.order'; }).fields; |
||||
|
options = options || {}; |
||||
|
|
||||
|
var self = this; |
||||
|
var timeout = typeof options.timeout === 'number' ? options.timeout : 7500 * orders.length; |
||||
|
|
||||
|
// Keep the order ids that are about to be sent to the
|
||||
|
// backend. In between create_from_ui and the success callback
|
||||
|
// new orders may have been added to it.
|
||||
|
var order_ids_to_sync = _.pluck(orders, 'id'); |
||||
|
|
||||
|
// we try to send the order. shadow prevents a spinner if it takes too long. (unless we are sending an invoice,
|
||||
|
// then we want to notify the user that we are waiting on something )
|
||||
|
var args = [_.map(orders, function (order) { |
||||
|
order.to_invoice = options.to_invoice || false; |
||||
|
return order; |
||||
|
})]; |
||||
|
return rpc.query({ |
||||
|
model: 'pos.order', |
||||
|
method: 'create_from_ui', |
||||
|
args: args, |
||||
|
kwargs: {context: session.user_context}, |
||||
|
}, { |
||||
|
timeout: timeout, |
||||
|
shadow: !options.to_invoice |
||||
|
}) |
||||
|
.then(function (server_ids) { |
||||
|
_.each(order_ids_to_sync, function (order_id) { |
||||
|
self.db.remove_order(order_id); |
||||
|
}); |
||||
|
self.set('failed',false); |
||||
|
if (server_ids.length != 0){ |
||||
|
for (var item in server_ids){ |
||||
|
rpc.query({ |
||||
|
model: 'pos.order', |
||||
|
method: 'search_read', |
||||
|
args: [[['id', '=', server_ids[item]]], fields], |
||||
|
limit: 1, |
||||
|
}) |
||||
|
.then(function (order){ |
||||
|
self.orders.unshift(order[0]); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
self.load_server_data(); |
||||
|
return server_ids; |
||||
|
}).fail(function (type, error){ |
||||
|
if(error.code === 200 ){ // Business Logic Error, not a connection problem
|
||||
|
//if warning do not need to display traceback!!
|
||||
|
if (error.data.exception_type == 'warning') { |
||||
|
delete error.data.debug; |
||||
|
} |
||||
|
|
||||
|
// Hide error if already shown before ...
|
||||
|
if ((!self.get('failed') || options.show_error) && !options.to_invoice) { |
||||
|
self.gui.show_popup('error-traceback',{ |
||||
|
'title': error.data.message, |
||||
|
'body': error.data.debug |
||||
|
}); |
||||
|
} |
||||
|
self.set('failed',error); |
||||
|
} |
||||
|
console.error('Failed to send orders:', orders); |
||||
|
}); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
}); |
@ -0,0 +1,95 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<templates id="template" xml:space="preserve"> |
||||
|
|
||||
|
<t t-name="ReturnButton"> |
||||
|
<div class='control-button'> |
||||
|
<i class='fa fa-rotate-left' /> Return |
||||
|
</div> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="OrderLine"> |
||||
|
<tr class='order-line' t-att-data-id='order.id'> |
||||
|
<td><t t-esc='order.pos_reference' /></td> |
||||
|
<td><t t-if="order.return_ref"> |
||||
|
<t t-esc='order.return_ref' /> |
||||
|
</t></td> |
||||
|
<td><t t-esc='order.partner_id[1]' /></td> |
||||
|
<td><t t-esc='order.date_order' /></td> |
||||
|
<td><span class="return-button return_order">Return</span></td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
|
||||
|
<t t-name="OrderListScreenWidget"> |
||||
|
<div class="return-screen screen"> |
||||
|
<div class="screen-content"> |
||||
|
<section class="top-content"> |
||||
|
<span class='button back'> |
||||
|
<i class='fa fa-angle-double-left'></i> |
||||
|
Cancel |
||||
|
</span> |
||||
|
<span class='searchbox'> |
||||
|
<input placeholder='Search' /> |
||||
|
<span class='search-clear'></span> |
||||
|
</span> |
||||
|
<span class='searchbox'></span> |
||||
|
|
||||
|
</section> |
||||
|
<section class="full-content"> |
||||
|
<div class='window'> |
||||
|
<section class='subwindow'> |
||||
|
<div class='subwindow-container'> |
||||
|
<div class='subwindow-container-fix touch-scrollable scrollable-y'> |
||||
|
<table class='order-list'> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Order Ref</th> |
||||
|
<th>Return Ref</th> |
||||
|
<th>Partner</th> |
||||
|
<th>Date</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class='order-list-contents'> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
</div> |
||||
|
</section> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
<t t-name="ReturnWidget"> |
||||
|
<div class="modal-dialog" role="dialog"> |
||||
|
<div class="popup popup-selection product_return_pos"> |
||||
|
<p class="title">Return Order</p> |
||||
|
<div class='selection scrollable-y touch-scrollable'> |
||||
|
<table id = "list" cellspacing = "1px" cellpadding = "10px" text-align = "center" |
||||
|
width="100%" style="border:1px;padding-left:1.16cm;"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<td>ID</td> |
||||
|
<td>Price</td> |
||||
|
<td>Name</td> |
||||
|
<td>Qty</td> |
||||
|
<td>Dis</td> |
||||
|
<td>Line ID</td> |
||||
|
<td>Returned Quantity</td> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody id="table-body"> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
<div class="footer"> |
||||
|
<div class="button confirm"> |
||||
|
Return |
||||
|
</div> |
||||
|
<div class="button cancel"> |
||||
|
Cancel |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
</templates> |
@ -0,0 +1,13 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data> |
||||
|
<template id="assets" inherit_id="point_of_sale.assets"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" |
||||
|
src="/product_return_pos/static/src/js/pos_return.js"/> |
||||
|
<link rel="stylesheet" href="/product_return_pos/static/src/css/pos_return.css" /> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,31 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data> |
||||
|
<record model="ir.ui.view" id="view_pos_new_form_extended"> |
||||
|
<field name="name">pos.order.form.extend</field> |
||||
|
<field name="model">pos.order</field> |
||||
|
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//field[@name='pos_reference']" position="after"> |
||||
|
<field name="return_ref"/> |
||||
|
<field name="return_status"/> |
||||
|
</xpath> |
||||
|
<xpath expr="//field[@name='lines']//tree//field[@name='qty']" position="after"> |
||||
|
<field name="returned_qty" invisible="1"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="view_pos_new_tree_extended"> |
||||
|
<field name="name">pos.order.tree.extend</field> |
||||
|
<field name="model">pos.order</field> |
||||
|
<field name="inherit_id" ref="point_of_sale.view_pos_order_tree"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//field[@name='pos_reference']" position="after"> |
||||
|
<field name="return_ref"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</odoo> |