Skip to content
Permalink
Browse files

Merge branch '12.0' into 12.0-autostaging_base-porting

  • Loading branch information...
Ommo73 committed May 14, 2019
2 parents 7857dd5 + 58f3b3d commit de94a0d5587214525c36905ccb58b58e332e69bf
Showing with 890 additions and 288 deletions.
  1. +2 −0 README.md
  2. +2 −2 base_attendance/__manifest__.py
  3. +19 −0 base_attendance/doc/changelog.rst
  4. +11 −2 base_attendance/doc/index.rst
  5. +17 −2 base_attendance/models/res_attendance.py
  6. +38 −2 base_attendance/models/res_config.py
  7. +1 −1 base_attendance/models/res_partner.py
  8. +1 −1 base_attendance/security/ir.model.access.csv
  9. +3 −9 base_attendance/security/res_attendance_security.xml
  10. +1 −1 base_attendance/static/src/js/greeting_message.js
  11. +2 −2 base_attendance/static/src/js/kiosk_confirm.js
  12. +30 −2 base_attendance/static/src/js/kiosk_mode.js
  13. +1 −0 base_attendance/static/src/scss/hr_attendance.scss
  14. +3 −3 base_attendance/static/src/xml/attendance.xml
  15. +35 −8 base_attendance/views/res_attendance_view.xml
  16. +4 −2 base_attendance/views/res_config_view.xml
  17. +10 −5 ir_attachment_s3/i18n/es_CR.po
  18. +3 −3 ir_config_parameter_multi_company/i18n/es_CR.po
  19. +0 −1 ir_config_parameter_multi_company/models/__init__.py
  20. +0 −2 ir_config_parameter_multi_company/models/ir_config_parameter.py
  21. +0 −36 ir_config_parameter_multi_company/models/res_users.py
  22. +13 −8 product_category_taxes/i18n/es_CR.po
  23. +17 −16 product_tags/i18n/es_CR.po
  24. +25 −0 production_lot_details/i18n/es_CR.po
  25. +41 −0 project_gantt8/i18n/es_CR.po
  26. +6 −5 project_task_order_kanban_state/i18n/es_CR.po
  27. +17 −3 project_task_subtask/README.rst
  28. +2 −1 project_task_subtask/__init__.py
  29. +9 −1 project_task_subtask/__manifest__.py
  30. +5 −5 project_task_subtask/data/subscription_template.xml
  31. +5 −4 project_task_subtask/demo/project_task_subtask_demo.xml
  32. +5 −0 project_task_subtask/doc/changelog.rst
  33. +30 −36 project_task_subtask/i18n/es_CR.po
  34. +2 −1 project_task_subtask/models/__init__.py
  35. +82 −22 project_task_subtask/models/project_task_subtask.py
  36. +4 −5 project_task_subtask/security/project_security.xml
  37. +35 −0 project_task_subtask/static/src/css/kanban_styles.css
  38. +213 −0 project_task_subtask/static/src/js/one2many_renderer.js
  39. +10 −0 project_task_subtask/static/src/xml/templates.xml
  40. +11 −0 project_task_subtask/views/assets.xml
  41. +12 −3 project_task_subtask/views/project_task_subtask.xml
  42. +22 −19 reminder_base/i18n/es_CR.po
  43. +7 −6 reminder_crm_next_action/i18n/es_CR.po
  44. +6 −5 reminder_crm_next_action_time/i18n/es_CR.po
  45. +35 −0 reminder_hr_recruitment/i18n/es_CR.po
  46. +6 −5 reminder_task_deadline/i18n/es_CR.po
  47. +6 −5 res_partner_skype/i18n/es_CR.po
  48. +25 −0 sale_order_hide_tax/i18n/es_CR.po
  49. +1 −1 theme_kit/__manifest__.py
  50. +1 −2 web_debranding/__manifest__.py
  51. +5 −0 web_debranding/doc/changelog.rst
  52. +10 −10 web_debranding/i18n/es_CR.po
  53. +2 −1 web_debranding/models/ir_ui_view.py
  54. +0 −1 web_debranding/security/ir.model.access.csv
  55. +12 −28 web_debranding/static/src/js/field_upgrade.js
  56. +11 −10 web_preview/i18n/es_CR.po
  57. +1 −1 web_website/__manifest__.py
  58. +9 −0 web_website/doc/changelog.rst
  59. +4 −0 web_website/models/ir_property.py
@@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.com/it-projects-llc/misc-addons.svg?branch=12.0)](https://travis-ci.com/it-projects-llc/misc-addons)

Odoo addons
===========

@@ -1,13 +1,13 @@
# 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": "12.0.1.0.0",
"version": "12.0.1.1.1",
"application": False,

"author": "IT-Projects LLC, Kolushov Alexandr",
@@ -1,3 +1,22 @@
`1.1.1`
-------

- **Fix:** Broken pin pad in the **Kiosk Mode**
- **Fix:** Security issues for ``Attendance Manager`` group on opening the **Kiosk Mode**

`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
- **Fix:** Error message even for correct partner PIN codes

`1.0.1`
-------

- **Fix:** Error on error message for incorrect attendance creation

`1.0.0`
-------

@@ -17,8 +17,9 @@ In order to set access rights for users

* ``Read-Only`` may see only *Attendances* menu
* ``Manual Attendance`` may create and update partner attendances, but not delete
* ``Officer`` may also delete partners attendances, has access to *Partners*, *Reports* menus and *Kiosk Mode*
* ``Manager`` like Officer, but also has access to *Configuration* menu
* ``Manager`` may also delete partners attendances, has access to *Partners*, *Reports* menus and *Kiosk Mode*

* In order to get access to ``Configuration`` menu user has to have **Administration** ``Settings`` rights

Barcode
-------
@@ -57,6 +58,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,8 +1,12 @@
# 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, _
import logging

_logger = logging.getLogger(__name__)


class HrAttendance(models.Model):
@@ -95,7 +99,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))),
})

@@ -105,3 +109,14 @@ 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() - x.check_in).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,8 +1,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):
@@ -13,3 +13,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_values(self):
super(BaseConfigSettings, self).set_values()
config_parameters = self.env["ir.config_parameter"].sudo()
for record in self:
config_parameters.set_param("base_attendance.shift_autocheckout",
record.shift_autocheckout or '0')
config_parameters.set_param("base_attendance.hex_scanner_is_used", record.hex_scanner_is_used)
self.checkout_shifts()

@api.multi
def get_values(self):
res = super(BaseConfigSettings, self).get_values()
config_parameters = self.env["ir.config_parameter"].sudo()
res.update(
shift_autocheckout=int(config_parameters.get_param("base_attendance.shift_autocheckout", default=0)),
hex_scanner_is_used=config_parameters.get_param("base_attendance.hex_scanner_is_used", default=False),
)
return res

@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,
})
@@ -64,7 +64,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)
@@ -1,5 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_hr_attendance_readonly_attendance,res.partner.attendance.user,model_res_partner_attendance,base_attendance.group_res_attendance,1,0,0,0
access_hr_attendance_manual_attendance,res.partner.attendance.user,model_res_partner_attendance,base_attendance.group_manual_attendance,1,1,1,0
access_hr_attendance_officer,res.partner.attendance.user,model_res_partner_attendance,base_attendance.group_hr_attendance_user,1,1,1,1
access_hr_attendance_officer,res.partner.attendance.user,model_res_partner_attendance,base_attendance.group_hr_attendance_manager,1,1,1,1
access_hr_attendance_attendance,res.partner.attendance.user,model_res_partner_attendance,,0,0,0,0
@@ -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 model="ir.module.category" id="module_category_attendance">
@@ -22,16 +22,10 @@
<field name="comment">The user will gain access to manage partners attendance.</field>
</record>

<record id="group_hr_attendance_user" model="res.groups">
<field name="name">Officer</field>
<field name="category_id" ref="module_category_attendance"/>
<field name="implied_ids" eval="[(4, ref('group_manual_attendance'))]"/>
</record>

<record id="group_hr_attendance_manager" model="res.groups">
<field name="name">Manager</field>
<field name="category_id" ref="module_category_attendance"/>
<field name="implied_ids" eval="[(4, ref('base_attendance.group_hr_attendance_user'))]"/>
<field name="implied_ids" eval="[(4, ref('group_manual_attendance'))]"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>

@@ -51,7 +45,7 @@
<field name="name">attendance officer: full access</field>
<field name="model_id" ref="model_res_partner_attendance"/>
<field name="domain_force">[(1,'=',1)]</field>
<field name="groups" eval="[(4,ref('base_attendance.group_hr_attendance_user'))]"/>
<field name="groups" eval="[(4,ref('base_attendance.group_hr_attendance_manager'))]"/>
</record>

</data>
@@ -28,7 +28,7 @@ var GreetingMessage = AbstractAction.extend({
// to the (likely) appropriate menu, according to the user access rights
if(!action.attendance) {
this.activeBarcode = false;
this.getSession().user_has_group('base_attendance.group_hr_attendance_user').then(function(has_group) {
this.getSession().user_has_group('base_attendance.group_hr_attendance_manager').then(function(has_group) {
if(has_group) {
self.next_action = 'base_attendance.hr_attendance_action_kiosk_mode';
} else {
@@ -69,7 +69,7 @@ var KioskConfirm = AbstractAction.extend({
this._rpc({
model: 'res.partner',
method: 'attendance_manual',
args: [[this.partner], this.next_action, this.$('.o_hr_attendance_PINbox').val()],
args: [[self.partner_id], this.next_action, this.$('.o_hr_attendance_PINbox').val()],
}).then(function(result) {
if (result.action) {
self.do_action(result.action);
@@ -105,7 +105,7 @@ var KioskConfirm = AbstractAction.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'}));
}, 500);
}, 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 AbstractAction = require('web.AbstractAction');
var ajax = require('web.ajax');
var core = require('web.core');
var Session = require('web.session');
var local_storage = require('web.local_storage');

var QWeb = core.qweb;

@@ -18,6 +19,26 @@ var KioskMode = AbstractAction.extend({
},
},

init: function (parent, action) {
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;
this._super(parent, action);
},

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;
core.bus.on('barcode_scanned', this, this._onBarcodeScanned);
@@ -39,10 +60,17 @@ var KioskMode = AbstractAction.extend({

_onBarcodeScanned: function(barcode) {
var self = this;
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;
}
}
this._rpc({
model: 'res.partner',
method: 'attendance_scan',
args: [barcode, ],
args: [res_barcode, ],
}).then(function (result) {
if (result.action) {
self.do_action(result.action);
@@ -55,7 +83,7 @@ var KioskMode = AbstractAction.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'}));
},
@@ -102,6 +102,7 @@
position: relative;
background-color: #fff;
padding: 2em;
margin-top: 50px;

h1 {
margin: 0 0 2rem 0;
@@ -44,13 +44,13 @@
<h2>Please enter your PIN to check in</h2>
</t>
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div class="col-8 offset-2">
<div class="row" >
<div class="col-xs-4 col-xs-offset-4"><input class="o_hr_attendance_PINbox" type="password" disabled="true"/></div>
<div class="col-4 offset-4"><input class="o_hr_attendance_PINbox" type="password" disabled="true"/></div>
</div>
<div class="row o_hr_attendance_pin_pad">
<t t-foreach="['1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', '0', 'ok']" t-as="btn_name">
<div class="col-xs-4 o_hr_attendance_pin_pad_border">
<div class="col-4 o_hr_attendance_pin_pad_border">
<a t-attf-class="btn btn-primary btn-block btn-lg o_hr_attendance_btn-round-corners {{ 'o_hr_attendance_pin_pad_button_' + btn_name }}"><t t-esc="btn_name"/></a>
</div>
</t>
@@ -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>

@@ -124,10 +124,22 @@
<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="state">code</field>
<field name="code">
hex_scanner_is_used = model.env["ir.config_parameter"].sudo().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">
@@ -261,9 +273,24 @@

<menuitem id="menu_hr_attendance_view_attendances" name="Attendances" parent="menu_hr_attendance_manage_attendances" sequence="10" groups="base_attendance.group_res_attendance" action="hr_attendance_action"/>

<menuitem id="menu_hr_attendance_view_partners_kanban" name="Partners" parent="menu_hr_attendance_manage_attendances" sequence="15" groups="base_attendance.group_hr_attendance_user" action="base.action_partner_form"/>
<menuitem id="menu_hr_attendance_view_partners_kanban" name="Partners" parent="menu_hr_attendance_manage_attendances" sequence="15" groups="base_attendance.group_hr_attendance_manager" action="base.action_partner_form"/>

<menuitem id="menu_hr_attendance_kiosk_mode" name="Kiosk Mode" parent="menu_hr_attendance_manage_attendances" sequence="20" groups="base_attendance.group_hr_attendance_manager" action="hr_attendance_action_kiosk_mode"/>

<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_manager" 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_id" ref="model_res_partner_attendance"/>
<field name="state">code</field>
<field name="code">model.autocheckout_close_shifts()</field>
</record>

<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"/>
</odoo>
Oops, something went wrong.

0 comments on commit de94a0d

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