tine20/HumanResources/Controller/MonthlyWTReport.php
Rama main · réplica de lectura del repositorio original.
<?php
/**
* MonthlyWorkingTimeReport controller for HumanResources application
*
* @package HumanResources
* @subpackage Controller
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Paul Mehrer <p.mehrer@metaways.de>
* @copyright Copyright (c) 2019-2022 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
/**
* MonthlyWorkingTimeReport controller class for HumanResources application
*
* @package HumanResources
* @subpackage Controller
*/
class HumanResources_Controller_MonthlyWTReport extends Tinebase_Controller_Record_Abstract
{
/** @use Tinebase_Controller_SingletonTrait<HumanResources_Controller_MonthlyWTReport> */
use Tinebase_Controller_SingletonTrait;
use HumanResources_Controller_CheckFilterACLEmployeeTrait;
const RC_JSON_REQUEST = 'jsonRequest';
protected $_getMultipleGrant = [HumanResources_Model_DivisionGrants::READ_TIME_DATA];
protected $_requiredFilterACLget = [HumanResources_Model_DivisionGrants::READ_TIME_DATA];
protected $_requiredFilterACLupdate = [HumanResources_Model_DivisionGrants::UPDATE_TIME_DATA];
protected $_requiredFilterACLsync = [HumanResources_Model_DivisionGrants::READ_TIME_DATA];
protected $_requiredFilterACLexport = [HumanResources_Model_DivisionGrants::READ_TIME_DATA];
protected $allowCorrectionUpdate = false;
/**
* the constructor
*
* don't use the constructor. use the singleton
*/
protected function __construct()
{
$this->_applicationName = HumanResources_Config::APP_NAME;
$this->_modelName = HumanResources_Model_MonthlyWTReport::class;
$this->_backend = new Tinebase_Backend_Sql(array(
'modelName' => $this->_modelName,
'tableName' => HumanResources_Model_MonthlyWTReport::TABLE_NAME,
'modlogActive' => true
));
$this->_purgeRecords = false;
$this->_resolveCustomFields = true;
$this->_doContainerACLChecks = true;
$this->_traitCheckFilterACLRight = HumanResources_Acl_Rights::MANAGE_WORKINGTIME;
}
protected function _checkGrant($_record, $_action, $_throw = TRUE, $_errorMessage = 'No Permission.', $_oldRecord = NULL)
{
if (!$this->_doContainerACLChecks) {
return true;
}
// if we have manage_employee right, we have all grants
if (Tinebase_Core::getUser()->hasRight(HumanResources_Config::APP_NAME, HumanResources_Acl_Rights::MANAGE_WORKINGTIME)) {
return true;
}
switch ($_action) {
case self::ACTION_GET:
try {
HumanResources_Controller_Employee::getInstance()->get($_record->getIdFromProperty('employee_id'));
} catch (Tinebase_Exception_AccessDenied $e) {
if ($_throw) {
throw new Tinebase_Exception_AccessDenied($_errorMessage);
} else {
return false;
}
}
return true;
case self::ACTION_CREATE:
case self::ACTION_UPDATE:
case self::ACTION_DELETE:
$_action = HumanResources_Model_DivisionGrants::UPDATE_TIME_DATA;
break;
}
return parent::_checkGrant($_record, $_action, $_throw, $_errorMessage, $_oldRecord);
}
/**
* @param string|HumanResources_Model_Employee $employeeId
* @param string|DateTime $month default current year
* @return HumanResources_Model_MonthlyWTReport|NULL
* @throws Tinebase_Exception_InvalidArgument
*
* maybe @deprecated
*/
public function getByEmployeeMonth($employeeId, $month = null)
{
$employeeId = !($employeeId instanceof HumanResources_Model_Employee) ?: $employeeId->getId();
$month = $month ?: Tinebase_DateTime::now();
$month = !($month instanceof DateTime) ?: $month->format('Y-m');
// find account
$filter = Tinebase_Model_Filter_FilterGroup::getFilterForModel(HumanResources_Model_MonthlyWTReport::class, [
['field' => HumanResources_Model_MonthlyWTReport::FLDS_MONTH, 'operator' => 'equals', 'value' => $month],
['field' => HumanResources_Model_MonthlyWTReport::FLDS_EMPLOYEE_ID , 'operator' => 'equals', 'value' => $employeeId]
]);
return $this->search($filter)->getFirstRecord();
}
/**
* will recalculate the given monthly report and all reports that exist after the given one
*
* @param HumanResources_Model_MonthlyWTReport $_monthlyWTR
*/
public function recalculateReport(HumanResources_Model_MonthlyWTReport $_monthlyWTR,
?\HumanResources_Model_MonthlyWTReport $_previousMonthlyWTR = null)
{
$transaction = new Tinebase_TransactionManager_Handle();
if (null === $_previousMonthlyWTR) {
$_previousMonthlyWTR = $this->getPreviousMonthlyWTR($_monthlyWTR);
}
$rs = new Tinebase_Record_RecordSet(HumanResources_Model_MonthlyWTReport::class, [$_monthlyWTR]);
Tinebase_ModelConfiguration::resolveRecordsPropertiesForRecordSet($rs,
HumanResources_Model_MonthlyWTReport::getConfiguration());
$_monthlyWTR->dailywtreports->sort('date');
$currentRecord = clone $_monthlyWTR;
$firstDay = $_monthlyWTR->dailywtreports->getFirstRecord();
if (null !== $_previousMonthlyWTR) {
$_monthlyWTR->working_time_balance_previous = $_previousMonthlyWTR->working_time_balance;
if ($firstDay && (int)$firstDay->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE_PREVIOUS} !==
(int)$_previousMonthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE}) {
$firstDay->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE_PREVIOUS} =
(int)$_previousMonthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE};
}
} else {
$_monthlyWTR->working_time_balance_previous = 0;
if ($firstDay && 0 !== (int)$firstDay->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE_PREVIOUS}) {
$firstDay->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE_PREVIOUS} = 0;
}
}
$isTime = 0;
$shouldTime = 0;
$prevDay = null;
/** @var HumanResources_Model_DailyWTReport $dailyWTR */
foreach ($_monthlyWTR->dailywtreports as $dailyWTR) {
$is = $dailyWTR->getIsWorkingTime();
$should = $dailyWTR->getShouldWorkingTime();
if ($prevDay && (int)$dailyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE_PREVIOUS}
!== (int)$prevDay->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE}) {
$dailyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE_PREVIOUS} =
(int)$prevDay->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE};
}
$balance = $is - $should +
$dailyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE_PREVIOUS};
if ($balance !== (int)$dailyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE}) {
$dailyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE} = $balance;
}
if ($dailyWTR->isDirty()) {
HumanResources_Controller_DailyWTReport::getInstance()->update(clone $dailyWTR);
}
$isTime += $is;
$shouldTime += $should;
$prevDay = $dailyWTR;
}
$_monthlyWTR->working_time_actual = $isTime;
$_monthlyWTR->working_time_target = $shouldTime;
$_monthlyWTR->working_time_balance = $_monthlyWTR->working_time_balance_previous +
$_monthlyWTR->working_time_actual - $_monthlyWTR->working_time_target +
$_monthlyWTR->working_time_correction;
if ($_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_DAILY_WT_REPORTS}->getLastRecord() &&
(int)$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE} !==
(int)$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_DAILY_WT_REPORTS}->getLastRecord()
->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_BALANCE}
+ (int)$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_CORRECTION}) {
// well this is bad...
Tinebase_Exception::log(new Tinebase_Exception_UnexpectedValue(
'monthly balance mismatches last days balance for month ' .
$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_MONTH} . ' for employee '
. $_monthlyWTR->getIdFromProperty(HumanResources_Model_MonthlyWTReport::FLDS_EMPLOYEE_ID)));
$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_SYSTEM_REMARK} = 'balance of last day mismatches monthly balance';
} elseif (!empty($_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_SYSTEM_REMARK})) {
$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_SYSTEM_REMARK} =
str_replace('balance of last day mismatches monthly balance', '',
$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_SYSTEM_REMARK});
}
if (!$currentRecord->diff($_monthlyWTR)->isEmpty()) {
$_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_LAST_CALCULATION} = Tinebase_DateTime::now();
Tinebase_Timemachine_ModificationLog::getInstance()
->setRecordMetaData($_monthlyWTR, self::ACTION_UPDATE, $currentRecord);
$currentMods = $this->_writeModLog($_monthlyWTR, $currentRecord);
$this->_setSystemNotes($_monthlyWTR, Tinebase_Model_Note::SYSTEM_NOTE_NAME_CHANGED, $currentMods);
$_monthlyWTR = $this->_backend->update($_monthlyWTR);
}
if (null !== ($_nextMonthlyWTR = $this->getNextMonthlyWTR($_monthlyWTR))) {
$this->recalculateReport($_nextMonthlyWTR, $_monthlyWTR);
}
$transaction->commit();
}
/**
* @param HumanResources_Model_MonthlyWTReport $_monthlyWTR
* @return null|HumanResources_Model_MonthlyWTReport
*/
public function getNextMonthlyWTR(HumanResources_Model_MonthlyWTReport $_monthlyWTR)
{
$date = new Tinebase_DateTime($_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_MONTH}, 'UTC');
$date->addMonth(1);
return $this->search(
Tinebase_Model_Filter_FilterGroup::getFilterForModel(HumanResources_Model_MonthlyWTReport::class, [
['field' => HumanResources_Model_MonthlyWTReport::FLDS_EMPLOYEE_ID, 'operator' => 'equals',
'value' => $_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_EMPLOYEE_ID}],
['field' => HumanResources_Model_MonthlyWTReport::FLDS_MONTH, 'operator' => 'equals',
'value' => $date->format('Y-m')],
]))->getFirstRecord();
}
/**
* @param HumanResources_Model_MonthlyWTReport $_monthlyWTR
* @return null|HumanResources_Model_MonthlyWTReport
*/
public function getPreviousMonthlyWTR(HumanResources_Model_MonthlyWTReport $_monthlyWTR)
{
$date = new Tinebase_DateTime($_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_MONTH}, 'UTC');
$date->subMonth(1);
return $this->search(
Tinebase_Model_Filter_FilterGroup::getFilterForModel(HumanResources_Model_MonthlyWTReport::class, [
['field' => HumanResources_Model_MonthlyWTReport::FLDS_EMPLOYEE_ID, 'operator' => 'equals',
'value' => $_monthlyWTR->{HumanResources_Model_MonthlyWTReport::FLDS_EMPLOYEE_ID}],
['field' => HumanResources_Model_MonthlyWTReport::FLDS_MONTH, 'operator' => 'equals',
'value' => $date->format('Y-m')],
]))->getFirstRecord();
}
/**
* inspect creation of one record (before create)
*
* @param Tinebase_Record_Interface $_record
* @return void
*/
protected function _inspectBeforeCreate(Tinebase_Record_Interface $_record)
{
if (isset($this->_requestContext[self::RC_JSON_REQUEST])) {
// _("monthly wt reports can't be created")
throw new Tinebase_Exception_SystemGeneric("monthly wt reports can't be created", 600, HumanResources_Config::APP_NAME);
}
}
/**
* inspect update of one record (before update)
*
* @param HumanResources_Model_MonthlyWTReport $_record the update record
* @param HumanResources_Model_MonthlyWTReport $_oldRecord the current persistent record
* @return void
* @throws Tinebase_Exception_Record_NotAllowed
*/
protected function _inspectBeforeUpdate($_record, $_oldRecord)
{
parent::_inspectBeforeUpdate($_record, $_oldRecord);
if (isset($this->_requestContext[self::RC_JSON_REQUEST])) {
$allowedProperties = [
HumanResources_Model_MonthlyWTReport::FLDS_IS_CLEARED => true,
];
if ($this->allowCorrectionUpdate) {
$allowedProperties[HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_CORRECTION] = true;
}
foreach ($_record->getFields() as $prop) {
if (!isset($allowedProperties[$prop])) {
$_record->{$prop} = $_oldRecord->{$prop};
}
}
}
if ($_record->is_cleared && $_oldRecord->is_cleared) {
// _('It is not allowed to update a cleared report')
throw new Tinebase_Exception_SystemGeneric('It is not allowed to update a cleared report', 600, HumanResources_Config::APP_NAME);
}
}
/**
* inspect update of one record (after update)
*
* @param HumanResources_Model_MonthlyWTReport $updatedRecord the just updated record
* @param HumanResources_Model_MonthlyWTReport $record the update record
* @param HumanResources_Model_MonthlyWTReport $currentRecord the current record (before update)
* @return void
*/
protected function _inspectAfterUpdate($updatedRecord, $record, $currentRecord)
{
foreach ([
HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_CORRECTION,
] as $prop) {
if ($currentRecord->{$prop} !== $updatedRecord->{$prop}) {
$this->recalculateReport($updatedRecord);
break;
}
}
// set is_cleared
if ($updatedRecord->is_cleared && !$currentRecord->is_cleared) {
// previous month needs to be cleared first!
if (null !== ($prev = $this->getPreviousMonthlyWTR($updatedRecord)) && !$prev->is_cleared) {
// _('You need to clear the previous month first.')
throw new Tinebase_Exception_SystemGeneric('You need to clear the previous month first.', 600, HumanResources_Config::APP_NAME);
}
$rs = new Tinebase_Record_RecordSet(HumanResources_Model_MonthlyWTReport::class, [$updatedRecord]);
Tinebase_ModelConfiguration::resolveRecordsPropertiesForRecordSet($rs,
HumanResources_Model_MonthlyWTReport::getConfiguration());
$dailyCtrl = HumanResources_Controller_DailyWTReport::getInstance();
$dailyCtrl->setRequestContext([HumanResources_Controller_DailyWTReport::RC_ALLOW_IS_CLEARED => true]);
try {
foreach ($updatedRecord->dailywtreports as $dailyReport) {
$dailyReport->is_cleared = true;
$dailyCtrl->update($dailyReport);
}
} finally {
$dailyCtrl->setRequestContext([]);
}
// unset is_cleared
} elseif (!$updatedRecord->is_cleared && $currentRecord->is_cleared) {
// next month must not be cleared!
if (null !== ($next = $this->getNextMonthlyWTR($updatedRecord)) && $next->is_cleared) {
// _('You need to revert the clearing of the previous month first.')
throw new Tinebase_Exception_SystemGeneric('You need to revert the clearing of the previous month first.', 600, HumanResources_Config::APP_NAME);
}
$rs = new Tinebase_Record_RecordSet(HumanResources_Model_MonthlyWTReport::class, [$updatedRecord]);
Tinebase_ModelConfiguration::resolveRecordsPropertiesForRecordSet($rs,
HumanResources_Model_MonthlyWTReport::getConfiguration());
$dailyCtrl = HumanResources_Controller_DailyWTReport::getInstance();
$dailyCtrl->setRequestContext([HumanResources_Controller_DailyWTReport::RC_ALLOW_IS_CLEARED => true]);
try {
foreach ($updatedRecord->dailywtreports as $dailyReport) {
$dailyReport->is_cleared = false;
$dailyCtrl->update($dailyReport);
}
} finally {
$dailyCtrl->setRequestContext([]);
}
}
}
public function recalcCorrection(string $id)
{
$correction = 0;
foreach (HumanResources_Controller_WTRCorrection::getInstance()->search(
Tinebase_Model_Filter_FilterGroup::getFilterForModel(HumanResources_Model_WTRCorrection::class,[
['field' => HumanResources_Model_WTRCorrection::FLD_WTR_MONTHLY, 'operator' => 'equals', 'value' => $id],
['field' => HumanResources_Model_WTRCorrection::FLD_STATUS, 'operator' => 'equals', 'value' => HumanResources_Config::WTR_CORRECTION_STATUS_ACCEPTED],
])) as $c) {
$correction += intval($c->{HumanResources_Model_WTRCorrection::FLD_CORRECTION});
}
$oldAclVal = $this->doContainerACLChecks(false);
$oldCorrectionVal = $this->allowCorrectionUpdate;
$this->allowCorrectionUpdate = true;
$raii = new Tinebase_RAII(function() use($oldAclVal, $oldCorrectionVal) {
$this->doContainerACLChecks($oldAclVal);
$this->allowCorrectionUpdate = $oldCorrectionVal;
});
$record = $this->get($id);
if (intval($record->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_CORRECTION}) !== $correction) {
$record->{HumanResources_Model_MonthlyWTReport::FLDS_WORKING_TIME_CORRECTION} = $correction;
$this->update($record);
}
unset($raii);
}
}