Implemented locking feature as an optionally enabled plugin.
authorNik Okuntseff <support@anuko.com>
Thu, 31 Mar 2016 18:31:28 +0000 (18:31 +0000)
committerNik Okuntseff <support@anuko.com>
Thu, 31 Mar 2016 18:32:56 +0000 (18:32 +0000)
18 files changed:
WEB-INF/lib/ttTeamHelper.class.php
WEB-INF/lib/ttUser.class.php
WEB-INF/resources/en.lang.php
WEB-INF/resources/ru.lang.php
WEB-INF/templates/footer.tpl
WEB-INF/templates/locking.tpl [new file with mode: 0644]
WEB-INF/templates/profile_edit.tpl
expense_delete.php
expense_edit.php
expenses.php
locking.php [new file with mode: 0644]
mobile/time.php
mobile/time_delete.php
mobile/time_edit.php
profile_edit.php
time.php
time_delete.php
time_edit.php

index d037f86..1cf71d8 100644 (file)
@@ -707,11 +707,11 @@ class ttTeamHelper {
   // The update function updates team information.
   static function update($team_id, $fields)    
   {
-       // We'll require team name to be always set.
-       if (!isset($fields['name'])) return false;
+    // We'll require team name to be always set.
+    if (!isset($fields['name'])) return false;
 
-       $mdb2 = getConnection();
-       $name_part = 'name = '.$mdb2->quote($fields['name']);
+    $mdb2 = getConnection();
+    $name_part = 'name = '.$mdb2->quote($fields['name']);
     $currency_part = '';
     $addr_part = '';
     $locktime_part = '';
index 78fee50..a14f7cd 100644 (file)
@@ -172,4 +172,20 @@ class ttUser {
     }
     return $result;
   }
+
+  // isDateLocked checks whether a specifc date is locked for modifications.
+  function isDateLocked($date)
+  {
+    if ($this->isPluginEnabled('lk')) {
+      // Determine lock date. Entries earlier than lock date cannot be created or modified.
+      $lockdate = 0;
+      if ($this->lock_interval > 0) {
+        $lockdate = new DateAndTime();
+        $lockdate->decDay($this->lock_interval);
+      }
+      if($lockdate && $date->before($lockdate))
+        return true;
+    }
+    return false;
+  }
 }
index 323e615..19fc348 100644 (file)
@@ -251,6 +251,9 @@ $i18n_key_words = array(
 'title.cf_add_dropdown_option' => 'Adding Option',
 'title.cf_edit_dropdown_option' => 'Editing Option',
 'title.cf_delete_dropdown_option' => 'Deleting Option',
+// NOTE TO TRANSLATORS: Locking is a feature to lock records from modifications (ex: weekly on Mondays we lock all previous weeks).
+// It is also a name for the Locking plugin on the Team profile page.
+'title.locking' => 'Locking',
 
 // Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
 // Strings that are used in a single form must go to the specific form section.
index 76ab676..0a37683 100644 (file)
@@ -251,6 +251,7 @@ $i18n_key_words = array(
 'title.cf_add_dropdown_option' => 'Добавление опции',
 'title.cf_edit_dropdown_option' => 'Редактирование опции',
 'title.cf_delete_dropdown_option' => 'Удаление опции',
+'title.locking' => 'Блокировка',
 
 // Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
 // Strings that are used in a single form must go to the specific form section.
index 646f68d..7bf4e1a 100644 (file)
@@ -12,7 +12,7 @@
       <br>
       <table cellspacing="0" cellpadding="4" width="100%" border="0">
         <tr>
-          <td align="center">&nbsp;Anuko Time Tracker 1.9.20.3463 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
+          <td align="center">&nbsp;Anuko Time Tracker 1.9.21.3464 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
             <a href="https://www.anuko.com/lp/tt_4.htm" target="_blank">{$i18n.footer.credits}</a> |
             <a href="https://www.anuko.com/lp/tt_5.htm" target="_blank">{$i18n.footer.license}</a> |
             <a href="https://www.anuko.com/lp/tt_7.htm" target="_blank">{$i18n.footer.improve}</a>
diff --git a/WEB-INF/templates/locking.tpl b/WEB-INF/templates/locking.tpl
new file mode 100644 (file)
index 0000000..94e706a
--- /dev/null
@@ -0,0 +1,20 @@
+{$forms.lockingForm.open}
+<table cellspacing="4" cellpadding="7" border="0">
+  <tr>
+    <td>
+      <table cellspacing="1" cellpadding="2" border="0">
+        <tr>
+          <td align="right" nowrap>{$i18n.label.lock_interval}:</td>
+          <td>{$forms.lockingForm.lock_interval.control}</td>
+        </tr>
+        <tr>
+          <td colspan="2">&nbsp;</td>
+        </tr>
+        <tr>
+          <td colspan="2" height="50" align="center">{$forms.lockingForm.btn_save.control}</td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+</table>
+{$forms.lockingForm.close}
index 5a90937..8d68c3e 100644 (file)
@@ -44,6 +44,14 @@ function handlePluginCheckboxes() {
   } else {
     configureLabel.style.visibility = "hidden";
   }
+
+  var lockingCheckbox = document.getElementById("locking");
+  configureLabel = document.getElementById("locking_config");
+  if (lockingCheckbox.checked) {
+    configureLabel.style.visibility = "visible";
+  } else {
+    configureLabel.style.visibility = "hidden";
+  }
 }
 </script>
 
@@ -96,10 +104,6 @@ function handlePluginCheckboxes() {
             <td align="right">{$i18n.label.currency}:</td>
             <td>{$forms.profileForm.currency.control}</td>
           </tr>
-          <tr>
-            <td align="right" nowrap>{$i18n.label.lock_interval}:</td>
-            <td>{$forms.profileForm.lock_interval.control}</td>
-          </tr>
           <tr>
            <td align="right" nowrap>{$i18n.label.language}:</td>
            <td>{$forms.profileForm.lang.control}</td>
@@ -175,6 +179,10 @@ function handlePluginCheckboxes() {
             <td align="right" nowrap>{$forms.profileForm.notifications.control}</td>
             <td><label for="notifications">{$i18n.title.notifications}</label> <span id="notifications_config"><a href="notifications.php">{$i18n.label.configure}</a></span></td>
           </tr>
+          <tr>
+            <td align="right" nowrap>{$forms.profileForm.locking.control}</td>
+            <td><label for="notifications">{$i18n.title.locking}</label> <span id="locking_config"><a href="locking.php">{$i18n.label.configure}</a></span></td>
+          </tr>
 {/if}
 
           <tr>
index 14e7088..78209aa 100644 (file)
@@ -46,21 +46,10 @@ if ($expense_item['invoice_id']) die($i18n->getKey('error.sys'));
 if ($request->isPost()) {
   if ($request->getParameter('delete_button')) { // Delete button pressed.
 
-    // Determine if it's okay to delete the record.
-
-    // Determine lock date.
-    $lock_interval = $user->lock_interval;
-    $lockdate = 0;
-    if ($lock_interval > 0) {
-      $lockdate = new DateAndTime();
-      $lockdate->decDay($lock_interval);
-    }
-    if ($lockdate) {
-      $item_date = new DateAndTime(DB_DATEFORMAT);
-      $item_date->parseVal($expense_item['date'], DB_DATEFORMAT);
-      if ($item_date->before($lockdate))
-        $err->add($i18n->getKey('error.period_locked'));
-    }
+    // Determine if it is okay to delete the record.
+    $item_date = new DateAndTime(DB_DATEFORMAT, $expense_item['date']);
+    if ($user->isDateLocked($item_date))
+      $err->add($i18n->getKey('error.period_locked'));
 
     if ($err->no()) {
       // Mark the record as deleted.
index 16b9abb..e4d1d05 100644 (file)
@@ -140,14 +140,6 @@ if ($request->isPost()) {
   if (!ttValidFloat($cl_cost)) $err->add($i18n->getKey('error.field'), $i18n->getKey('label.cost'));
   if (!ttValidDate($cl_date)) $err->add($i18n->getKey('error.field'), $i18n->getKey('label.date'));
 
-  // Determine lock date.
-  $lock_interval = $user->lock_interval;
-  $lockdate = 0;
-  if ($lock_interval > 0) {
-    $lockdate = new DateAndTime();
-    $lockdate->decDay($lock_interval);
-  }
-
   // This is a new date for the expense item.
   $new_date = new DateAndTime($user->date_format, $cl_date);
 
@@ -161,15 +153,16 @@ if ($request->isPost()) {
   // Save record.
   if ($request->getParameter('btn_save')) {
     // We need to:
-    // 1) Prohibit updating locked entries (that are in locked interval).
-    // 2) Prohibit saving unlocked entries into locked interval.
+    // 1) Prohibit updating locked entries (that are in locked range).
+    // 2) Prohibit saving unlocked entries into locked range.
 
     // Now, step by step.
-    // 1) Prohibit updating locked entries.
-    if($lockdate && $item_date->before($lockdate))
+    // 1) Prohibit saving locked entries in any form.
+    if ($user->isDateLocked($item_date))
       $err->add($i18n->getKey('error.period_locked'));
-    // 2) Prohibit saving completed unlocked entries into locked interval.
-    if($err->no() && $lockdate && $new_date->before($lockdate))
+
+    // 2) Prohibit saving unlocked entries into locked range.
+    if ($err->no() && $user->isDateLocked($new_date))
       $err->add($i18n->getKey('error.period_locked'));
 
     // Now, an update.
index f1319e0..56446a8 100644 (file)
@@ -133,14 +133,6 @@ $form->addInput(array('type'=>'calendar','name'=>'date','highlight'=>'expenses',
 $form->addInput(array('type'=>'hidden','name'=>'browser_today','value'=>'')); // User current date, which gets filled in on btn_submit click.
 $form->addInput(array('type'=>'submit','name'=>'btn_submit','onclick'=>'browser_today.value=get_date()','value'=>$i18n->getKey('button.submit')));
 
-// Determine lock date. Time entries earlier than lock date cannot be created or modified.
-$lock_interval = $user->lock_interval;
-$lockdate = 0;
-if ($lock_interval > 0) {
-  $lockdate = new DateAndTime();
-  $lockdate->decDay($lock_interval);
-}
-
 // Submit.
 if ($request->isPost()) {
   if ($request->getParameter('btn_submit')) {
@@ -161,8 +153,8 @@ if ($request->isPost()) {
     }
     // Finished validating input data.
 
-    // Prohibit creating time entries in locked interval.
-    if($lockdate && $selected_date->before($lockdate))
+    // Prohibit creating entries in locked range.
+    if ($user->isDateLocked($selected_date))
       $err->add($i18n->getKey('error.period_locked'));
 
     // Insert record.
diff --git a/locking.php b/locking.php
new file mode 100644 (file)
index 0000000..09a7cf9
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+// +----------------------------------------------------------------------+
+// | Anuko Time Tracker
+// +----------------------------------------------------------------------+
+// | Copyright (c) Anuko International Ltd. (https://www.anuko.com)
+// +----------------------------------------------------------------------+
+// | LIBERAL FREEWARE LICENSE: This source code document may be used
+// | by anyone for any purpose, and freely redistributed alone or in
+// | combination with other software, provided that the license is obeyed.
+// |
+// | There are only two ways to violate the license:
+// |
+// | 1. To redistribute this code in source form, with the copyright
+// |    notice or license removed or altered. (Distributing in compiled
+// |    forms without embedded copyright notices is permitted).
+// |
+// | 2. To redistribute modified versions of this code in *any* form
+// |    that bears insufficient indications that the modifications are
+// |    not the work of the original author(s).
+// |
+// | This license applies to this document only, not any other software
+// | that it may be combined with.
+// |
+// +----------------------------------------------------------------------+
+// | Contributors:
+// | https://www.anuko.com/time_tracker/credits.htm
+// +----------------------------------------------------------------------+
+
+require_once('initialize.php');
+import('form.Form');
+import('ttTeamHelper');
+
+// Access check.
+if (!ttAccessCheck(right_manage_team)) {
+  header('Location: access_denied.php');
+  exit();
+}
+
+$cl_lock_interval = $request->isPost() ? $request->getParameter('lock_interval') : $user->lock_interval;
+
+$form = new Form('lockingForm');
+$form->addInput(array('type'=>'text','maxlength'=>'10','name'=>'lock_interval','value'=>$cl_lock_interval));
+$form->addInput(array('type'=>'submit','name'=>'btn_save','value'=>$i18n->getKey('button.save')));
+
+if ($request->isPost()) {
+  if ($cl_lock_interval == null || trim($cl_lock_interval) == '') $cl_lock_interval = 0;
+
+  if (ttTeamHelper::update($user->team_id, array(
+    'name' => $user->team,
+    'locktime' => $cl_lock_interval))) {
+    header('Location: time.php');
+    exit();
+  } else {
+    $err->add($i18n->getKey('error.db'));
+  }
+} // isPost
+
+$smarty->assign('forms', array($form->getName()=>$form->toArray()));
+$smarty->assign('title', $i18n->getKey('title.locking'));
+$smarty->assign('content_page_name', 'locking.tpl');
+$smarty->display('index.tpl');
index 8b20cac..ab0ada0 100644 (file)
@@ -183,14 +183,6 @@ if ($custom_fields && $custom_fields->fields[0]) {
   }
 }
 
-// Determine lock date. Time entries earlier than lock date cannot be created or modified. 
-$lock_interval = $user->lock_interval;
-$lockdate = 0;
-if ($lock_interval > 0) {
-  $lockdate = new DateAndTime();
-  $lockdate->decDay($lock_interval);
-}
-
 // Submit.
 if ($request->isPost()) {
   if ($request->getParameter('btn_submit')) {
@@ -241,8 +233,8 @@ if ($request->isPost()) {
         $err->add($i18n->getKey('error.future_date'));
     }
 
-    // Prohibit creating time entries in locked interval.
-    if($lockdate && $selected_date->before($lockdate))
+    // Prohibit creating entries in locked range.
+    if ($user->isDateLocked($selected_date))
       $err->add($i18n->getKey('error.period_locked'));
 
     // Prohibit creating another uncompleted record.
index 9e818e7..e9f0e22 100644 (file)
@@ -38,12 +38,6 @@ if (!ttAccessCheck(right_data_entry)) {
   exit();
 }
 
-// Use Custom Fields plugin if we have one.
-// if (file_exists("plugins/CustomFields.class.php")) {
-//   require_once("plugins/CustomFields.class.php");
-//   $custom_fields = new CustomFields($user->team_id);
-// }
-
 $cl_id = $request->getParameter('id');
 $time_rec = ttTimeHelper::getRecord($cl_id, $user->getActiveUser());
 
@@ -59,19 +53,11 @@ if ($request->isPost()) {
     // Determine if it's okay to delete the record.
     $item_date = new DateAndTime(DB_DATEFORMAT, $time_rec['date']);
 
-    // Determine lock date.
-    $lock_interval = $user->lock_interval;
-    $lockdate = 0;
-    if ($lock_interval > 0) {
-      $lockdate = new DateAndTime();
-      $lockdate->decDay($lock_interval);
-    }
     // Determine if the record is uncompleted.
     $uncompleted = ($time_rec['duration'] == '0:00');
 
-    if($lockdate && $item_date->before($lockdate) && !$uncompleted) {
+    if ($user->isDateLocked($item_date) && !$uncompleted)
       $err->add($i18n->getKey('error.period_locked'));
-    }
 
     if ($err->no()) {
 
index 052ec1f..cce9946 100644 (file)
@@ -249,14 +249,6 @@ if ($request->isPost()) {
   if (!ttValidString($cl_note, true)) $err->add($i18n->getKey('error.field'), $i18n->getKey('label.note'));
   // Finished validating user input.
 
-  // Determine lock date.
-  $lock_interval = $user->lock_interval;
-  $lockdate = 0;
-  if ($lock_interval > 0) {
-    $lockdate = new DateAndTime();
-    $lockdate->decDay($lock_interval);
-  }
-
   // This is a new date for the time record.
   $new_date = new DateAndTime($user->date_format, $cl_date);
 
@@ -270,18 +262,20 @@ if ($request->isPost()) {
   // Save record.
   if ($request->getParameter('btn_save')) {
     // We need to:
-    // 1) Prohibit saving locked time entries in any form.
-    // 2) Prohibit saving completed unlocked entries into locked interval.
+    // 1) Prohibit saving locked entries in any form.
+    // 2) Prohibit saving completed unlocked entries into locked range.
     // 3) Prohibit saving uncompleted unlocked entries when another uncompleted entry exists.
 
     // Now, step by step.
     if ($err->no()) {
-      // 1) Prohibit saving locked time entries in any form.
-      if($lockdate && $item_date->before($lockdate))
+      // 1) Prohibit saving locked entries in any form.
+      if ($user->isDateLocked($item_date))
         $err->add($i18n->getKey('error.period_locked'));
-      // 2) Prohibit saving completed unlocked entries into locked interval.
-      if($err->no() && $lockdate && $new_date->before($lockdate))
+
+      // 2) Prohibit saving completed unlocked entries into locked range.
+      if ($err->no() && $user->isDateLocked($new_date))
         $err->add($i18n->getKey('error.period_locked'));
+
       // 3) Prohibit saving uncompleted unlocked entries when another uncompleted entry exists.
       $uncompleted = ($cl_finish == '' && $cl_duration == '');
       if ($uncompleted) {
index e538fce..d446574 100644 (file)
@@ -53,7 +53,6 @@ if ($request->isPost()) {
     $cl_address = trim($request->getParameter('address'));
     $cl_currency = trim($request->getParameter('currency'));
     if (!$cl_currency) $cl_currency = CURRENCY_DEFAULT;
-    $cl_lock_interval = $request->getParameter('lock_interval');
     $cl_lang = $request->getParameter('lang');
     $cl_decimal_mark = $request->getParameter('decimal_mark');
     $cl_custom_format_date = $request->getParameter('format_date');
@@ -69,6 +68,7 @@ if ($request->isPost()) {
     $cl_expenses = $request->getParameter('expenses');
     $cl_tax_expenses = $request->getParameter('tax_expenses');
     $cl_notifications = $request->getParameter('notifications');
+    $cl_locking = $request->getParameter('locking');
   }
 } else {
   $cl_name = $user->name;
@@ -78,7 +78,6 @@ if ($request->isPost()) {
     $cl_team = $user->team;
     $cl_address = $user->address;
     $cl_currency = ($user->currency == ''? CURRENCY_DEFAULT : $user->currency);
-    $cl_lock_interval = $user->lock_interval;
     $cl_lang = $user->lang;
     $cl_decimal_mark = $user->decimal_mark;
     $cl_custom_format_date = $user->date_format;
@@ -97,6 +96,7 @@ if ($request->isPost()) {
     $cl_expenses = in_array('ex', $plugins);
     $cl_tax_expenses = in_array('et', $plugins);
     $cl_notifications = in_array('no', $plugins);
+    $cl_locking = in_array('lk', $plugins);
   }
 }
 
@@ -115,7 +115,6 @@ if ($user->canManageTeam()) {
   $DECIMAL_MARK_OPTIONS = array(array('id'=>'.','name'=>'.'),array('id'=>',','name'=>','));
   $form->addInput(array('type'=>'combobox','name'=>'decimal_mark','style'=>'width: 150px','data'=>$DECIMAL_MARK_OPTIONS,'datakeys'=>array('id','name'),'value'=>$cl_decimal_mark,
     'onchange'=>'adjustDecimalPreview()'));
-  $form->addInput(array('type'=>'text','maxlength'=>'10','name'=>'lock_interval','value'=>$cl_lock_interval));
   // Prepare an array of available languages.
   $lang_files = I18n::getLangFileList();
   foreach ($lang_files as $lfile) {
@@ -176,6 +175,7 @@ if ($user->canManageTeam()) {
   $form->addInput(array('type'=>'checkbox','name'=>'expenses','data'=>1,'value'=>$cl_expenses,'onchange'=>'handlePluginCheckboxes()'));
   $form->addInput(array('type'=>'checkbox','name'=>'tax_expenses','data'=>1,'value'=>$cl_tax_expenses));
   $form->addInput(array('type'=>'checkbox','name'=>'notifications','data'=>1,'value'=>$cl_notifications,'onchange'=>'handlePluginCheckboxes()'));
+  $form->addInput(array('type'=>'checkbox','name'=>'locking','data'=>1,'value'=>$cl_locking,'onchange'=>'handlePluginCheckboxes()'));
 }
 $form->addInput(array('type'=>'submit','name'=>'btn_save','value'=>$i18n->getKey('button.save')));
 
@@ -228,13 +228,14 @@ if ($request->isPost()) {
         $plugins .= ',et';
       if ($cl_notifications)
         $plugins .= ',no';
+      if ($cl_locking)
+        $plugins .= ',lk';
       $plugins = trim($plugins, ',');
 
       $update_result = ttTeamHelper::update($user->team_id, array(
         'name' => $cl_team,
         'address' => $cl_address,
         'currency' => $cl_currency,
-        'locktime' => $cl_lock_interval,
         'lang' => $cl_lang,
         'decimal_mark' => $cl_decimal_mark,
         'date_format' => $cl_custom_format_date,
index 047556b..f6e4b71 100644 (file)
--- a/time.php
+++ b/time.php
@@ -204,14 +204,6 @@ if ($custom_fields && $custom_fields->fields[0]) {
   }
 }
 
-// Determine lock date. Time entries earlier than lock date cannot be created or modified.
-$lock_interval = $user->lock_interval;
-$lockdate = 0;
-if ($lock_interval > 0) {
-  $lockdate = new DateAndTime();
-  $lockdate->decDay($lock_interval);
-}
-
 // Submit.
 if ($request->isPost()) {
   if ($request->getParameter('btn_submit')) {
@@ -262,8 +254,8 @@ if ($request->isPost()) {
         $err->add($i18n->getKey('error.future_date'));
     }
 
-    // Prohibit creating time entries in locked interval.
-    if($lockdate && $selected_date->before($lockdate))
+    // Prohibit creating entries in locked range.
+    if ($user->isDateLocked($selected_date))
       $err->add($i18n->getKey('error.period_locked'));
 
     // Prohibit creating another uncompleted record.
index 273cba3..4e2f99a 100644 (file)
@@ -52,19 +52,12 @@ if ($request->isPost()) {
 
     // Determine if it's okay to delete the record.
     $item_date = new DateAndTime(DB_DATEFORMAT, $time_rec['date']);
-    // Determine lock date.
-    $lock_interval = $user->lock_interval;
-    $lockdate = 0;
-    if ($lock_interval > 0) {
-      $lockdate = new DateAndTime();
-      $lockdate->decDay($lock_interval);
-    }
+
     // Determine if the record is uncompleted.
     $uncompleted = ($time_rec['duration'] == '0:00');
 
-    if($lockdate && $item_date->before($lockdate) && !$uncompleted) {
+    if ($user->isDateLocked($item_date) && !$uncompleted)
       $err->add($i18n->getKey('error.period_locked'));
-    }
 
     if ($err->no()) {
 
index a3421a8..8287597 100644 (file)
@@ -250,14 +250,6 @@ if ($request->isPost()) {
   if (!ttValidString($cl_note, true)) $err->add($i18n->getKey('error.field'), $i18n->getKey('label.note'));
   // Finished validating user input.
 
-  // Determine lock date.
-  $lock_interval = $user->lock_interval;
-  $lockdate = 0;
-  if ($lock_interval > 0) {
-    $lockdate = new DateAndTime();
-    $lockdate->decDay($lock_interval);
-  }
-
   // This is a new date for the time record.
   $new_date = new DateAndTime($user->date_format, $cl_date);
 
@@ -277,12 +269,14 @@ if ($request->isPost()) {
 
     // Now, step by step.
     if ($err->no()) {
-      // 1) Prohibit saving locked time entries in any form.
-      if($lockdate && $item_date->before($lockdate))
+      // 1) Prohibit saving locked entries in any form.
+      if ($user->isDateLocked($item_date))
         $err->add($i18n->getKey('error.period_locked'));
-      // 2) Prohibit saving completed unlocked entries into locked interval.
-      if($err->no() && $lockdate && $new_date->before($lockdate))
+
+      // 2) Prohibit saving completed unlocked entries into locked range.
+      if ($err->no() && $user->isDateLocked($new_date))
         $err->add($i18n->getKey('error.period_locked'));
+
       // 3) Prohibit saving uncompleted unlocked entries when another uncompleted entry exists.
       $uncompleted = ($cl_finish == '' && $cl_duration == '');
       if ($uncompleted) {
@@ -333,14 +327,15 @@ if ($request->isPost()) {
   // Save as new record.
   if ($request->getParameter('btn_copy')) {
     // We need to:
-    // 1) Prohibit saving into locked interval.
+    // 1) Prohibit saving into locked range.
     // 2) Prohibit saving uncompleted unlocked entries when another uncompleted entry exists.
 
     // Now, step by step.
     if ($err->no()) {
-      // 1) Prohibit saving into locked interval.
-      if($lockdate && $new_date->before($lockdate))
+      // 1) Prohibit saving into locked range.
+      if ($user->isDateLocked($new_date))
         $err->add($i18n->getKey('error.period_locked'));
+
       // 2) Prohibit saving uncompleted unlocked entries when another uncompleted entry exists.
       $uncompleted = ($cl_finish == '' && $cl_duration == '');
       if ($uncompleted) {