Skip to content
This repository has been archived by the owner on Dec 27, 2023. It is now read-only.

Commit

Permalink
feature(DFCom): support customer specific pt account
Browse files Browse the repository at this point in the history
  • Loading branch information
corneliusweiss committed Mar 9, 2023
1 parent 35ce12d commit ad9111d
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 43 deletions.
27 changes: 27 additions & 0 deletions tine20/DFCom/Config.php
Expand Up @@ -35,6 +35,8 @@ class DFCom_Config extends Tinebase_Config_Abstract

const DFCOM_ID_TYPE = 'dfcomIdType';

const DEVICE_LISTE_PERCENTAGE = 'DeviceListPercentage';

/**
* (non-PHPdoc)
* @see tine20/Tinebase/Config/Definition::$_properties
Expand Down Expand Up @@ -72,6 +74,31 @@ class DFCom_Config extends Tinebase_Config_Abstract
'default' => 0
]
],
self::DEVICE_LISTE_PERCENTAGE => [
//_('Device List Percentage')
'label' => 'Device List Percentage',
//_('Device list with Percentage entries.')
'description' => 'Device list with Percentage entries.',
'type' => Tinebase_Config_Abstract::TYPE_KEYFIELD_CONFIG,
'clientRegistryInclude' => false,
'setByAdminModule' => true,
'default' => [
'records' => array(
['id' => ' 0', 'value' => ' 0 %',],
['id' => ' 10', 'value' => ' 10 %',],
['id' => ' 20', 'value' => ' 20 %',],
['id' => ' 30', 'value' => ' 30 %',],
['id' => ' 40', 'value' => ' 40 %',],
['id' => ' 50', 'value' => ' 50 %',],
['id' => ' 60', 'value' => ' 60 %',],
['id' => ' 70', 'value' => ' 70 %',],
['id' => ' 80', 'value' => ' 80 %',],
['id' => ' 90', 'value' => ' 90 %',],
['id' => '100', 'value' => '100 %',],
),
'default' => 0
]
],
self::SETUP_AUTH_KEY => [
//_('Initial AuthKey for Device Setup')
'label' => 'Initial AuthKey for Device Setup',
Expand Down
3 changes: 2 additions & 1 deletion tine20/DFCom/Controller/Device.php
Expand Up @@ -192,10 +192,11 @@ public function dispatchRecord()
break;
case 'listFeedback':
$lists = $deviceListController->getDeviceLists($device);
$listName = explode(',', $deviceRecord->data['detail1'])[0];
/** @var DFCom_Model_DeviceList $list */
foreach($lists as $list) {
// NOTE: device can't signal for which list the feedback was
if ($list->list_status == -1) {
if ($list->name === $listName) {
$list->list_status = $deviceRecord->xprops('data')['reason'];
$deviceListController->update($list);
if ($list->controlCommands) {
Expand Down
86 changes: 59 additions & 27 deletions tine20/DFCom/Controller/DeviceList.php
Expand Up @@ -72,14 +72,28 @@ public function createDefaultDeviceLists(DFCom_Model_Device $device)
$defaultListNames = DFCom_Config::getInstance()->get(DFCom_Config::DEFAULT_DEVICE_LISTS);

foreach($defaultListNames as $listName) {
$exportDefinition = Tinebase_ImportExportDefinition::getInstance()->getByName($listName);
$options = Tinebase_ImportExportDefinition::getInstance()->getOptionsAsZendConfigXml($exportDefinition);
$createdLists->addRecord($this->create(new DFCom_Model_DeviceList([
'device_id' => $device->getId(),
'name' => $options->deviceName,
'export_definition_id' => $exportDefinition->getId(),
'controlCommands' => $options->controlCommands,
])));
try {
$exportDefinition = Tinebase_ImportExportDefinition::getInstance()->getByName($listName);
$options = Tinebase_ImportExportDefinition::getInstance()->getOptionsAsZendConfigXml($exportDefinition);
$deviceList = new DFCom_Model_DeviceList([
'device_id' => $device->getId(),
'name' => $options->deviceName,
'export_definition_id' => $exportDefinition->getId(),
'controlCommands' => $options->controlCommands,
]);
} catch (Exception $e) {
$deviceName = preg_match('/^keyField_/', $listName) ?
strtolower(str_replace('DeviceList', '', explode('_', $listName)[2]))
: $listName;

$deviceList = new DFCom_Model_DeviceList([
'device_id' => $device->getId(),
'name' => $deviceName,
'export_definition_id' => $listName,
]);
}

$createdLists->addRecord($this->create($deviceList));
}

return $createdLists;
Expand Down Expand Up @@ -134,23 +148,35 @@ public function getDeviceList($deviceId, $listId, $authKey)
return $response;
}

/** @var Tinebase_Export_CsvNew $export */
$export = Tinebase_Export::factory(null, [
'definitionId' => $deviceList->export_definition_id,
'charset' => str_replace(' ', '-', $request
->getHeader('Accept-Charset')
->getFieldValue()),
'ignoreACL' => true,
]);
$export->generate();

$responseStream = fopen('php://memory', 'w');
$export->write($responseStream);

if(preg_match('/^keyField_/', $deviceList->export_definition_id)) {
try {
[, $appName, $keyFieldName] = explode('_', $deviceList->export_definition_id);
$config = Tinebase_Config::getAppConfig($appName)->$keyFieldName;
foreach($config->records as $record) {
Tinebase_Export_CsvNew::fputcsv($responseStream, array_values($record->toArray()), "\t", '');
};
} catch (Exception $e) {
$response = new \Zend\Diactoros\Response('php://memory', 404);
$response->getBody()->write('keyField '. $deviceList->name. ' not found!');
return $response;
}
} else {
/** @var Tinebase_Export_CsvNew $export */
$export = Tinebase_Export::factory(null, [
'definitionId' => $deviceList->export_definition_id,
'charset' => str_replace(' ', '-', $request
->getHeader('Accept-Charset')
->getFieldValue()),
'ignoreACL' => true,
]);
$export->generate();
$export->write($responseStream);
}

$deviceList->list_version = $this->getSyncToken($deviceList);
$deviceList->list_status = -1;
$deviceList->list_version = Tinebase_FilterSyncToken::getInstance()
->getFilterSyncToken($export->getFilter(), $export->getController());

$this->update($deviceList);

$device->lastSeen = Tinebase_DateTime::now();
Expand Down Expand Up @@ -201,10 +227,16 @@ public function getDeviceLists(DFCom_Model_Device $device)
*/
public function getSyncToken($deviceList)
{
$export = Tinebase_Export::factory(null, [
'definitionId' => $deviceList->export_definition_id,
'ignoreACL' => true,
]);
return Tinebase_FilterSyncToken::getInstance()->getFilterSyncToken($export->getFilter(), $export->getController());
if(preg_match('/^keyField_/', $deviceList->export_definition_id)) {
[, $appName, $keyFieldName] = explode('_', $deviceList->export_definition_id);
$config = Tinebase_Config::getAppConfig($appName)->$keyFieldName;
return sha1(print_r($config->records->toArray(), true));
} else {
$export = Tinebase_Export::factory(null, [
'definitionId' => $deviceList->export_definition_id,
'ignoreACL' => true,
]);
return Tinebase_FilterSyncToken::getInstance()->getFilterSyncToken($export->getFilter(), $export->getController());
}
}
}
5 changes: 3 additions & 2 deletions tine20/DFCom/Model/DeviceResponse.php
Expand Up @@ -96,7 +96,8 @@ public function setDeviceVariable($name, $value)
if ($name == 'setupVersion') {
throw new Tinebase_Exception_InvalidArgument('setupVersion can only be set in setup!');
}
$this->_responseData['df_var'] = "setup.$name," . urlencode($value);
// NOTE: No urlencode here for some reason device doesn't decode
$this->_responseData['df_var'] = "setup.$name," . $value;

return $this;
}
Expand Down Expand Up @@ -148,7 +149,7 @@ public function triggerEventChain($name)
*/
public function displayMessage($message, $duration=5, $beep=self::BEEP_SHORTLONG, $font=self::FONT_STANDARD)
{
$this->_responseData['df_msg'] = implode(',', [rawurlencode($message), $duration, $beep, $font]);
$this->_responseData['df_msg'] = implode(',', [rawurlencode(utf8_decode($message)), $duration, $beep, $font]);
return $this;
}

Expand Down
18 changes: 13 additions & 5 deletions tine20/DFCom/RecordHandler/TimeAccounting.php
Expand Up @@ -26,7 +26,11 @@ class DFCom_RecordHandler_TimeAccounting
const XPROP_TIMESHEET_ID = self::class . '::timesheet_id';
const XPROP_UNKNOWN_CARD_ID = self::class . '::unknown_card_id';

protected $dateTime;
protected $device;
/**
* @var DFCom_Model_DeviceResponse
*/
protected $deviceResponse;
protected $deviceRecord;
protected $deviceData;
Expand Down Expand Up @@ -77,8 +81,8 @@ public function handle()
];
// end attention

$dateTime = new Tinebase_DateTime($this->deviceData['dateTime'], $this->device->timezone);
$dateTime->setTimezone('UTC');
$this->dateTime = new Tinebase_DateTime($this->deviceData['dateTime'], $this->device->timezone);
$this->dateTime->setTimezone('UTC');

$this->currentUser = null;
$result = null;
Expand All @@ -100,6 +104,7 @@ public function handle()
$this->currentUser = Tinebase_Core::getUser();
$this->user = Tinebase_Core::setUser(Tinebase_User::getInstance()->getUserById($this->employee->account_id, Tinebase_Model_FullUser::class));

$result = $this->onBeforeHandleTimeAccounting();
switch ($this->deviceData['functionKey']) {
case self::FUNCTION_KEY_PROJECT:
if ($this->deviceData['functionValue'] === 'QUERY') {
Expand All @@ -115,13 +120,13 @@ public function handle()
HumanResources_Model_AttendanceRecorderDevice::SYSTEM_PROJECT_TIME_ID);
$cfg = (new HumanResources_Config_AttendanceRecorder())
->setMetaData([
HumanResources_Model_AttendanceRecord::CLOCK_OUT_OTHERS => 1,
HumanResources_Config_AttendanceRecorder::METADATA_SOURCE => __METHOD__,
Timetracker_Model_Timeaccount::class => $this->deviceData['functionValue']
])
->setDevice($device)
->setEmployee($this->employee)
->setAccount(Tinebase_User::getInstance()->getFullUserById($this->employee->account_id))
->setTimeStamp($dateTime);
->setTimeStamp($this->dateTime);

HumanResources_Controller_AttendanceRecorder::getInstance()->clockIn($cfg);
break;
Expand All @@ -142,7 +147,7 @@ public function handle()
->setDevice($device)
->setEmployee($this->employee)
->setAccount(Tinebase_User::getInstance()->getFullUserById($this->employee->account_id))
->setTimeStamp($dateTime);
->setTimeStamp($this->dateTime);

if (self::FUNCTION_KEY_CLOCKIN === $this->deviceData['functionKey']) {
HumanResources_Controller_AttendanceRecorder::getInstance()->clockIn($cfg);
Expand Down Expand Up @@ -213,6 +218,9 @@ public function handle()
return (bool)$result;
}

// template fn
protected function onBeforeHandleTimeAccounting() {}

public function createTimesheet($date, $functionKey = self::FUNCTION_KEY_CLOCKIN)
{
return $this->timesheetController->create(new Timetracker_Model_Timesheet([
Expand Down
1 change: 1 addition & 0 deletions tine20/DFCom/Setup/Initialize.php
Expand Up @@ -39,6 +39,7 @@ protected function _initializeDefaultDeviceLists()
'DFCom_device_list_employee',
'DFCom_device_list_absenceReasons',
'DFCom_device_list_timeaccounts',
'keyField_DFCom_DeviceListPercentage',
]);
}

Expand Down
18 changes: 12 additions & 6 deletions tine20/HumanResources/BL/AttendanceRecorder/TimeSheet.php
Expand Up @@ -161,7 +161,7 @@ public function execute(Tinebase_BL_PipeContext $_context, Tinebase_BL_DataInter
'note_type_id' => Tinebase_Model_Note::SYSTEM_NOTE_NAME_NOTE,
]));
if (empty($absenceTS->description)) {
$absenceTS->description = Tinebase_Translation::getTranslation(HumanResources_Config::APP_NAME)->_('attendance recorder generated');
$absenceTS->description = self::getTSDescription($record);
}

if ($absenceTS->getId()) {
Expand Down Expand Up @@ -242,7 +242,7 @@ protected function updateTimeSheet(Tinebase_Record_RecordSet $tsRs, HumanResourc

foreach ($tsRs as $ts) {
if (empty($ts->description)) {
$ts->description = Tinebase_Translation::getTranslation(HumanResources_Config::APP_NAME)->_('attendance recorder generated');
$ts->description = self::getTSDescription($record);
}
if (empty($ts->notes) || is_array($ts->notes)) {
$ts->notes = new Tinebase_Record_RecordSet(Tinebase_Model_Note::class,
Expand All @@ -261,7 +261,7 @@ protected function updateTimeSheet(Tinebase_Record_RecordSet $tsRs, HumanResourc
$lastTs->end_time = null;
$lastTs->duration = 0;
$lastTs->start_date->addDay(1);
$lastTs->description = Tinebase_Translation::getTranslation(HumanResources_Config::APP_NAME)->_('attendance recorder generated');
$lastTs->description = self::getTSDescription($record);
$lastTs->notes = null;
$tsRs->addRecord($lastTs = Timetracker_Controller_Timesheet::getInstance()->create($lastTs));
$lastTs->notes = new Tinebase_Record_RecordSet(Tinebase_Model_Note::class);
Expand Down Expand Up @@ -292,7 +292,7 @@ protected function updateTimeSheet(Tinebase_Record_RecordSet $tsRs, HumanResourc
'end_time' => $startDate->format('H:i:00'),
'duration' => 0,
HumanResources_Model_FreeTimeType::TT_TS_SYSCF_ABSENCE_REASON => $fttId,
'description' => Tinebase_Translation::getTranslation(HumanResources_Config::APP_NAME)->_('attendance recorder generated'),
'description' => self::getTSDescription($record),
'notes' => new Tinebase_Record_RecordSet(Tinebase_Model_Note::class, [
new Tinebase_Model_Note([
'note' => sprintf(Tinebase_Translation::getTranslation(HumanResources_Config::APP_NAME)->_('Clock in: %1$s'), $startDate->format('H:i:s')),
Expand Down Expand Up @@ -576,8 +576,7 @@ protected function createTimeSheet(HumanResources_Model_AttendanceRecord $record
'end_time' => $date->format('H:i:00'),
'duration' => 0,
'notes' => new Tinebase_Record_RecordSet(Tinebase_Model_Note::class),
'description' => Tinebase_Translation::getTranslation(HumanResources_Config::APP_NAME)
->_('attendance recorder generated'),
'description' => self::getTSDescription($record),
], true);

$note = sprintf($translate->_($type ?
Expand Down Expand Up @@ -607,6 +606,13 @@ protected function createTimeSheet(HumanResources_Model_AttendanceRecord $record
return $ts;
}

public static function getTSDescription(HumanResources_Model_AttendanceRecord $record): string
{
return isset($record->xprops()[HumanResources_Model_AttendanceRecord::META_DATA][HumanResources_Config_AttendanceRecorder::METADATA_TS_DESCRIPTION]) ?
$record->xprops()[HumanResources_Model_AttendanceRecord::META_DATA][HumanResources_Config_AttendanceRecorder::METADATA_TS_DESCRIPTION] :
Tinebase_Translation::getTranslation(HumanResources_Config::APP_NAME)->_('attendance recorder generated');
}

public function undo(Tinebase_Record_RecordSet $data): void
{
if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__);
Expand Down
1 change: 1 addition & 0 deletions tine20/HumanResources/Config/AttendanceRecorder.php
Expand Up @@ -3,6 +3,7 @@
class HumanResources_Config_AttendanceRecorder
{
public const METADATA_SOURCE = 'source';
public const METADATA_TS_DESCRIPTION = 'ts_description';

protected $account;
protected $autoGen = false;
Expand Down
4 changes: 2 additions & 2 deletions tine20/HumanResources/js/AttendanceRecorder.js
Expand Up @@ -456,7 +456,7 @@ const attendanceRecorder = Ext.extend(Ext.Button, {
if (el && !Ext.fly(el).hasClass('x-item-disabled')) {
const row = this.menu.timeAccountPickerGrid.view.findRowIndex(el);
const timeAccount = this.menu.timeAccountPickerGrid.store.getAt(row);
const timesheet = _.get(timeAccount, `data.xprops.HumanResources_Model_AttendanceRecord.bottom.xprops.metaData.Timetracker_Model_Timesheet`);
const timesheet = { id: _.get(timeAccount, `data.xprops.HumanResources_Model_AttendanceRecord.bottom.xprops.metaData.Timetracker_Model_Timesheet.id[0]`) };
const action = el.dataset.action;
const multiStart = e.ctrlKey || e.shiftKey;

Expand All @@ -467,7 +467,7 @@ const attendanceRecorder = Ext.extend(Ext.Button, {

let result;
const openTimesheet = (timeAccount) => {
const timesheet = _.get(timeAccount, `data.xprops.HumanResources_Model_AttendanceRecord.bottom.xprops.metaData.Timetracker_Model_Timesheet`);
const timesheet = { id: _.get(timeAccount, `data.xprops.HumanResources_Model_AttendanceRecord.bottom.xprops.metaData.Timetracker_Model_Timesheet.id[0]`) };
Tine.Timetracker.TimesheetEditDialog.openWindow({
record: timesheet,
contentPanelConstructorInterceptor: async (config) => {
Expand Down
3 changes: 3 additions & 0 deletions tine20/HumanResources/translations/de.po
Expand Up @@ -128,6 +128,9 @@ msgstr "Allen Arbeitszeiten unabhängig der Abteilungsrechte managen."
msgid "Clock in: %1$s"
msgstr "Einstemplen: %1$s"

msgid "attendance recorder generated"
msgstr "Angelegt durch die Stempeluhr"

#: BL/AttendanceRecorder/TimeSheet.php:241
#: BL/AttendanceRecorder/TimeSheet.php:246
msgid "Clock out: %1$s"
Expand Down

0 comments on commit ad9111d

Please sign in to comment.