work_time-1.0.x-dev/modules/fingerprint/src/Form/FingerprintImportForm.php
modules/fingerprint/src/Form/FingerprintImportForm.php
<?php
namespace Drupal\fingerprint\Form;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides fingerprint import attendance.
*/
class FingerprintImportForm extends FormBase implements ContainerInjectionInterface {
/**
* Entity display repository service.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
public $entityDisplayRepository;
/**
* Entity field manager service.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
public $entityFieldManager;
/**
* Entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
public $entityTypeManager;
/**
* {@inheritdoc}
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, EntityDisplayRepositoryInterface $entity_display_repository) {
$this->entityDisplayRepository = $entity_display_repository;
$this->entityFieldManager = $entity_field_manager;
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('entity_field.manager'),
$container->get('entity_display.repository')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'fingerprint_import';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
if ($form_state->has('page') && $form_state->get('page') == 2) {
return self::formPageNext($form, $form_state);
}
$filename = 'fingerprint-import.csv';
$options_fields = [
'uid' => $this->t("User id"),
'label' => $this->t("Name"),
'created' => $this->t("Time"),
'status' => $this->t("State"),
'note' => $this->t("Exception"),
];
$separate = ',';
$form['files']['csv_file_upload'] = [
'#type' => 'managed_file',
'#title' => $this->t('Choose a file'),
'#description' => '<a class="btn btn-link button button--small" id="export" data-filename="' . $filename . '" download="' . $filename . '"> ' . "Download CSV template" . ' <i class="bi bi-filetype-csv"></i> : <br/></a>
<span id="export-header" >' . implode($separate, $options_fields) . '</span>',
'#required' => TRUE,
'#upload_validators' => [
'file_validate_extensions' => ['csv'],
],
];
$form['files']['csv_delimiter'] = [
'#type' => 'select',
'#title' => $this->t('Character used to separate'),
'#default_value' => $separate,
'#options' => [
',' => ',',
';' => ';',
'tab' => 'Tab',
],
];
array_unshift($options_fields, $this->t('- Select -'));
if ($fid = $form_state->getValue('csv_file_upload')) {
$csv_rows = $this->convertCsvArray($fid, 10);
$header_title = !empty($csv_rows) ? array_shift($csv_rows) : [$this->t('Empty')];
$header = [];
$field = [
'#type' => 'select',
'#options' => $options_fields,
'#empty_option' => $this->t('- Select -'),
];
foreach ($header_title as $col => $title_col) {
$title_col = trim($title_col);
$header[$col]["data"] = $field;
$header[$col]["data"]["#title"] = $title_col;
$header[$col]["data"]["#name"] = 'col[' . $col . ']';
foreach ($options_fields as $val => $name) {
if ($title_col == (string) $name) {
$header[$col]["data"]["#value"] = $val;
}
}
}
$form['files']['csv_file_upload']['#description'] = [
'#type' => 'details',
'#title' => $this->t('Preview'),
'#open' => TRUE,
'preview' => [
'#type' => 'table',
'#header' => $header,
'#rows' => !empty($csv_rows) ? $csv_rows : [],
'#caption' => $this->t('Preview attendance'),
'#attributes' => ['class' => ['admin-dblog']],
],
];
}
$form['files']['date_format'] = [
'#type' => 'select',
'#title' => $this->t('Select format date'),
'#default_value' => 'd/m/Y',
'#options' => [
'd/m/Y' => implode('/', [
$this->t('Day'),
$this->t('Month'),
$this->t('Year'),
]),
'm/d/Y' => implode('/', [
$this->t('Month'),
$this->t('Day'),
$this->t('Year'),
]),
],
];
$form['#attached'] = [
'library' => ['fingerprint/export'],
];
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['next'] = [
'#type' => 'submit',
'#button_type' => 'success',
'#value' => $this->t('Next'),
'#submit' => ['::nextCsvSubmit'],
];
return $form;
}
/**
* Step 2 form.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @return array
* The render array defining the elements of the form.
*/
public function formPageNext(array &$form, FormStateInterface $form_state) {
$col = array_flip($form_state->getUserInput()['col']);
$rows = $this->calculateCsv($form_state->getValue("csv_file_upload"), $col);
$header = [
$this->t('uid'),
$this->t('Name'),
$this->t('Day'),
$this->t('Check in'),
$this->t('Check out'),
$this->t('Time break'),
$this->t('Total'),
$this->t('Night shift'),
$this->t('Overtime'),
$this->t('Sunday'),
$this->t('Holiday'),
$this->t('Note'),
];
$form['table'] = [
'#type' => 'table',
'#caption' => $this->t('Attendance calculate'),
'#title' => $this->t('Attendance'),
'#header' => $header,
'#rows' => $rows,
'#attributes' => [
'data-toggle' => "table",
'data-search' => "true",
'data-show-refresh' => "true",
'data-show-toggle' => "true",
'data-show-fullscreen' => "true",
'data-click-to-select' => "true",
'data-show-columns-toggle-all' => "true",
'data-detail-view' => "true",
'data-show-columns' => "true",
'data-show-export' => "true",
'data-pagination' => "true",
],
];
$form['timeline'] = [
'#type' => 'container',
'#title' => $this->t('Visualize'),
'#attributes' => [
'class' => ['timeline'],
],
];
$form['#attached']['library'][] = 'work_time/bootstrapTable';
$form['#attached']['library'][] = 'fingerprint/fingerprint';
$form['back'] = [
'#type' => 'submit',
'#value' => $this->t('Back'),
'#submit' => ['::pageBack'],
'#limit_validation_errors' => [],
];
$form['submit'] = [
'#type' => 'submit',
'#button_type' => 'primary',
'#value' => $this->t('Submit'),
];
return $form;
}
/**
* Button submit back.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function pageBack(array &$form, FormStateInterface $form_state) {
$form_state
->set('col', $form_state->get('col'))
->set('page', 1)
->setRebuild(TRUE);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
if (!empty($form_state->getValue('csv_file_upload'))) {
$csv_rows = $this->convertCsvArray($form_state->getValue("csv_file_upload"), 5);
if (count($csv_rows) < 1) {
$form_state->setErrorByName('csv_file_upload', $this->t('The list should be at least 1 line.'));
}
if (count($csv_rows[0]) < 2 && $csv_rows[0][0] != 'Email' && $csv_rows[0][1] != 'First name' && $csv_rows[0][0] != 'Last name') {
$form_state->setErrorByName('csv_file_upload', $this->t('The file csv is not compatible.'));
}
}
}
/**
* {@inheritdoc}
*/
public function nextCsvSubmit(array &$form, FormStateInterface $form_state) {
$form_state->set('page', 2)->setRebuild(TRUE);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->messenger()
->addStatus($this->t('The fingerprint has been imported.'));
$form_state->setRedirect('fingerprint.list');
}
/**
* {@inheritDoc}
*/
protected function getFile($fid) {
if (is_array($fid)) {
$fid = end($fid);
}
$file = $this->entityTypeManager->getStorage('file')->load($fid);
if (empty($file)) {
return FALSE;
}
return $file->get('uri')->value;
}
/**
* {@inheritDoc}
*/
protected function getDelimiter($row, &$delimiter = ',') {
$line = explode($delimiter, $row);
if (count($line) <= 1) {
$delimiters = [',', ';', "\t"];
foreach ($delimiters as $delimiter) {
$line = explode($delimiter, $row);
if (count($line) > 1) {
break;
}
}
}
return $line;
}
/**
* {@inheritDoc}
*/
protected function convertTimestamp($date, $formatDay = 'd/m/Y') {
$date = str_replace(['/', '.'], '-', $date);
// Convert format US month day Year.
if ($formatDay == 'm/d/Y H:i') {
$extract = explode('-', $date);
$temp = $extract[0];
$extract[0] = $extract[1];
$extract[1] = $temp;
$date = implode('-', $extract);
}
return strtotime($date);
}
/**
* {@inheritDoc}
*/
public function calculateCsv($fid, $col) {
$filename = $this->getFile($fid);
if (($f = fopen($filename, "r")) !== FALSE) {
$line = trim(fgets($f));
$delimiter = ',';
$this->getDelimiter($line, $delimiter);
$label = $lines = [];
$formatDay = 'd/m/Y';
if (!ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', TRUE);
}
$processService = \Drupal::service('fingerprint.process_services');
$workingHours = $processService->getShifts();
$margin = 30 * 60;
while (($data = fgetcsv($f, 0, $delimiter)) !== FALSE) {
$uid = $data[$col['uid']] ?? '';
$date = $data[$col['created']] ?? '';
$label[$uid] = $data[$col['label']] ?? '';
if (empty($uid) || empty($date)) {
continue;
}
$date = $this->convertTimestamp($date, $formatDay);
$lines[$uid][] = $date;
}
fclose($f);
if (!empty($lines)) {
$calculated = [];
$fingerprintStorage = $this->entityTypeManager->getStorage('fingerprint');
foreach ($lines as $uid => $attendance) {
sort($attendance);
$date = $processService->processTimeRecords($attendance, $workingHours, $margin);
foreach ($date as $day => $process) {
$calculated[] = [
'uid' => $uid,
'label' => $label[$uid],
'date' => date($formatDay, strtotime($day)),
'checkin' => $process['checkin'],
'checkout' => $process['checkout'],
'lunch' => $process['lunch'],
'total' => $process['total'],
'night' => $process['night'],
'over_time' => $process['over_time'],
'sunday' => $process['sunday'],
'holiday' => $process['holiday'],
'description' => $process['description'],
];
$query = \Drupal::entityQuery('fingerprint');
$query->condition('uid', $uid);
$query->condition('created', $process['check_in']);
$fingerprint_ids = $query->execute();
if (empty($fingerprint_ids)) {
$fingerprint = $fingerprintStorage->create([
'label' => $label[$uid],
'uid' => $uid,
'created' => $process['created'],
'stopped' => $process['stopped'],
'time_total' => $process['time_total'],
'description' => $process['description'],
'break' => $process['break'],
]);
$fingerprint->save();
}
}
}
return $calculated;
}
return $lines;
}
}
/**
* {@inheritDoc}
*/
public function convertCsvArray($fid, $limit = FALSE) {
$filename = $this->getFile($fid);
if (($f = fopen($filename, "r")) !== FALSE) {
$line = trim(fgets($f));
$delimiter = ',';
$csv_rows = [$this->getDelimiter($line, $delimiter)];
$i = 0;
if (!ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', TRUE);
}
while (($data = fgetcsv($f, 0, $delimiter)) !== FALSE) {
$csv_rows[] = $data;
if ($limit && $i++ > $limit) {
break;
}
}
fclose($f);
return $csv_rows;
}
return FALSE;
}
}
