Skip to content
Permalink
Browse files

Merge pull request #2 from Ommo73/10.0-project_timelog_port

10.0 project timelog port
  • Loading branch information...
GabbasovDinar committed Apr 5, 2019
2 parents 58d070e + 82f42f7 commit 8b78eebb106f648d1e6ab997d08283fe33005de2
@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2004-2015 Odoo S.A.
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# Copyright 2018-2019 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{
"name": """Partner Attendances""",
"summary": """Manage partner attendances""",
"category": "Extra Tools",
# "live_test_url": "",
"images": [],
"version": "10.0.1.0.0",
"version": "10.0.1.1.0",
"application": False,

"author": "IT-Projects LLC, Kolushov Alexandr",
@@ -1,3 +1,10 @@
`1.1.0`
-------

- **New:** Autocheckout option - closes shifts after defined time
- **New:** Option to support HEX barcode scanners in **Kiosk Mode**
- **Fix:** Error related to incorrect attribute name

`1.0.0`
-------

@@ -57,6 +57,14 @@ Also it is possible to use barcodes to check partners attendance
* Open menu ``[[ Partner Attendances ]] >> Kiosk Mode``
* Scan a partner's barcode to check him in or out, it depends on the actual partner's presence

Auto Checkout
-------------

Restriction on the maximum partner attendance time. Each ten minutes odoo checks for opened partner session, if a session lasts more then defined time it will be closed.

* Open menu ``[[ Partner Attendances ]] >> Configuration``
* Set ``AutoCheckout`` field in minutes.

Installation
============

@@ -1,12 +1,15 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2004-2015 Odoo S.A.
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# Copyright 2018-2019 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

from datetime import datetime

from odoo import models, fields, api, exceptions, _
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
import logging

_logger = logging.getLogger(__name__)


class HrAttendance(models.Model):
@@ -100,7 +103,7 @@ def _check_validity(self):
], order='check_in desc', limit=1)
if last_attendance_before_check_out and last_attendance_before_check_in != last_attendance_before_check_out:
raise exceptions.ValidationError(_("Cannot create new attendance record for %(partner_name)s, the partner was already checked in on %(datetime)s") % {
'partner_name': attendance.partner.name,
'partner_name': attendance.partner_id.name,
'datetime': fields.Datetime.to_string(fields.Datetime.context_timestamp(self, fields.Datetime.from_string(last_attendance_before_check_out.check_in))),
})

@@ -110,3 +113,15 @@ def copy(self):
# [W8106(method-required-super), HrAttendance.copy] Missing `super` call in "copy" method.
super(HrAttendance, self).copy()
raise exceptions.UserError(_('You cannot duplicate an attendance.'))

@api.multi
def autocheckout_close_shifts(self):
max_interval = float(self.env["ir.config_parameter"].get_param("base_attendance.shift_autocheckout", default=0))
if max_interval:
shifts = self.search([('check_out', '=', False)]).filtered(
lambda x: (datetime.today() - datetime.strptime(x.check_in, DEFAULT_SERVER_DATETIME_FORMAT)).
total_seconds() / 3600 >= max_interval / 60)
_logger.info("partner session autologout for: %s, interval: %s", shifts.ids, max_interval)
shifts.write({
'check_out': fields.Datetime.now(),
})
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2004-2015 Odoo S.A.
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# Copyright 2018-2019 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

from odoo import fields, models
from odoo import fields, models, api


class BaseConfigSettings(models.TransientModel):
@@ -14,3 +14,39 @@ class BaseConfigSettings(models.TransientModel):
string='Partner PIN',
help='Enable or disable partner PIN identification at check in',
implied_group="base_attendance.group_hr_attendance_use_pin")
shift_autocheckout = fields.Integer('Autocheckout ', help="Maximum Shift Time in Minutes")
hex_scanner_is_used = fields.Boolean('HEX Scanner', default=False,
help='Some devices scan regular barcodes as hexadecimal. '
'This option decode those types of barcodes')

@api.multi
def set_shift_autocheckout(self):
self.env["ir.config_parameter"].set_param("base_attendance.shift_autocheckout", self.shift_autocheckout or '0')
self.checkout_shifts()

@api.multi
def get_default_shift_autocheckout(self, fields):
shift_autocheckout = self.env["ir.config_parameter"].get_param("base_attendance.shift_autocheckout", default=0)
return {'shift_autocheckout': int(shift_autocheckout)}

@api.model
def checkout_shifts(self):
cron_record = self.env.ref('base_attendance.base_attendance_autocheckout')
if self.shift_autocheckout == 0:
cron_record.write({
'active': False,
})
else:
cron_record.write({
'active': True,
})

@api.multi
def set_hex_scanner_is_used(self):
self.env["ir.config_parameter"].set_param("base_attendance.hex_scanner_is_used", self.hex_scanner_is_used)

@api.multi
def get_default_hex_scanner_is_used(self, fields):
hex_scanner_is_used = self.env["ir.config_parameter"].get_param("base_attendance.hex_scanner_is_used",
default=False)
return {'hex_scanner_is_used': hex_scanner_is_used}
@@ -65,7 +65,7 @@ def attendance_scan(self, barcode):
def attendance_manual(self, next_action, entered_pin=None):
self.ensure_one()
if not (entered_pin is None) or \
self.env['res.users'].browse(SUPERUSER_ID).has_group('hr_partner_attendance.group_hr_attendance_use_pin'):
self.env['res.users'].browse(SUPERUSER_ID).has_group('base_attendance.group_hr_attendance_use_pin'):
if entered_pin != self.pin:
return {'warning': _('Wrong PIN')}
return self.attendance_action(next_action)
@@ -104,7 +104,7 @@ var KioskConfirm = Widget.extend({
start_clock: function () {
this.clock_start = setInterval(function() {
this.$(".o_hr_attendance_clock").text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit'}));
}, 700);
}, 900);
// First clock refresh before interval to avoid delay
this.$(".o_hr_attendance_clock").text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit'}));
},
@@ -8,6 +8,7 @@ var core = require('web.core');
var Model = require('web.Model');
var Widget = require('web.Widget');
var Session = require('web.session');
var local_storage = require('web.local_storage');
var BarcodeHandlerMixin = require('barcodes.BarcodeHandlerMixin');

var QWeb = core.qweb;
@@ -27,9 +28,27 @@ var KioskMode = Widget.extend(BarcodeHandlerMixin, {
// We added a local variable for this._super in order to fix the nextLINT error
//"Expected an assignment or function call and instead saw an expression. [Error/no-unused-expressions]"
var init_super = this._super;

action.target = 'fullscreen';
var hex_scanner_is_used = action.context.hex_scanner_is_used;
if (typeof hex_scanner_is_used === 'undefined') {
hex_scanner_is_used = this.get_from_storage('hex_scanner_is_used') || false;
} else {
this.save_locally('hex_scanner_is_used', Boolean(hex_scanner_is_used));
}
this.hex_scanner_is_used = hex_scanner_is_used;

BarcodeHandlerMixin.init.apply(this, arguments);
},

save_locally: function(key, value) {
local_storage.setItem('est.' + key, JSON.stringify(value));
},

get_from_storage: function(key) {
return JSON.parse(local_storage.getItem('est.' + key));
},

start: function () {
var self = this;
self.session = Session;
@@ -49,20 +68,26 @@ var KioskMode = Widget.extend(BarcodeHandlerMixin, {
on_barcode_scanned: function(barcode) {
var self = this;
var hr_employee = new Model('res.partner');
hr_employee.call('attendance_scan', [barcode, ]).
then(function (result) {
if (result.action) {
self.do_action(result.action);
} else if (result.warning) {
self.do_warn(result.warning);
}
});
var res_barcode = barcode;
if (this.hex_scanner_is_used) {
res_barcode = parseInt(barcode, 16).toString();
if (res_barcode.length % 2) {
res_barcode = '0' + res_barcode;
}
}
hr_employee.call('attendance_scan', [res_barcode, ]).then(function (result) {
if (result.action) {
self.do_action(result.action);
} else if (result.warning) {
self.do_warn(result.warning);
}
});
},

start_clock: function() {
this.clock_start = setInterval(function() {
this.$(".o_hr_attendance_clock").text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit'}));
}, 700);
}, 900);
// First clock refresh before interval to avoid delay
this.$(".o_hr_attendance_clock").text(new Date().toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit'}));
},
@@ -17,7 +17,7 @@ odoo.define('base_attendance.tour', function (require) {
'.oe_hr_attendance_status.fa.fa-user.oe_hr_attendance_status_' + color,
content: 'Select Partner',
}, {
trigger: '.fa.btn-primary.o_hr_attendance_sign_in_out_icon.fa-sign-out.fa-sign-out',
trigger: '.fa.btn-primary.o_hr_attendance_sign_in_out_icon.fa-sign-out',
content: 'Check in',
}, {
trigger: 'button:contains("ok")',
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2004-2015 Odoo S.A.
Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
Copyright 2018-2019 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).-->
<odoo>

@@ -113,10 +113,21 @@
<field name="view_id"></field> <!-- force empty -->
</record>

<record id="hr_attendance_action_kiosk_mode" model="ir.actions.client">
<field name="name">Attendances</field>
<field name="tag">base_attendance_kiosk_mode</field>
<field name="target">fullscreen</field>
<record model="ir.actions.server" id="hr_attendance_action_kiosk_mode">
<field name="name">Get to the Kiosk Mode</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_res_partner_attendance"/>
<field name="code">
hex_scanner_is_used = model.env["ir.config_parameter"].get_param("base_attendance.hex_scanner_is_used",default=False)
action = {
'type': 'ir.actions.client',
'tag': 'base_attendance_kiosk_mode',
'target': 'fullscreen',
'context': {
'hex_scanner_is_used': hex_scanner_is_used
},
}
</field>
</record>

<record id="hr_attendance_action_greeting_message" model="ir.actions.client">
@@ -233,4 +244,18 @@
<menuitem id="menu_hr_attendance_kiosk_mode" name="Kiosk Mode" parent="menu_hr_attendance_manage_attendances" sequence="20" groups="base_attendance.group_hr_attendance_user" action="hr_attendance_action_kiosk_mode"/>

<menuitem id="menu_hr_attendance_report" name="Reports" parent="menu_base_attendance_root" sequence="30" groups="base_attendance.group_hr_attendance_user" action="hr_attendance_action_graph"/>

<!--IR CRON-->

<record model="ir.cron" id="base_attendance_autocheckout">
<field name="name">Partner Shift Autocheckout</field>
<field name="active" eval="False"/>
<field name="interval_number">10</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="model" eval="'res.partner.attendance'"/>
<field name="function" eval="'autocheckout_close_shifts'"/>
</record>

</odoo>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2004-2015 Odoo S.A.
Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
Copyright 2018-2019 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<record id="hr_attendance_view_config" model="ir.ui.view">
@@ -14,7 +14,9 @@
<button string="Cancel" type="object" name="cancel" class="oe_link" special="cancel"/>
</header>
<group string="Settings">
<field name="hex_scanner_is_used"/>
<field name="group_attendance_use_pin" widget="radio"/>
<field name="shift_autocheckout"/>
</group>
</form>
</field>
@@ -18,8 +18,6 @@
'mail_base',
],
'data': [
'security/web_debranding_security.xml',
'security/ir.model.access.csv',
'data.xml',
'views.xml',
'js.xml',
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="default_logo_module" model="ir.config_parameter">
<field name="key">web_debranding.default_logo_module</field>
<field name="value">web_debranding</field>
@@ -10,5 +9,4 @@
</record>


</data>
</odoo>
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="debranding_title_js" name="Debranding title JS"
inherit_id="web.assets_backend">
<xpath expr="." position="inside">
@@ -21,5 +20,4 @@
src="/web_debranding/static/src/js/user_menu.js"></script>
</xpath>
</template>
</data>
</odoo>
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import logging
from odoo.tools import mute_logger
from odoo import models, api

from .ir_translation import debrand
@@ -72,7 +73,7 @@ def _create_view(self, name, inherit_id, arch, noupdate=False, type='qweb'):
return view.id

try:
with self.env.cr.savepoint():
with self.env.cr.savepoint(), mute_logger('odoo.models'):
view = self.env['ir.ui.view'].create({
'name': name,
'type': type,

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<data>
<template id="login_layout" inherit_id="web.login_layout" priority="8">
<xpath expr="//div[@t-if='not disable_footer']" position="replace"></xpath>
</template>
@@ -15,6 +14,5 @@
</t>
</xpath>
</template>
</data>

</odoo>

0 comments on commit 8b78eeb

Please sign in to comment.
You can’t perform that action at this time.