First commit waiting for Budget Alert
This commit is contained in:
26
modules/axelor-open-suite/axelor-human-resource/build.gradle
Normal file
26
modules/axelor-open-suite/axelor-human-resource/build.gradle
Normal file
@ -0,0 +1,26 @@
|
||||
apply plugin: "com.axelor.app-module"
|
||||
|
||||
apply from: "../version.gradle"
|
||||
|
||||
apply {
|
||||
version = openSuiteVersion
|
||||
}
|
||||
|
||||
axelor {
|
||||
title "Axelor Human Resource"
|
||||
description "Axelor Human Resource Module"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(":modules:axelor-project")
|
||||
compile project(":modules:axelor-bank-payment")
|
||||
}
|
||||
|
||||
task copyWebapp(type: Copy) {
|
||||
destinationDir = file(rootProject.buildDir)
|
||||
into("webapp/hr") {
|
||||
from "src/main/webapp"
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.tasks.war.dependsOn copyWebapp
|
||||
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.csv.script;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.ExtraHours;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExtraHoursRepository;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Map;
|
||||
|
||||
public class ImportExtraHours {
|
||||
|
||||
@Inject private EmployeeRepository employeeRepository;
|
||||
|
||||
@Inject private ExtraHoursRepository extraHoursRepository;
|
||||
|
||||
public Long importEmployee(String registrationNumber) {
|
||||
Employee employee =
|
||||
employeeRepository
|
||||
.all()
|
||||
.filter("self.registrationNumber = ?1", registrationNumber)
|
||||
.fetchOne();
|
||||
return employee.getId();
|
||||
}
|
||||
|
||||
public Object saveExtraHours(Object bean, Map<String, Object> values) {
|
||||
|
||||
if (!(bean instanceof ExtraHours)) {
|
||||
System.out.println(
|
||||
"Error: Bean is not an instance of ExtraHours. Actual type: "
|
||||
+ bean.getClass().getName());
|
||||
return null;
|
||||
}
|
||||
|
||||
ExtraHours extraHour = (ExtraHours) bean;
|
||||
|
||||
if (extraHour == null) {
|
||||
System.out.println("Error: Extra hours data is missing.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Print the values for debugging purposes
|
||||
System.out.println("Extra hours data found: " + extraHour);
|
||||
System.out.println("Values map: " + values);
|
||||
|
||||
return extraHoursRepository.save(extraHour);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.csv.script;
|
||||
|
||||
import com.axelor.apps.base.db.ImportConfiguration;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ImportExtraHoursConfiguration {
|
||||
|
||||
public static final String IMPORT_EXTRA_HOURS_CONFIG = "import-extra-hours-config.xml";
|
||||
public static final String IMPORT_EXTRA_HOURS_CSV = "Extra-hours.csv";
|
||||
public static final String FILES_DIR = "files";
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(ImportExtraHoursConfiguration.class);
|
||||
@Inject private MetaFiles metaFiles;
|
||||
|
||||
public Object importFiles(Object bean, Map<String, Object> values) {
|
||||
|
||||
assert bean instanceof ImportConfiguration;
|
||||
|
||||
final Path path = (Path) values.get("__path__");
|
||||
|
||||
ImportConfiguration importConfig = (ImportConfiguration) bean;
|
||||
|
||||
try {
|
||||
File file = path.resolve(FILES_DIR + File.separator + IMPORT_EXTRA_HOURS_CONFIG).toFile();
|
||||
importConfig.setBindMetaFile(metaFiles.upload(file));
|
||||
file = path.resolve(FILES_DIR + File.separator + IMPORT_EXTRA_HOURS_CSV).toFile();
|
||||
importConfig.setDataMetaFile(metaFiles.upload(file));
|
||||
} catch (IOException e) {
|
||||
log.debug("Error importing Extra-hours import config", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return importConfig;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.base.db.repo.PartnerBaseRepository;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.inject.Beans;
|
||||
|
||||
public class EmployeeHRRepository extends EmployeeRepository {
|
||||
|
||||
@Override
|
||||
public Employee save(Employee entity) {
|
||||
Partner partner = entity.getContactPartner();
|
||||
if (!partner.getIsContact() && partner.getPartnerTypeSelect() == 0) {
|
||||
partner.setIsContact(true);
|
||||
partner.setIsEmployee(true);
|
||||
Beans.get(PartnerHRRepository.class).save(partner);
|
||||
}
|
||||
|
||||
EmploymentContract employmentContract = entity.getMainEmploymentContract();
|
||||
if (employmentContract != null && employmentContract.getEmployee() == null) {
|
||||
employmentContract.setEmployee(entity);
|
||||
}
|
||||
|
||||
return super.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Employee copy(Employee entity, boolean deep) {
|
||||
|
||||
entity.setContactPartner(null);
|
||||
entity.setFixedProPhone(null);
|
||||
entity.setMobileProPhone(null);
|
||||
entity.setPhoneAtCustomer(null);
|
||||
entity.setEmergencyContact(null);
|
||||
entity.setEmergencyNumber(null);
|
||||
entity.setDateOfHire(null);
|
||||
entity.setSeniorityDate(null);
|
||||
entity.setProfitSharingBeneficiary(null);
|
||||
entity.setMainEmploymentContract(null);
|
||||
entity.setExportCode(null);
|
||||
entity.setEmploymentContractList(null);
|
||||
entity.setLunchVoucherAdvanceList(null);
|
||||
entity.setEmployeeAdvanceList(null);
|
||||
entity.setKilometricLogList(null);
|
||||
entity.setLeaveLineList(null);
|
||||
|
||||
Employee copy = super.copy(entity, deep);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Employee employee) {
|
||||
|
||||
if (employee.getUser() != null) {
|
||||
UserHRRepository userRepo = Beans.get(UserHRRepository.class);
|
||||
User user = userRepo.find(employee.getUser().getId());
|
||||
if (user != null) {
|
||||
user.setEmployee(null);
|
||||
userRepo.save(user);
|
||||
}
|
||||
}
|
||||
if (employee.getContactPartner() != null) {
|
||||
PartnerBaseRepository partnerRepo = Beans.get(PartnerBaseRepository.class);
|
||||
Partner partner = partnerRepo.find(employee.getContactPartner().getId());
|
||||
if (partner != null) {
|
||||
partner.setEmployee(null);
|
||||
partnerRepo.save(partner);
|
||||
}
|
||||
}
|
||||
super.remove(employee);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.service.expense.ExpenseService;
|
||||
import com.axelor.inject.Beans;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
public class ExpenseHRRepository extends ExpenseRepository {
|
||||
@Override
|
||||
public Expense save(Expense expense) {
|
||||
try {
|
||||
expense = super.save(expense);
|
||||
Beans.get(ExpenseService.class).setDraftSequence(expense);
|
||||
if (expense.getStatusSelect() == ExpenseRepository.STATUS_DRAFT) {
|
||||
Beans.get(ExpenseService.class).completeExpenseLines(expense);
|
||||
}
|
||||
|
||||
return expense;
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
|
||||
public class HrBatchHRRepository extends HrBatchRepository {
|
||||
|
||||
@Override
|
||||
public HrBatch copy(HrBatch entity, boolean deep) {
|
||||
HrBatch copy = super.copy(entity, deep);
|
||||
copy.setBatchList(null);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.account.db.repo.PartnerAccountRepository;
|
||||
import com.axelor.apps.account.service.AccountingSituationService;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.base.service.app.AppService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class PartnerHRRepository extends PartnerAccountRepository {
|
||||
|
||||
@Inject
|
||||
public PartnerHRRepository(
|
||||
AppService appService, AccountingSituationService accountingSituationService) {
|
||||
super(appService, accountingSituationService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Partner partner) {
|
||||
if (partner.getEmployee() != null) {
|
||||
EmployeeHRRepository employeeRepo = Beans.get(EmployeeHRRepository.class);
|
||||
Employee employee = employeeRepo.find(partner.getEmployee().getId());
|
||||
if (employee != null) {
|
||||
employeeRepo.remove(employee);
|
||||
}
|
||||
}
|
||||
super.remove(partner);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.service.project.ProjectPlanningTimeService;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.apps.project.db.ProjectPlanningTime;
|
||||
import com.axelor.apps.project.db.repo.ProjectManagementRepository;
|
||||
import com.axelor.apps.project.db.repo.ProjectPlanningTimeRepository;
|
||||
import com.axelor.team.db.TeamTask;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.List;
|
||||
|
||||
public class ProjectHRRepository extends ProjectManagementRepository {
|
||||
|
||||
@Inject private ProjectPlanningTimeService projectPlanningTimeService;
|
||||
|
||||
@Inject private ProjectPlanningTimeRepository planningTimeRepo;
|
||||
|
||||
@Override
|
||||
public Project save(Project project) {
|
||||
super.save(project);
|
||||
|
||||
List<ProjectPlanningTime> projectPlanningTimeList =
|
||||
planningTimeRepo
|
||||
.all()
|
||||
.filter("self.project = ?1 OR self.project.parentProject = ?1", project)
|
||||
.fetch();
|
||||
|
||||
project.setTotalPlannedHrs(projectPlanningTimeService.getProjectPlannedHrs(project));
|
||||
|
||||
Project parentProject = project.getParentProject();
|
||||
if (parentProject != null) {
|
||||
parentProject.setTotalPlannedHrs(
|
||||
projectPlanningTimeService.getProjectPlannedHrs(parentProject));
|
||||
}
|
||||
|
||||
if (projectPlanningTimeList != null) {
|
||||
for (ProjectPlanningTime planningTime : projectPlanningTimeList) {
|
||||
TeamTask task = planningTime.getTask();
|
||||
if (task != null) {
|
||||
task.setTotalPlannedHrs(projectPlanningTimeService.getTaskPlannedHrs(task));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return project;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.service.project.ProjectPlanningTimeService;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.apps.project.db.ProjectPlanningTime;
|
||||
import com.axelor.apps.project.db.repo.ProjectPlanningTimeRepository;
|
||||
import com.axelor.apps.project.db.repo.ProjectRepository;
|
||||
import com.axelor.team.db.TeamTask;
|
||||
import com.axelor.team.db.repo.TeamTaskRepository;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class ProjectPlanningTimeHRRepository extends ProjectPlanningTimeRepository {
|
||||
|
||||
@Inject private ProjectPlanningTimeService planningTimeService;
|
||||
|
||||
@Inject private ProjectRepository projectRepo;
|
||||
|
||||
@Inject private TeamTaskRepository taskRepo;
|
||||
|
||||
@Override
|
||||
public ProjectPlanningTime save(ProjectPlanningTime projectPlanningTime) {
|
||||
|
||||
super.save(projectPlanningTime);
|
||||
|
||||
Project project = projectPlanningTime.getProject();
|
||||
project.setTotalPlannedHrs(planningTimeService.getProjectPlannedHrs(project));
|
||||
|
||||
Project parentProject = project.getParentProject();
|
||||
if (parentProject != null) {
|
||||
parentProject.setTotalPlannedHrs(planningTimeService.getProjectPlannedHrs(parentProject));
|
||||
}
|
||||
|
||||
TeamTask task = projectPlanningTime.getTask();
|
||||
if (task != null) {
|
||||
task.setTotalPlannedHrs(planningTimeService.getTaskPlannedHrs(task));
|
||||
}
|
||||
|
||||
return projectPlanningTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(ProjectPlanningTime projectPlanningTime) {
|
||||
|
||||
Project project = projectPlanningTime.getProject();
|
||||
TeamTask task = projectPlanningTime.getTask();
|
||||
|
||||
super.remove(projectPlanningTime);
|
||||
|
||||
if (task != null) {
|
||||
taskRepo.save(task);
|
||||
} else {
|
||||
projectRepo.save(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.service.project.ProjectPlanningTimeService;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.apps.project.db.repo.TeamTaskProjectRepository;
|
||||
import com.axelor.team.db.TeamTask;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class TeamTaskHRRepository extends TeamTaskProjectRepository {
|
||||
|
||||
@Inject private ProjectPlanningTimeService projectPlanningTimeService;
|
||||
|
||||
@Override
|
||||
public TeamTask save(TeamTask teamTask) {
|
||||
|
||||
super.save(teamTask);
|
||||
|
||||
teamTask.setTotalPlannedHrs(projectPlanningTimeService.getTaskPlannedHrs(teamTask));
|
||||
|
||||
Project project = teamTask.getProject();
|
||||
project.setTotalPlannedHrs(projectPlanningTimeService.getProjectPlannedHrs(project));
|
||||
|
||||
Project parentProject = project.getParentProject();
|
||||
if (parentProject != null) {
|
||||
parentProject.setTotalPlannedHrs(
|
||||
projectPlanningTimeService.getProjectPlannedHrs(parentProject));
|
||||
}
|
||||
|
||||
return teamTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(TeamTask teamTask) {
|
||||
|
||||
Project project = teamTask.getProject();
|
||||
super.remove(teamTask);
|
||||
|
||||
project.setTotalPlannedHrs(projectPlanningTimeService.getProjectPlannedHrs(project));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeamTask copy(TeamTask entity, boolean deep) {
|
||||
entity.setTotalPlannedHrs(null);
|
||||
entity.setTotalRealHrs(null);
|
||||
entity.setProjectPlanningTimeList(null);
|
||||
return super.copy(entity, deep);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetLineService;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetService;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.apps.project.db.repo.ProjectRepository;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class TimesheetHRRepository extends TimesheetRepository {
|
||||
|
||||
@Inject private TimesheetService timesheetService;
|
||||
@Inject private TimesheetLineService timesheetLineService;
|
||||
@Inject private ProjectRepository projectRepository;
|
||||
|
||||
@Override
|
||||
public Timesheet save(Timesheet timesheet) {
|
||||
if (timesheet.getTimesheetLineList() != null) {
|
||||
for (TimesheetLine timesheetLine : timesheet.getTimesheetLineList())
|
||||
Beans.get(TimesheetLineHRRepository.class).computeFullName(timesheetLine);
|
||||
}
|
||||
return super.save(timesheet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> validate(Map<String, Object> json, Map<String, Object> context) {
|
||||
|
||||
Map<String, Object> obj = super.validate(json, context);
|
||||
|
||||
if (json.get("id") == null) {
|
||||
Timesheet timesheet = create(json);
|
||||
if (timesheet.getTimesheetLineList() == null || timesheet.getTimesheetLineList().isEmpty()) {
|
||||
timesheet.setTimesheetLineList(new ArrayList<TimesheetLine>());
|
||||
obj.put("timesheetLineList", timesheetService.createDefaultLines(timesheet));
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Timesheet entity) {
|
||||
|
||||
if (entity.getStatusSelect() == TimesheetRepository.STATUS_VALIDATED
|
||||
&& entity.getTimesheetLineList() != null) {
|
||||
|
||||
timesheetService.setTeamTaskTotalRealHrs(entity.getTimesheetLineList(), false);
|
||||
|
||||
Map<Project, BigDecimal> projectTimeSpentMap =
|
||||
timesheetLineService.getProjectTimeSpentMap(entity.getTimesheetLineList());
|
||||
Iterator<Project> projectIterator = projectTimeSpentMap.keySet().iterator();
|
||||
|
||||
while (projectIterator.hasNext()) {
|
||||
Project project = projectIterator.next();
|
||||
project.setTimeSpent(project.getTimeSpent().subtract(projectTimeSpentMap.get(project)));
|
||||
projectRepository.save(project);
|
||||
}
|
||||
}
|
||||
super.remove(entity);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
public class TimesheetLineHRRepository extends TimesheetLineRepository {
|
||||
|
||||
@Override
|
||||
public TimesheetLine save(TimesheetLine timesheetLine) {
|
||||
try {
|
||||
computeFullName(timesheetLine);
|
||||
|
||||
return super.save(timesheetLine);
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void computeFullName(TimesheetLine timesheetLine) {
|
||||
|
||||
timesheetLine.setFullName(
|
||||
timesheetLine.getTimesheet().getFullName()
|
||||
+ " "
|
||||
+ timesheetLine.getDate()
|
||||
+ " "
|
||||
+ timesheetLine.getId());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.hr.db.TSTimer;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.hr.service.timesheet.timer.TimesheetTimerService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class TimesheetTimerHRRepository extends TSTimerRepository {
|
||||
|
||||
@Inject private TimesheetTimerService tsTimerService;
|
||||
|
||||
@Override
|
||||
public TSTimer save(TSTimer tsTimer) {
|
||||
if (tsTimer.getStatusSelect() == TSTimerRepository.STATUS_STOP) {
|
||||
if (tsTimer.getTimesheetLine() != null) updateTimesheetLine(tsTimer);
|
||||
else {
|
||||
if (tsTimer.getDuration() > 59) {
|
||||
tsTimerService.generateTimesheetLine(tsTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.save(tsTimer);
|
||||
}
|
||||
|
||||
public void updateTimesheetLine(TSTimer tsTimer) {
|
||||
TimesheetLine timesheetLine = tsTimer.getTimesheetLine();
|
||||
|
||||
timesheetLine.setProject(tsTimer.getProject());
|
||||
timesheetLine.setProduct(tsTimer.getProduct());
|
||||
timesheetLine.setHoursDuration(
|
||||
tsTimerService.convertSecondDurationInHours(tsTimer.getDuration()));
|
||||
timesheetLine.setComments(tsTimer.getComments());
|
||||
|
||||
Beans.get(TimesheetLineRepository.class).save(timesheetLine);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.db.repo;
|
||||
|
||||
import com.axelor.apps.base.db.repo.UserBaseRepository;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.inject.Beans;
|
||||
|
||||
public class UserHRRepository extends UserBaseRepository {
|
||||
|
||||
@Override
|
||||
public void remove(User user) {
|
||||
if (user.getEmployee() != null) {
|
||||
EmployeeHRRepository employeeRepo = Beans.get(EmployeeHRRepository.class);
|
||||
Employee employee = employeeRepo.find(user.getEmployee().getId());
|
||||
if (employee != null) {
|
||||
employee.setUser(null);
|
||||
employeeRepo.save(employee);
|
||||
}
|
||||
}
|
||||
super.remove(user);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.exception;
|
||||
|
||||
/** Interface of Exceptions. Enum all exception of axelor-human-resource. */
|
||||
public interface IExceptionMessage {
|
||||
|
||||
static final String HR_CONFIG = /*$$(*/
|
||||
"Please configure informations for human resources for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_EXPENSE_TYPE = /*$$(*/
|
||||
"Please configure the expense type for kilometric allowance in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_SENT_EXPENSE_TEMPLATE = /*$$(*/
|
||||
"Please configure the sent expense template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_VALIDATED_EXPENSE_TEMPLATE = /*$$(*/
|
||||
"Please configure the validated expense template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_REFUSED_EXPENSE_TEMPLATE = /*$$(*/
|
||||
"Please configure the refused expense template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_CANCELED_EXPENSE_TEMPLATE = /*$$(*/
|
||||
"Please configure the canceled expense template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_SENT_TIMESHEET_TEMPLATE = /*$$(*/
|
||||
"Please configure the sent timehsheet template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_VALIDATED_TIMESHEET_TEMPLATE = /*$$(*/
|
||||
"Please configure the validated timehsheet template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_REFUSED_TIMESHEET_TEMPLATE = /*$$(*/
|
||||
"Please configure the refused timehsheet template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_CANCELED_TIMESHEET_TEMPLATE = /*$$(*/
|
||||
"Please configure the canceled timehsheet template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_SENT_LEAVE_TEMPLATE = /*$$(*/
|
||||
"Please configure the sent leave template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_VALIDATED_LEAVE_TEMPLATE = /*$$(*/
|
||||
"Please configure the validated leave template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_REFUSED_LEAVE_TEMPLATE = /*$$(*/
|
||||
"Please configure the refused leave template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_CANCELED_LEAVE_TEMPLATE = /*$$(*/
|
||||
"Please configure the canceled leave template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_SENT_EXTRA_HOURS_TEMPLATE = /*$$(*/
|
||||
"Please configure the sent extra hours template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_VALIDATED_EXTRA_HOURS_TEMPLATE = /*$$(*/
|
||||
"Please configure the validated extra hours template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_REFUSED_EXTRA_HOURS_TEMPLATE = /*$$(*/
|
||||
"Please configure the refused extra hours template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_CANCELED_EXTRA_HOURS_TEMPLATE = /*$$(*/
|
||||
"Please configure the canceled extra hours template in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_LEAVE_REASON = /*$$(*/
|
||||
"Please configure the unjustified absence reason in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_LUNCH_VOUCHER_EXPORT_PATH = /*$$(*/
|
||||
"Please configure the lunch voucher export path in HR config for the company %s" /*)*/;
|
||||
static final String HR_CONFIG_NO_EXPENSE_SEQUENCE = /*$$(*/
|
||||
"Company %s does not have any expense's sequence" /*)*/;
|
||||
static final String HR_CONFIG_FORMULA_VARIABLE_MISSING = /*$$(*/
|
||||
"Please configure Formula Variables for human resource for the company %s" /*)*/;
|
||||
|
||||
static final String TIMESHEET_FROM_DATE = /*$$(*/ "Please add a start date for generation" /*)*/;
|
||||
static final String TIMESHEET_TO_DATE = /*$$(*/ "Please add an end date for generation" /*)*/;
|
||||
static final String TIMESHEET_PRODUCT = /*$$(*/ "Please add a product" /*)*/;
|
||||
static final String TIMESHEET_EMPLOYEE_DAY_PLANNING = /*$$(*/
|
||||
"Please add an employee's planning related to user %s" /*)*/;
|
||||
static final String TIMESHEET_EMPLOYEE_DAILY_WORK_HOURS = /*$$(*/
|
||||
"Please, enter the number of daily work hours per employee %s" /*)*/;
|
||||
static final String TIMESHEET_DAILY_WORK_HOURS = /*$$(*/
|
||||
"Please, configure the number of daily work hours." /*)*/;
|
||||
static final String TIMESHEET_NULL_FROM_DATE = /*$$(*/ "From date can't be empty" /*)*/;
|
||||
static final String TIMESHEET_NULL_TO_DATE = /*$$(*/ "To date can't be empty" /*)*/;
|
||||
static final String TIMESHEET_LINE_NULL_DATE = /*$$(*/
|
||||
"The date of timesheet line %d can't be empty" /*)*/;
|
||||
static final String GENERAL_EMPLOYEE_ACTIVITY = /*$$(*/
|
||||
"Please, enter an activity for the employee %s" /*)*/;
|
||||
static final String TIMESHEET_EMPLOYEE_PUBLIC_HOLIDAY_EVENTS_PLANNING = /*$$(*/
|
||||
"Please add an employee's public holiday events planning related to user %s" /*)*/;
|
||||
static final String TIMESHEET_TIMESHEET_LINE_LIST_IS_EMPTY = /*$$(*/
|
||||
"Timesheet line list is empty, please add a timesheet line list" /*)*/;
|
||||
static final String TIMESHEET_HOLIDAY = /*$$(*/ "Holiday" /*)*/;
|
||||
static final String TIMESHEET_DAY_LEAVE = /*$$(*/ "Day leave" /*)*/;
|
||||
|
||||
static final String LEAVE_USER_EMPLOYEE = /*$$(*/
|
||||
"Please create an employee for the user %s" /*)*/;
|
||||
static final String LEAVE_LINE = /*$$(*/
|
||||
"There is no leave line for the employee %s and the reason %s." /*)*/;
|
||||
static final String LEAVE_ALLOW_NEGATIVE_VALUE_EMPLOYEE = /*$$(*/
|
||||
"Employee %s is not allowed to take leave in advance." /*)*/;
|
||||
static final String LEAVE_ALLOW_NEGATIVE_VALUE_REASON = /*$$(*/
|
||||
"You are not able to take leave in advance for the reason '%s'." /*)*/;
|
||||
static final String LEAVE_ALLOW_NEGATIVE_ALERT = /*$$(*/
|
||||
"You now have a negative amount of leave available for the reason %s" /*)*/;
|
||||
static final String LEAVE_REASON_NO_UNIT = /*$$(*/
|
||||
"Please, choose unit in leave reason %s." /*)*/;
|
||||
|
||||
static final String EMPLOYEE_PLANNING = /*$$(*/ "Please, add a planning for employee : %s" /*)*/;
|
||||
static final String EMPLOYEE_PUBLIC_HOLIDAY = /*$$(*/
|
||||
"Please, add a public holiday planning for employee : %s" /*)*/;
|
||||
static final String EMPLOYEE_CONTRACT_OF_EMPLOYMENT = /*$$(*/
|
||||
"Please, add a contract of employment for employee : %s" /*)*/;
|
||||
|
||||
static final String BATCH_MISSING_FIELD = /*$$(*/
|
||||
"Leave reason and day number have to be defined" /*)*/;
|
||||
static final String EMPLOYEE_DOUBLE_LEAVE_MANAGEMENT = /*$$(*/
|
||||
"The employee %s has multiple %s leave lines" /*)*/;
|
||||
static final String EMPLOYEE_NO_LEAVE_MANAGEMENT = /*$$(*/
|
||||
"The employee %s has no %s leave line" /*)*/;
|
||||
static final String EMPLOYEE_NO_SENIORITY_DATE = /*$$(*/
|
||||
"The employee %s has no seniority date" /*)*/;
|
||||
static final String EMPLOYEE_NO_BIRTH_DATE = /*$$(*/ "The employee %s has no birth date" /*)*/;
|
||||
|
||||
static final String BATCH_LEAVE_MANAGEMENT_ENDING_0 = /*$$(*/
|
||||
"Employees' leaves attempted to be computed : %s" /*)*/;
|
||||
static final String BATCH_LEAVE_MANAGEMENT_ENDING_1 = /*$$(*/
|
||||
"Employees' leaves successfully computed : %s" /*)*/;
|
||||
static final String BATCH_LEAVE_MANAGEMENT_ENDING_2 = /*$$(*/
|
||||
"Employees' leaves failed to be computed due to configuration anomaly : %s" /*)*/;
|
||||
static final String BATCH_LEAVE_MANAGEMENT_ENDING_3 = /*$$(*/
|
||||
"Employees' leaves failed to be computed due to missing data : %s" /*)*/;
|
||||
static final String BATCH_LEAVE_MANAGEMENT_QTY_OUT_OF_BOUNDS = /*$$(*/
|
||||
"Qty must be lower than %d." /*)*/;
|
||||
static final String BATCH_SENIORITY_LEAVE_MANAGEMENT_FORMULA = /*$$(*/
|
||||
"There is an error in a formula" /*)*/;
|
||||
static final String BATCH_PAYROLL_PREPARATION_GENERATION_RECAP = /*$$(*/
|
||||
"Payroll preparations attempted to be generated : %s" /*)*/;
|
||||
static final String BATCH_PAYROLL_PREPARATION_SUCCESS_RECAP = /*$$(*/
|
||||
"Payroll preparations successfully generated : %s" /*)*/;
|
||||
static final String BATCH_PAYROLL_PREPARATION_DUPLICATE_RECAP = /*$$(*/
|
||||
"Payroll preparations failed to be generated due to a duplicate one : %s" /*)*/;
|
||||
static final String BATCH_PAYROLL_PREPARATION_CONFIGURATION_RECAP = /*$$(*/
|
||||
"Payroll preparations failed to be generated due to missing data : %s" /*)*/;
|
||||
static final String BATCH_PAYROLL_PREPARATION_EXPORT_RECAP = /*$$(*/
|
||||
"Payroll preparations exported : %s" /*)*/;
|
||||
|
||||
static final String BATCH_TIMESHEET_MISSING_TEMPLATE = /*$$(*/
|
||||
"You must choose a template." /*)*/;
|
||||
static final String BATCH_TIMESHEET_REMINDER_DONE = /*$$(*/ "Employees computed: %d" /*)*/;
|
||||
static final String BATCH_TIMESHEET_REMINDER_ANOMALY = /*$$(*/
|
||||
"Employees failed to be computed due to anomaly: %d" /*)*/;
|
||||
|
||||
static final String BATCH_CREDIT_TRANSFER_EXPENSE_DONE_SINGULAR = /*$$(*/
|
||||
"%d expense treated successfully," /*)*/;
|
||||
static final String BATCH_CREDIT_TRANSFER_EXPENSE_DONE_PLURAL = /*$$(*/
|
||||
"%d expenses treated successfully," /*)*/;
|
||||
|
||||
static final String LUNCH_VOUCHER_MIN_STOCK = /*$$(*/
|
||||
"Minimum stock of lunch vouchers will be reached for the company %s. Minimum Stock allowed : %s. Available Stock : %s" /*)*/;
|
||||
|
||||
static final String KILOMETRIC_LOG_NO_YEAR = /*$$(*/
|
||||
"There is no year for society %s which includes date %s" /*)*/;
|
||||
|
||||
static final String KILOMETRIC_ALLOWANCE_NO_RULE = /*$$(*/
|
||||
"There is no matching condition for the allowance %s" /*)*/;
|
||||
static final String KILOMETRIC_ALLOWANCE_NO_DATE_SELECTED = /*$$(*/
|
||||
"There is no year selected for the allowance." /*)*/;
|
||||
|
||||
static final String PAYROLL_PREPARATION_DUPLICATE = /*$$(*/
|
||||
"There is already a payroll preparation for the employee %s, the company %s and the period %s" /*)*/;
|
||||
|
||||
/** Expense service */
|
||||
static final String EXPENSE_JOURNAL = /*$$(*/
|
||||
"You must configure an expenses journal(company : %s)" /*)*/;
|
||||
|
||||
static final String EXPENSE_ACCOUNT = /*$$(*/
|
||||
"You must configure an expenses account (company : %s)" /*)*/;
|
||||
static final String EXPENSE_ACCOUNT_TAX = /*$$(*/
|
||||
"You must configure an account for expenses taxes (company : %s)" /*)*/;
|
||||
static final String EXPENSE_CANCEL_MOVE = /*$$(*/
|
||||
"Move already used, you must unreconcile it first" /*)*/;
|
||||
|
||||
static final String EXPENSE_TAX_PRODUCT = /*$$(*/ "No Tax for the product %s" /*)*/;
|
||||
static final String EXPENSE_MISSING_PERIOD = /*$$(*/ "Please fill the period" /*)*/;
|
||||
static final String EXPENSE_MISSING_PAYMENT_MODE = /*$$(*/ "Please fill the payment mode." /*)*/;
|
||||
|
||||
/** Timesheet Editor */
|
||||
static final String NEW_PROJECT_LINE = /*$$(*/ "New project line" /*)*/;
|
||||
|
||||
/** Kilometric allowance */
|
||||
String KILOMETRIC_ALLOWANCE_GOOGLE_MAPS_ERROR = /*$$(*/ "Google Maps error: %s" /*)*/;
|
||||
|
||||
String KILOMETRIC_ALLOWANCE_OSM_ERROR = /*$$(*/ "Open Street Maps error: %s" /*)*/;
|
||||
|
||||
static final String EXPENSE_PAYMENT_CANCEL = /*$$(*/
|
||||
"The bank order linked to this expense has already been carried out/rejected, and thus can't be canceled" /*)*/;
|
||||
|
||||
/** Kilometric service */
|
||||
static final String KILOMETRIC_ALLOWANCE_RATE_MISSING = /*$$(*/
|
||||
"The kilometric allowance rate corresponding to the kilometric allow param %s and the company %s is missing" /*)*/;
|
||||
|
||||
/** TsTimer Service */
|
||||
String NO_TIMESHEET_CREATED = /*$$(*/
|
||||
"No timesheet line has been created because the duration is less than 1 minute" /*)*/;
|
||||
|
||||
static final String EXPENSE_NOT_SELECTED = /*$$(*/ "Please, select an expense" /*)*/;
|
||||
|
||||
static final String BATCH_EMPLOYMENT_CONTRACT_EXPORT_RECAP = /*$$(*/
|
||||
"Employment contracts exported : %s" /*)*/;
|
||||
|
||||
static final String UNIT_SELECT_FOR_LEAVE_REASON = /*$$(*/
|
||||
"Please configure the unit for this type of absence" /*)*/;
|
||||
|
||||
static final String EMPLOYEE_TIMESHEET_REMINDER_TEMPLATE = /*$$(*/
|
||||
"Please configure the template for email reminder" /*)*/;
|
||||
|
||||
static final String EXTRA_HOURS_1 = /*$$(*/ "No Extra hours import configuration found" /*)*/;
|
||||
|
||||
static final String EXTRA_HOURS_2 = /*$$(*/ "Import lead" /*)*/;
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.axelor.apps.hr.job;
|
||||
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.service.DailyReportServiceImpl;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.util.List;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.quartz.SchedulerException;
|
||||
|
||||
/** An example {@link Job} class that prints a some messages to the stderr. */
|
||||
public class CalculateAttendanceJob implements Job {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(CalculateAttendanceJob.class);
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException{
|
||||
|
||||
if (isRunning(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
List<DailyReport> dailyReportList =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.isCalculated = ?", false)
|
||||
.fetch();
|
||||
|
||||
if (!dailyReportList.isEmpty()) {
|
||||
Beans.get(DailyReportServiceImpl.class).workingHoursForAll(dailyReportList);
|
||||
log.debug("Working hours calculated successfully.");
|
||||
} else {
|
||||
log.debug("No new records to process.");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("An error occurred while calculating working hours.");
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRunning(JobExecutionContext context) {
|
||||
try {
|
||||
return context
|
||||
.getScheduler()
|
||||
.getCurrentlyExecutingJobs()
|
||||
.stream()
|
||||
.anyMatch(
|
||||
j ->
|
||||
j.getTrigger().equals(context.getTrigger())
|
||||
&& !j.getFireInstanceId().equals(context.getFireInstanceId()));
|
||||
} catch (SchedulerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
package com.axelor.apps.hr.job;
|
||||
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.quartz.SchedulerException;
|
||||
import com.axelor.app.AppSettings;
|
||||
|
||||
public class FetchAttendanceJob implements Job {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(FetchCheckInOutJob.class);
|
||||
private final String pythonScriptDir = AppSettings.get().get("services.dir");
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException{
|
||||
|
||||
if (isRunning(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pythonScriptDir == null || pythonScriptDir.isEmpty()) {
|
||||
log.error("Python script path is not configured in AppSettings.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Define the command to run the Python script with the correct path (V3)
|
||||
String[] args = {"python", pythonScriptDir + "\\Scrape\\main.py"};
|
||||
|
||||
// Execute the command
|
||||
Process p = Runtime.getRuntime().exec(args);
|
||||
|
||||
// Capture the output stream (standard output)
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.info("Python script (Pointage) output: " + line);
|
||||
}
|
||||
|
||||
// Capture the error stream (standard error)
|
||||
BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
while ((line = errorReader.readLine()) != null) {
|
||||
log.error("Python script (Pointage) error: " + line);
|
||||
}
|
||||
|
||||
// Wait for the process to complete and check the exit value
|
||||
int exitCode = p.waitFor();
|
||||
|
||||
// Check if the process ran successfully
|
||||
if (exitCode == 0) {
|
||||
log.info("Python script executed successfully (Pointage).");
|
||||
} else {
|
||||
log.error("Python script execution (Pointage) failed with exit code: " + exitCode);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
// Check if the file is not found based on the message or error code
|
||||
if (e.getMessage().contains("The system cannot find the file specified")) {
|
||||
log.error("Python script file (Pointage) not found: " + e.getMessage());
|
||||
} else {
|
||||
log.error("An error occurred while executing the Python script (Pointage).", e);
|
||||
}
|
||||
TraceBackService.trace(e);
|
||||
} catch (InterruptedException e) {
|
||||
// Handle any interruption errors
|
||||
log.error("Python script (Pointage) execution interrupted.", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRunning(JobExecutionContext context) {
|
||||
try {
|
||||
return context
|
||||
.getScheduler()
|
||||
.getCurrentlyExecutingJobs()
|
||||
.stream()
|
||||
.anyMatch(
|
||||
j ->
|
||||
j.getTrigger().equals(context.getTrigger())
|
||||
&& !j.getFireInstanceId().equals(context.getFireInstanceId()));
|
||||
} catch (SchedulerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
package com.axelor.apps.hr.job;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.hr.db.repo.CheckInOutRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.time.LocalDate;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FetchCheckInOutJob implements Job {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(FetchCheckInOutJob.class);
|
||||
private final String pythonScriptDir = AppSettings.get().get("services.dir");
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
|
||||
if (isRunning(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pythonScriptDir == null || pythonScriptDir.isEmpty()) {
|
||||
log.error("Python script path is not configured in AppSettings.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
LocalDate today = LocalDate.now();
|
||||
|
||||
// Fetch the CheckInOut list from the repository where the date_attendance is today
|
||||
int lenCheckInOutList =
|
||||
Beans.get(CheckInOutRepository.class)
|
||||
.all()
|
||||
.filter("self.date_attendance = :today")
|
||||
.bind("today", today)
|
||||
.fetch()
|
||||
.size();
|
||||
|
||||
// Define the command to run the Python script with the correct path (V3)
|
||||
String[] args = {
|
||||
"python", pythonScriptDir + "\\Scrape\\main2.py", String.valueOf(lenCheckInOutList)
|
||||
};
|
||||
|
||||
// Execute the command
|
||||
Process p = Runtime.getRuntime().exec(args);
|
||||
|
||||
// Capture the output stream (standard output)
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.info("Python script (Check In Out) output: " + line);
|
||||
}
|
||||
|
||||
// Capture the error stream (standard error)
|
||||
BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
while ((line = errorReader.readLine()) != null) {
|
||||
log.error("Python script (Check In Out) error: " + line);
|
||||
}
|
||||
|
||||
// Wait for the process to complete and check the exit value
|
||||
int exitCode = p.waitFor();
|
||||
|
||||
// Check if the process ran successfully
|
||||
if (exitCode == 0) {
|
||||
log.info("Python script executed successfully (Check In Out).");
|
||||
} else {
|
||||
log.error("Python script execution (Check In Out) failed with exit code: " + exitCode);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Check if the file is not found based on the message or error code
|
||||
if (e.getMessage().contains("The system cannot find the file specified")) {
|
||||
log.error("Python script file (Check In Out) not found: " + e.getMessage());
|
||||
} else {
|
||||
log.error("An error occurred while executing the Python script (Check In Out).", e);
|
||||
}
|
||||
TraceBackService.trace(e);
|
||||
} catch (InterruptedException e) {
|
||||
// Handle any interruption errors
|
||||
log.error("Python script (Check In Out) execution interrupted.", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRunning(JobExecutionContext context) {
|
||||
try {
|
||||
return context
|
||||
.getScheduler()
|
||||
.getCurrentlyExecutingJobs()
|
||||
.stream()
|
||||
.anyMatch(
|
||||
j ->
|
||||
j.getTrigger().equals(context.getTrigger())
|
||||
&& !j.getFireInstanceId().equals(context.getFireInstanceId()));
|
||||
} catch (SchedulerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,238 @@
|
||||
package com.axelor.apps.hr.job;
|
||||
|
||||
import com.axelor.apps.base.web.AppBaseController;
|
||||
import com.axelor.apps.hr.service.AuthorizationService;
|
||||
import com.axelor.apps.hr.service.extra.hours.ExtraHoursService;
|
||||
import com.axelor.apps.hr.service.leave.LeaveService;
|
||||
import com.axelor.apps.hr.web.AuthorizationController;
|
||||
import com.axelor.apps.hr.web.extra.hours.ExtraHoursController;
|
||||
import com.axelor.apps.hr.web.leave.LeaveController;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import wslite.json.JSONArray;
|
||||
import wslite.json.JSONException;
|
||||
import wslite.json.JSONObject;
|
||||
import org.quartz.SchedulerException;
|
||||
|
||||
/** An example {@link Job} class that prints a some messages to the stderr. */
|
||||
public class FetchHrTicketsJob implements Job {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(FetchHrTicketsJob.class);
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException{
|
||||
|
||||
if (isRunning(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("Starting the job to fetch HR tickets...");
|
||||
|
||||
String accessToken = null;
|
||||
try {
|
||||
accessToken = AppBaseController.getAccessToken();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to get access token", e);
|
||||
return; // Exit the method since the access token is critical to proceed
|
||||
}
|
||||
|
||||
if (accessToken == null) {
|
||||
log.error("Access token is null, unable to proceed.");
|
||||
return;
|
||||
}
|
||||
|
||||
final String token = accessToken;
|
||||
|
||||
// Create a thread pool with a fixed number of threads (can adjust based on system resources)
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(5);
|
||||
|
||||
try {
|
||||
// Extra hours fetch task
|
||||
executorService.submit(
|
||||
() -> {
|
||||
try {
|
||||
log.info("Fetching extra hours data...");
|
||||
String jsonResponse = Beans.get(ExtraHoursController.class).fetchHS(token);
|
||||
log.info("Fetched extra hours data successfully.");
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(ExtraHoursService.class).saveExtraHours(jsonObject);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
log.error("Failed to parse JSON: " + jsonResponse, e);
|
||||
}
|
||||
} else {
|
||||
log.warn("No response received from fetchHS.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch extra hours data: ", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Authorization AA fetch task
|
||||
executorService.submit(
|
||||
() -> {
|
||||
try {
|
||||
log.info("Fetching authorization AA...");
|
||||
String jsonResponse = Beans.get(AuthorizationController.class).fetchAA(token);
|
||||
log.info("Fetched authorization AA successfully.");
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveAA(jsonObject);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
log.error("Failed to parse JSON: " + jsonResponse, e);
|
||||
}
|
||||
} else {
|
||||
log.warn("No response received from fetchAA.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch authorization AA: ", e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Authorization AE fetch task
|
||||
executorService.submit(
|
||||
() -> {
|
||||
try {
|
||||
log.info("Fetching authorization AE...");
|
||||
String jsonResponse = Beans.get(AuthorizationController.class).fetchAE(token);
|
||||
log.info("Fetched authorization AE successfully.");
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveAE(jsonObject);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
log.error("Failed to parse JSON: " + jsonResponse, e);
|
||||
}
|
||||
} else {
|
||||
log.warn("No response received from fetchAE.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch authorization AE: ", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Authorization BS fetch task
|
||||
executorService.submit(
|
||||
() -> {
|
||||
try {
|
||||
log.info("Fetching authorization BS...");
|
||||
String jsonResponse = Beans.get(AuthorizationController.class).fetchBS(token);
|
||||
log.info("Fetched authorization BS successfully.");
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveBS(jsonObject);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
log.error("Failed to parse JSON: " + jsonResponse, e);
|
||||
}
|
||||
} else {
|
||||
log.warn("No response received from fetchBS.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch authorization BS: ", e);
|
||||
}
|
||||
});
|
||||
|
||||
executorService.submit(
|
||||
() -> {
|
||||
try {
|
||||
log.info("Fetching authorization AP...");
|
||||
String jsonResponse = Beans.get(AuthorizationController.class).fetchAP(token);
|
||||
log.info("Fetched authorization AP successfully.");
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveAP(jsonObject);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
log.error("Failed to parse JSON: " + jsonResponse, e);
|
||||
}
|
||||
} else {
|
||||
log.warn("No response received from fetchAP.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch Salary authorization: ", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Leave requests fetch task
|
||||
executorService.submit(
|
||||
() -> {
|
||||
try {
|
||||
log.info("Fetching leave requests...");
|
||||
String jsonResponse = Beans.get(LeaveController.class).fetchCR(token);
|
||||
log.info("Fetched leave requests successfully.");
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(LeaveService.class).saveCR(jsonObject);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
log.error("Failed to parse JSON: " + jsonResponse, e);
|
||||
}
|
||||
} else {
|
||||
log.warn("No response received from fetchCR.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch leave requests: ", e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
} finally {
|
||||
// Shutdown the ExecutorService gracefully
|
||||
executorService.shutdown();
|
||||
try {
|
||||
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
|
||||
executorService.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
executorService.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Finished fetching HR tickets.");
|
||||
}
|
||||
|
||||
private boolean isRunning(JobExecutionContext context) {
|
||||
try {
|
||||
return context
|
||||
.getScheduler()
|
||||
.getCurrentlyExecutingJobs()
|
||||
.stream()
|
||||
.anyMatch(
|
||||
j ->
|
||||
j.getTrigger().equals(context.getTrigger())
|
||||
&& !j.getFireInstanceId().equals(context.getFireInstanceId()));
|
||||
} catch (SchedulerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,678 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.mobile;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.base.db.repo.ProductRepository;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmployeeVehicle;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.ExpenseLine;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.LeaveLine;
|
||||
import com.axelor.apps.hr.db.LeaveReason;
|
||||
import com.axelor.apps.hr.db.LeaveRequest;
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeVehicleRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseRepository;
|
||||
import com.axelor.apps.hr.db.repo.KilometricAllowParamRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveReasonRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveRequestRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.KilometricService;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.apps.hr.service.expense.ExpenseService;
|
||||
import com.axelor.apps.hr.service.leave.LeaveService;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetLineService;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetService;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.apps.project.db.repo.ProjectRepository;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URLConnection;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HumanResourceMobileController {
|
||||
|
||||
/**
|
||||
* This method is used in mobile application. It was in ExpenseController
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws AxelorException
|
||||
* <p>POST
|
||||
* /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:insertKMExpenses
|
||||
* Content-Type: application/json
|
||||
* <p>URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:insertKMExpenses fields:
|
||||
* kmNumber, locationFrom, locationTo, allowanceTypeSelect, comments, date, projectTask,
|
||||
* kilometricAllowParam
|
||||
* <p>payload: { "data": { "action":
|
||||
* "com.axelor.apps.hr.mobile.HumanResourceMobileController:insertKMExpenses", "kmNumber":
|
||||
* 350.00, "locationFrom": "Paris", "locationTo": "Marseille", "allowanceTypeSelect": 1,
|
||||
* "comments": "no", "date": "2018-02-22", "expenseProduct": 43 } }
|
||||
*/
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void insertKMExpenses(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
User user = AuthUtils.getUser();
|
||||
if (user != null) {
|
||||
ExpenseService expenseService = Beans.get(ExpenseService.class);
|
||||
Expense expense = expenseService.getOrCreateExpense(user);
|
||||
|
||||
ExpenseLine expenseLine = new ExpenseLine();
|
||||
expenseLine.setDistance(new BigDecimal(request.getData().get("kmNumber").toString()));
|
||||
expenseLine.setFromCity(request.getData().get("locationFrom").toString());
|
||||
expenseLine.setToCity(request.getData().get("locationTo").toString());
|
||||
expenseLine.setKilometricTypeSelect(
|
||||
new Integer(request.getData().get("allowanceTypeSelect").toString()));
|
||||
expenseLine.setComments(request.getData().get("comments").toString());
|
||||
expenseLine.setExpenseDate(LocalDate.parse(request.getData().get("date").toString()));
|
||||
expenseLine.setProject(
|
||||
Beans.get(ProjectRepository.class)
|
||||
.find(Long.valueOf(request.getData().get("projectTask").toString())));
|
||||
|
||||
HRConfigService hrConfigService = Beans.get(HRConfigService.class);
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(expense.getCompany());
|
||||
Product expenseProduct = hrConfigService.getKilometricExpenseProduct(hrConfig);
|
||||
expenseLine.setExpenseProduct(expenseProduct);
|
||||
|
||||
Employee employee = user.getEmployee();
|
||||
if (employee != null) {
|
||||
KilometricAllowParamRepository kilometricAllowParamRepo =
|
||||
Beans.get(KilometricAllowParamRepository.class);
|
||||
|
||||
expenseLine.setKilometricAllowParam(
|
||||
kilometricAllowParamRepo.find(
|
||||
Long.valueOf(request.getData().get("kilometricAllowParam").toString())));
|
||||
|
||||
expenseLine.setTotalAmount(
|
||||
Beans.get(KilometricService.class).computeKilometricExpense(expenseLine, employee));
|
||||
|
||||
expenseLine.setUntaxedAmount(expenseLine.getTotalAmount());
|
||||
}
|
||||
|
||||
expense.addKilometricExpenseLineListItem(expenseLine);
|
||||
Beans.get(ExpenseRepository.class).save(expense);
|
||||
|
||||
response.setValue("id", expenseLine.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used in mobile application. It was in ExpenseController
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws AxelorException
|
||||
* <p>POST
|
||||
* /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:removeLines
|
||||
* Content-Type: application/json
|
||||
* <p>URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:removeLines no field
|
||||
* <p>payload: { "data": { "action":
|
||||
* "com.axelor.apps.hr.mobile.HumanResourceMobileController:removeLines" } }
|
||||
*/
|
||||
@Transactional
|
||||
public void removeLines(ActionRequest request, ActionResponse response) {
|
||||
|
||||
User user = AuthUtils.getUser();
|
||||
|
||||
try {
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Expense expense =
|
||||
Beans.get(ExpenseRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.statusSelect = ?1 AND self.user.id = ?2",
|
||||
ExpenseRepository.STATUS_DRAFT,
|
||||
user.getId())
|
||||
.order("-id")
|
||||
.fetchOne();
|
||||
|
||||
if (expense == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ExpenseLine> expenseLineList =
|
||||
Beans.get(ExpenseService.class).getExpenseLineList(expense);
|
||||
if (expenseLineList != null && !expenseLineList.isEmpty()) {
|
||||
Iterator<ExpenseLine> expenseLineIter = expenseLineList.iterator();
|
||||
while (expenseLineIter.hasNext()) {
|
||||
ExpenseLine generalExpenseLine = expenseLineIter.next();
|
||||
|
||||
if (generalExpenseLine.getKilometricExpense() != null
|
||||
&& (expense.getKilometricExpenseLineList() != null
|
||||
&& !expense.getKilometricExpenseLineList().contains(generalExpenseLine)
|
||||
|| expense.getKilometricExpenseLineList() == null)) {
|
||||
|
||||
expenseLineIter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
response.setValue("expenseLineList", expenseLineList);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used in mobile application.
|
||||
* It was in ExpenseServiceImpl
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* POST /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:insertOrUpdateExpenseLine
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:insertOrUpdateExpenseLine
|
||||
* fields: (id,) project, expenseType, date, comments, toInvoice, unTaxTotal, taxTotal, justification
|
||||
*
|
||||
* payload:
|
||||
* { "data": {
|
||||
* "action": "com.axelor.apps.hr.mobile.HumanResourceMobileController:insertOrUpdateExpenseLine",
|
||||
* "id": 1,
|
||||
* "project": 2,
|
||||
* "expenseType": 10,
|
||||
* "date": "2018-02-22",
|
||||
* "comments": "No",
|
||||
* "toInvoice": "no",
|
||||
* "unTaxTotal": 100,
|
||||
* "taxTotal": 2,
|
||||
* "justification": "no"
|
||||
* } }
|
||||
*/
|
||||
@Transactional
|
||||
public void insertOrUpdateExpenseLine(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
User user = AuthUtils.getUser();
|
||||
Map<String, Object> requestData = request.getData();
|
||||
Project project =
|
||||
Beans.get(ProjectRepository.class)
|
||||
.find(Long.valueOf(requestData.get("project").toString()));
|
||||
Product product =
|
||||
Beans.get(ProductRepository.class)
|
||||
.find(Long.valueOf(requestData.get("expenseType").toString()));
|
||||
if (user != null) {
|
||||
ExpenseService expenseService = Beans.get(ExpenseService.class);
|
||||
Expense expense = expenseService.getOrCreateExpense(user);
|
||||
|
||||
ExpenseLine expenseLine;
|
||||
Object idO = requestData.get("id");
|
||||
if (idO != null) {
|
||||
expenseLine = Beans.get(ExpenseLineRepository.class).find(Long.valueOf(idO.toString()));
|
||||
} else {
|
||||
expenseLine = new ExpenseLine();
|
||||
}
|
||||
expenseLine.setExpenseDate(
|
||||
LocalDate.parse(requestData.get("date").toString(), DateTimeFormatter.ISO_DATE));
|
||||
expenseLine.setComments(requestData.get("comments").toString());
|
||||
expenseLine.setExpenseProduct(product);
|
||||
expenseLine.setProject(project);
|
||||
expenseLine.setUser(user);
|
||||
expenseLine.setTotalAmount(new BigDecimal(requestData.get("unTaxTotal").toString()));
|
||||
expenseLine.setTotalTax(new BigDecimal(requestData.get("taxTotal").toString()));
|
||||
expenseLine.setUntaxedAmount(
|
||||
expenseLine.getTotalAmount().subtract(expenseLine.getTotalTax()));
|
||||
expenseLine.setToInvoice(new Boolean(requestData.get("toInvoice").toString()));
|
||||
String justification = (String) requestData.get("justification");
|
||||
|
||||
if (!Strings.isNullOrEmpty(justification)) {
|
||||
String MIME_IMAGE_X_ICON = "image/x-icon";
|
||||
String MIME_IMAGE_SVG_XML = "image/svg+xml";
|
||||
String MIME_IMAGE_BMP = "image/bmp";
|
||||
String MIME_IMAGE_GIF = "image/gif";
|
||||
String MIME_IMAGE_JPEG = "image/jpeg";
|
||||
String MIME_IMAGE_TIFF = "image/tiff";
|
||||
String MIME_IMAGE_PNG = "image/png";
|
||||
|
||||
Map<String, String> mimeTypeMapping = new HashMap<>(200);
|
||||
|
||||
mimeTypeMapping.put(MIME_IMAGE_X_ICON, "ico");
|
||||
mimeTypeMapping.put(MIME_IMAGE_SVG_XML, "svg");
|
||||
mimeTypeMapping.put(MIME_IMAGE_BMP, "bmp");
|
||||
mimeTypeMapping.put(MIME_IMAGE_GIF, "gif");
|
||||
mimeTypeMapping.put(MIME_IMAGE_JPEG, "jpg");
|
||||
mimeTypeMapping.put(MIME_IMAGE_TIFF, "tif");
|
||||
mimeTypeMapping.put(MIME_IMAGE_PNG, "png");
|
||||
|
||||
byte[] decodedFile = Base64.getDecoder().decode(justification);
|
||||
String formatName =
|
||||
URLConnection.guessContentTypeFromStream(new ByteArrayInputStream(decodedFile));
|
||||
String extension = "";
|
||||
if (mimeTypeMapping.containsKey(formatName)) {
|
||||
extension = "." + mimeTypeMapping.get(formatName);
|
||||
File file = MetaFiles.createTempFile("justification", extension).toFile();
|
||||
Files.write(decodedFile, file);
|
||||
MetaFile metaFile = Beans.get(MetaFiles.class).upload(file);
|
||||
expenseLine.setJustificationMetaFile(metaFile);
|
||||
}
|
||||
}
|
||||
expense.addGeneralExpenseLineListItem(expenseLine);
|
||||
expense = expenseService.compute(expense);
|
||||
|
||||
Beans.get(ExpenseRepository.class).save(expense);
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("id", expenseLine.getId());
|
||||
response.setData(data);
|
||||
response.setTotal(1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used in mobile application.
|
||||
* It was in TimesheetServiceImpl
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* POST /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:getActivities
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:getActivities
|
||||
* no field
|
||||
*
|
||||
* payload:
|
||||
* { "data": {
|
||||
* "action": "com.axelor.apps.hr.mobile.HumanResourceMobileController:getActivities"
|
||||
* } }
|
||||
*/
|
||||
@Transactional
|
||||
public void getActivities(ActionRequest request, ActionResponse response) {
|
||||
List<Map<String, String>> dataList = new ArrayList<>();
|
||||
try {
|
||||
List<Product> productList =
|
||||
Beans.get(ProductRepository.class).all().filter("self.isActivity = true").fetch();
|
||||
for (Product product : productList) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("name", product.getName());
|
||||
map.put("id", product.getId().toString());
|
||||
dataList.add(map);
|
||||
}
|
||||
response.setData(dataList);
|
||||
} catch (Exception e) {
|
||||
response.setStatus(-1);
|
||||
response.setError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used in mobile application.
|
||||
* It was in TimesheetServiceImpl
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* POST /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:insertOrUpdateTSLine
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:insertOrUpdateTSLine
|
||||
* fields: (id,) project, activity, date, duration, comments
|
||||
*
|
||||
* payload:
|
||||
* { "data": {
|
||||
* "action": "com.axelor.apps.hr.mobile.HumanResourceMobileController:insertOrUpdateTSLine",
|
||||
* "id": 1,
|
||||
* "project": 1,
|
||||
* "activity": 2,
|
||||
* "date": "2018-02-22",
|
||||
* "duration": 10,
|
||||
* "comments": "no"
|
||||
* } }
|
||||
*/
|
||||
@Transactional
|
||||
public void insertOrUpdateTSLine(
|
||||
ActionRequest request, ActionResponse response) { // insert TimesheetLine
|
||||
try {
|
||||
Map<String, Object> requestData = request.getData();
|
||||
User user = AuthUtils.getUser();
|
||||
Project project =
|
||||
Beans.get(ProjectRepository.class)
|
||||
.find(new Long(request.getData().get("project").toString()));
|
||||
Product product =
|
||||
Beans.get(ProductRepository.class)
|
||||
.find(new Long(request.getData().get("activity").toString()));
|
||||
LocalDate date =
|
||||
LocalDate.parse(request.getData().get("date").toString(), DateTimeFormatter.ISO_DATE);
|
||||
TimesheetRepository timesheetRepository = Beans.get(TimesheetRepository.class);
|
||||
TimesheetService timesheetService = Beans.get(TimesheetService.class);
|
||||
TimesheetLineService timesheetLineService = Beans.get(TimesheetLineService.class);
|
||||
|
||||
if (user != null) {
|
||||
Timesheet timesheet =
|
||||
timesheetRepository
|
||||
.all()
|
||||
.filter("self.statusSelect = 1 AND self.user.id = ?1", user.getId())
|
||||
.order("-id")
|
||||
.fetchOne();
|
||||
if (timesheet == null) {
|
||||
timesheet = timesheetService.createTimesheet(user, date, date);
|
||||
}
|
||||
BigDecimal hours = new BigDecimal(request.getData().get("duration").toString());
|
||||
|
||||
TimesheetLine line;
|
||||
Object idO = requestData.get("id");
|
||||
if (idO != null) {
|
||||
line =
|
||||
timesheetLineService.updateTimesheetLine(
|
||||
Beans.get(TimesheetLineRepository.class).find(Long.valueOf(idO.toString())),
|
||||
project,
|
||||
product,
|
||||
user,
|
||||
date,
|
||||
timesheet,
|
||||
hours,
|
||||
request.getData().get("comments").toString());
|
||||
} else {
|
||||
line =
|
||||
timesheetLineService.createTimesheetLine(
|
||||
project,
|
||||
product,
|
||||
user,
|
||||
date,
|
||||
timesheet,
|
||||
hours,
|
||||
request.getData().get("comments").toString());
|
||||
}
|
||||
|
||||
// convert hours to what is defined in timeLoggingPreferenceSelect
|
||||
BigDecimal duration = timesheetLineService.computeHoursDuration(timesheet, hours, false);
|
||||
line.setDuration(duration);
|
||||
|
||||
timesheet.addTimesheetLineListItem(line);
|
||||
|
||||
timesheetRepository.save(timesheet);
|
||||
response.setTotal(1);
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("id", line.getId());
|
||||
response.setData(data);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used in mobile application.
|
||||
* It was in LeaveServiceImpl
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* POST /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:insertLeave
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:insertLeave
|
||||
* fields: leaveReason, fromDateT, startOn, toDateT, endOn, comment
|
||||
*
|
||||
* payload:
|
||||
* { "data": {
|
||||
* "action": "com.axelor.apps.hr.mobile.HumanResourceMobileController:insertLeave",
|
||||
* "leaveReason": 10,
|
||||
* "fromDateT": "2018-02-22T10:30:00",
|
||||
* "startOn": 1,
|
||||
* "toDateT": "2018-02-24T:19:30:00",
|
||||
* "endOn": 1,
|
||||
* "comment": "no"
|
||||
* } }
|
||||
*/
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void insertLeave(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
AppBaseService appBaseService = Beans.get(AppBaseService.class);
|
||||
User user = AuthUtils.getUser();
|
||||
Map<String, Object> requestData = request.getData();
|
||||
LeaveReason leaveReason =
|
||||
Beans.get(LeaveReasonRepository.class)
|
||||
.find(Long.valueOf(requestData.get("leaveReason").toString()));
|
||||
Employee employee = user.getEmployee();
|
||||
if (employee == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),
|
||||
user.getName());
|
||||
}
|
||||
if (leaveReason != null) {
|
||||
LeaveRequest leave = new LeaveRequest();
|
||||
leave.setUser(user);
|
||||
Company company = null;
|
||||
if (employee.getMainEmploymentContract() != null) {
|
||||
company = employee.getMainEmploymentContract().getPayCompany();
|
||||
}
|
||||
leave.setCompany(company);
|
||||
LeaveLine leaveLine =
|
||||
Beans.get(LeaveLineRepository.class)
|
||||
.all()
|
||||
.filter("self.employee = ?1 AND self.leaveReason = ?2", employee, leaveReason)
|
||||
.fetchOne();
|
||||
if (leaveLine == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.LEAVE_LINE),
|
||||
employee.getName(),
|
||||
leaveReason.getLeaveReason());
|
||||
}
|
||||
leave.setLeaveLine(leaveLine);
|
||||
leave.setRequestDate(appBaseService.getTodayDate());
|
||||
if (requestData.get("fromDateT") != null) {
|
||||
leave.setFromDateT(
|
||||
LocalDateTime.parse(
|
||||
requestData.get("fromDateT").toString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME));
|
||||
}
|
||||
leave.setStartOnSelect(new Integer(requestData.get("startOn").toString()));
|
||||
if (requestData.get("toDateT") != null) {
|
||||
leave.setToDateT(
|
||||
LocalDateTime.parse(
|
||||
requestData.get("toDateT").toString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME));
|
||||
}
|
||||
leave.setEndOnSelect(new Integer(requestData.get("endOn").toString()));
|
||||
leave.setDuration(Beans.get(LeaveService.class).computeDuration(leave));
|
||||
leave.setStatusSelect(LeaveRequestRepository.STATUS_AWAITING_VALIDATION);
|
||||
if (requestData.get("comments") != null) {
|
||||
leave.setComments(requestData.get("comments").toString());
|
||||
}
|
||||
leave = Beans.get(LeaveRequestRepository.class).save(leave);
|
||||
response.setTotal(1);
|
||||
response.setValue("id", leave.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used in mobile application.
|
||||
* It was in LeaveServiceImpl
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* POST /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:getLeaveReason
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:getLeaveReason
|
||||
* fields: no field
|
||||
*
|
||||
* payload:
|
||||
* { "data": {
|
||||
* "action": "com.axelor.apps.hr.mobile.HumanResourceMobileController:getLeaveReason"
|
||||
* } }
|
||||
*/
|
||||
@Transactional
|
||||
public void getLeaveReason(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
User user = AuthUtils.getUser();
|
||||
|
||||
List<Map<String, String>> dataList = new ArrayList<>();
|
||||
|
||||
if (user == null || user.getEmployee() == null) {
|
||||
|
||||
List<LeaveReason> leaveReasonList = Beans.get(LeaveReasonRepository.class).all().fetch();
|
||||
for (LeaveReason leaveReason : leaveReasonList) {
|
||||
if (leaveReason.getUnitSelect() == LeaveReasonRepository.UNIT_SELECT_DAYS) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("name", leaveReason.getLeaveReason());
|
||||
map.put("id", leaveReason.getId().toString());
|
||||
dataList.add(map);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (user.getEmployee() != null) {
|
||||
List<LeaveLine> leaveLineList =
|
||||
Beans.get(LeaveLineRepository.class)
|
||||
.all()
|
||||
.filter("self.employee = ?1", user.getEmployee())
|
||||
.order("name")
|
||||
.fetch();
|
||||
|
||||
String tmpName = "";
|
||||
for (LeaveLine leaveLine : leaveLineList) {
|
||||
String name = leaveLine.getName();
|
||||
if (tmpName != name) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("name", leaveLine.getName());
|
||||
map.put("id", leaveLine.getLeaveReason().getId().toString());
|
||||
map.put("quantity", leaveLine.getQuantity().toString());
|
||||
dataList.add(map);
|
||||
}
|
||||
tmpName = name;
|
||||
}
|
||||
}
|
||||
response.setData(dataList);
|
||||
response.setTotal(dataList.size());
|
||||
} catch (Exception e) {
|
||||
response.setStatus(-1);
|
||||
response.setError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used in mobile application.
|
||||
* It was in ExpenseServiceImpl
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* POST /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:getExpensesTypes
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:getExpensesTypes
|
||||
* fields: no field
|
||||
*
|
||||
* payload:
|
||||
* { "data": {
|
||||
* "action": "com.axelor.apps.hr.mobile.HumanResourceMobileController:getExpensesTypes"
|
||||
* } }
|
||||
*/
|
||||
@Transactional
|
||||
public void getExpensesTypes(ActionRequest request, ActionResponse response) {
|
||||
List<Map<String, String>> dataList = new ArrayList<>();
|
||||
try {
|
||||
List<Product> productList =
|
||||
Beans.get(ProductRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.expense = true AND coalesce(self.unavailableToUsers, false) = false AND coalesce(self.personalExpense, false) = false")
|
||||
.fetch();
|
||||
for (Product product : productList) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("name", product.getName());
|
||||
map.put("id", product.getId().toString());
|
||||
dataList.add(map);
|
||||
}
|
||||
response.setData(dataList);
|
||||
response.setTotal(dataList.size());
|
||||
} catch (Exception e) {
|
||||
response.setStatus(-1);
|
||||
response.setError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used in mobile application.
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* POST /open-suite-webapp/ws/action/com.axelor.apps.hr.mobile.HumanResourceMobileController:getKilometricAllowParam
|
||||
* Content-Type: application/json
|
||||
*
|
||||
* URL: com.axelor.apps.hr.mobile.HumanResourceMobileController:getKilometricAllowParam
|
||||
* fields: no field
|
||||
*
|
||||
* payload:
|
||||
* { "data": {
|
||||
* "action": "com.axelor.apps.hr.mobile.HumanResourceMobileController:getKilometricAllowParam"
|
||||
* } }
|
||||
*/
|
||||
@Transactional
|
||||
public void getKilometricAllowParam(ActionRequest request, ActionResponse response) {
|
||||
List<Map<String, String>> dataList = new ArrayList<>();
|
||||
try {
|
||||
User user = AuthUtils.getUser();
|
||||
List<EmployeeVehicle> employeeVehicleList =
|
||||
Beans.get(EmployeeVehicleRepository.class)
|
||||
.all()
|
||||
.filter("self.employee = ?1", user.getEmployee())
|
||||
.fetch();
|
||||
|
||||
// Not sorted by default ?
|
||||
employeeVehicleList.sort(
|
||||
(employeeVehicle1, employeeVehicle2) ->
|
||||
employeeVehicle1
|
||||
.getKilometricAllowParam()
|
||||
.getCode()
|
||||
.compareTo(employeeVehicle2.getKilometricAllowParam().getCode()));
|
||||
|
||||
for (EmployeeVehicle employeeVehicle : employeeVehicleList) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("name", employeeVehicle.getKilometricAllowParam().getName());
|
||||
map.put("id", employeeVehicle.getKilometricAllowParam().getId().toString());
|
||||
dataList.add(map);
|
||||
}
|
||||
response.setData(dataList);
|
||||
} catch (Exception e) {
|
||||
response.setStatus(-1);
|
||||
response.setError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.module;
|
||||
|
||||
import com.axelor.app.AxelorModule;
|
||||
import com.axelor.apps.account.db.repo.PartnerAccountRepository;
|
||||
import com.axelor.apps.account.service.batch.BatchCreditTransferExpensePayment;
|
||||
import com.axelor.apps.account.service.config.AccountConfigService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderLineOriginServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderMergeServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderServiceImpl;
|
||||
import com.axelor.apps.base.db.repo.UserBaseRepository;
|
||||
import com.axelor.apps.base.service.batch.MailBatchService;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseRepository;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.apps.hr.db.repo.PartnerHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.ProjectHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.ProjectPlanningTimeHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.TSTimerRepository;
|
||||
import com.axelor.apps.hr.db.repo.TeamTaskHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetLineHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetTimerHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.UserHRRepository;
|
||||
import com.axelor.apps.hr.service.app.AppHumanResourceService;
|
||||
import com.axelor.apps.hr.service.app.AppHumanResourceServiceImpl;
|
||||
import com.axelor.apps.hr.service.bankorder.BankOrderLineOriginServiceHRImpl;
|
||||
import com.axelor.apps.hr.service.bankorder.BankOrderMergeHRServiceImpl;
|
||||
import com.axelor.apps.hr.service.bankorder.BankOrderServiceHRImpl;
|
||||
import com.axelor.apps.hr.service.batch.BatchCreditTransferExpensePaymentHR;
|
||||
import com.axelor.apps.hr.service.batch.MailBatchServiceHR;
|
||||
import com.axelor.apps.hr.service.config.AccountConfigHRService;
|
||||
import com.axelor.apps.hr.service.employee.EmployeeService;
|
||||
import com.axelor.apps.hr.service.employee.EmployeeServiceImpl;
|
||||
import com.axelor.apps.hr.service.expense.ExpenseService;
|
||||
import com.axelor.apps.hr.service.expense.ExpenseServiceImpl;
|
||||
import com.axelor.apps.hr.service.extra.hours.ExtraHoursService;
|
||||
import com.axelor.apps.hr.service.extra.hours.ExtraHoursServiceImpl;
|
||||
import com.axelor.apps.hr.service.leave.LeaveService;
|
||||
import com.axelor.apps.hr.service.leave.LeaveServiceImpl;
|
||||
import com.axelor.apps.hr.service.DailyReportService;
|
||||
import com.axelor.apps.hr.service.DailyReportServiceImpl;
|
||||
import com.axelor.apps.hr.service.lunch.voucher.LunchVoucherAdvanceService;
|
||||
import com.axelor.apps.hr.service.lunch.voucher.LunchVoucherAdvanceServiceImpl;
|
||||
import com.axelor.apps.hr.service.lunch.voucher.LunchVoucherMgtLineService;
|
||||
import com.axelor.apps.hr.service.lunch.voucher.LunchVoucherMgtLineServiceImpl;
|
||||
import com.axelor.apps.hr.service.lunch.voucher.LunchVoucherMgtService;
|
||||
import com.axelor.apps.hr.service.lunch.voucher.LunchVoucherMgtServiceImpl;
|
||||
import com.axelor.apps.hr.service.project.ProjectPlanningTimeService;
|
||||
import com.axelor.apps.hr.service.project.ProjectPlanningTimeServiceImpl;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetLineService;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetLineServiceImpl;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetReportService;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetReportServiceImpl;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetService;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetServiceImpl;
|
||||
import com.axelor.apps.hr.service.timesheet.timer.TimesheetTimerService;
|
||||
import com.axelor.apps.hr.service.timesheet.timer.TimesheetTimerServiceImpl;
|
||||
import com.axelor.apps.hr.service.user.UserHrService;
|
||||
import com.axelor.apps.hr.service.user.UserHrServiceImpl;
|
||||
import com.axelor.apps.project.db.repo.ProjectManagementRepository;
|
||||
import com.axelor.apps.project.db.repo.ProjectPlanningTimeRepository;
|
||||
import com.axelor.apps.project.db.repo.TeamTaskProjectRepository;
|
||||
import com.axelor.apps.hr.service.AuthorizationService;
|
||||
import com.axelor.apps.hr.service.AuthorizationServiceImpl;
|
||||
|
||||
public class HumanResourceModule extends AxelorModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
bind(EmployeeService.class).to(EmployeeServiceImpl.class);
|
||||
bind(TimesheetService.class).to(TimesheetServiceImpl.class);
|
||||
bind(TimesheetLineService.class).to(TimesheetLineServiceImpl.class);
|
||||
bind(TimesheetTimerService.class).to(TimesheetTimerServiceImpl.class);
|
||||
bind(TimesheetRepository.class).to(TimesheetHRRepository.class);
|
||||
bind(TimesheetLineRepository.class).to(TimesheetLineHRRepository.class);
|
||||
bind(TSTimerRepository.class).to(TimesheetTimerHRRepository.class);
|
||||
bind(MailBatchService.class).to(MailBatchServiceHR.class);
|
||||
bind(AccountConfigService.class).to(AccountConfigHRService.class);
|
||||
bind(ExtraHoursService.class).to(ExtraHoursServiceImpl.class);
|
||||
bind(LeaveService.class).to(LeaveServiceImpl.class);
|
||||
bind(ExpenseService.class).to(ExpenseServiceImpl.class);
|
||||
bind(LunchVoucherMgtService.class).to(LunchVoucherMgtServiceImpl.class);
|
||||
bind(LunchVoucherMgtLineService.class).to(LunchVoucherMgtLineServiceImpl.class);
|
||||
bind(AppHumanResourceService.class).to(AppHumanResourceServiceImpl.class);
|
||||
bind(LunchVoucherAdvanceService.class).to(LunchVoucherAdvanceServiceImpl.class);
|
||||
bind(UserHrService.class).to(UserHrServiceImpl.class);
|
||||
bind(ExpenseRepository.class).to(ExpenseHRRepository.class);
|
||||
bind(EmployeeRepository.class).to(EmployeeHRRepository.class);
|
||||
bind(BatchCreditTransferExpensePayment.class).to(BatchCreditTransferExpensePaymentHR.class);
|
||||
bind(BankOrderServiceImpl.class).to(BankOrderServiceHRImpl.class);
|
||||
bind(BankOrderLineOriginServiceImpl.class).to(BankOrderLineOriginServiceHRImpl.class);
|
||||
bind(HrBatchRepository.class).to(HrBatchHRRepository.class);
|
||||
bind(ProjectPlanningTimeRepository.class).to(ProjectPlanningTimeHRRepository.class);
|
||||
bind(ProjectPlanningTimeService.class).to(ProjectPlanningTimeServiceImpl.class);
|
||||
bind(ProjectManagementRepository.class).to(ProjectHRRepository.class);
|
||||
bind(TeamTaskProjectRepository.class).to(TeamTaskHRRepository.class);
|
||||
bind(UserBaseRepository.class).to(UserHRRepository.class);
|
||||
bind(PartnerAccountRepository.class).to(PartnerHRRepository.class);
|
||||
bind(BankOrderMergeServiceImpl.class).to(BankOrderMergeHRServiceImpl.class);
|
||||
bind(TimesheetReportService.class).to(TimesheetReportServiceImpl.class);
|
||||
bind(DailyReportService.class).to(DailyReportServiceImpl.class);
|
||||
bind(AuthorizationService.class).to(AuthorizationServiceImpl.class);
|
||||
bind(ExtraHoursService.class).to(ExtraHoursServiceImpl.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.report;
|
||||
|
||||
public interface IReport {
|
||||
|
||||
public static final String EMPLYOMENT_CONTRACT = "EmploymentContract.rptdesign";
|
||||
public static final String EXPENSE = "Expense.rptdesign";
|
||||
public static final String TIMESHEET = "Timesheet.rptdesign";
|
||||
public static final String EMPLOYEE_BONUS_MANAGEMENT = "EmployeeBonusMgt.rptdesign";
|
||||
public static final String EMPLOYEE_ANNUAL_REPORT = "EmployeeAnnualReport.rptdesign";
|
||||
public static final String LUNCH_VOUCHER_MGT_MONTHLY = "LunchVoucherMgt_Monthly.rptdesign";
|
||||
public static final String LUNCH_VOUCHER_ADVANCE = "LunchVoucherAdvance.rptdesign";
|
||||
public static final String EMPLOYEE_PHONEBOOK = "EmployeePhoneBook.rptdesign";
|
||||
public static final String EMPLOYEE_TIMESHEET = "EmployeeTimesheet.rptdesign";
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.report;
|
||||
|
||||
public class ITranslation {
|
||||
|
||||
public static final String EXPENSE_EXPENSE_OF = /*$$(*/ "Expense.expenseOf"; /*)*/
|
||||
public static final String EXPENSE_EMPLOYEE_NAME = /*$$(*/ "Expense.employeeName"; /*)*/
|
||||
public static final String EXPENSE_DATE = /*$$(*/ "Expense.expenseDate"; /*)*/
|
||||
public static final String EXPENSE_PERIOD = /*$$(*/ "Expense.period"; /*)*/
|
||||
public static final String EXPENSE_COMMENTS = /*$$(*/ "Expense.comments"; /*)*/
|
||||
public static final String EXPENSE_AMOUNT = /*$$(*/ "Expense.totalAmount"; /*)*/
|
||||
public static final String EXPENSE_EMPLOYEE_SIGNATURE = /*$$(*/ "Expense.employeeSignature"; /*)*/
|
||||
public static final String EXPENSE_EMPLOYER_SIGNATURE = /*$$(*/ "Expense.employerSignature"; /*)*/
|
||||
public static final String EXPENSE_WITHDRAWN_CASH = /*$$(*/ "Expense.withdrawnCash"; /*)*/
|
||||
public static final String EXPENSE_PERSONAL_EXPENSE_AMOUNT = /*$$(*/
|
||||
"Expense.personalExpenseAmount"; /*)*/
|
||||
public static final String EXPENSE_COMPANY_CB_SELECT = /*$$(*/ "Expense.companyCbSelect"; /*)*/
|
||||
public static final String EXPENSE_ADVANCE_AMOUNT = /*$$(*/ "Expense.advanceAmount"; /*)*/
|
||||
public static final String EXPENSE_MULTIPLE_USERS = /*$$(*/ "Expense.multipleUsers"; /*)*/
|
||||
public static final String EXPENSE_TOTAL_LABEL = /*$$(*/ "Expense.total"; /*)*/
|
||||
public static final String EXPENSE_CURRENCY = /*$$(*/ "Expense.currency"; /*)*/
|
||||
public static final String EXPENSE_GENERAL_EXPENSES = /*$$(*/ "General Expenses"; /*)*/
|
||||
|
||||
public static final String EXPENSE_LINE_EXPENSE_DATE = /*$$(*/ "ExpenseLine.expenseDate"; /*)*/
|
||||
public static final String EXPENSE_LINE_CLIENT = /*$$(*/ "ExpenseLine.client"; /*)*/
|
||||
public static final String EXPENSE_LINE_PROJECT = /*$$(*/ "ExpenseLine.project"; /*)*/
|
||||
public static final String EXPENSE_LINE_EXPENSE_TYPE = /*$$(*/ "ExpenseLine.expenseType"; /*)*/
|
||||
public static final String EXPENSE_LINE_AMOUNT = /*$$(*/ "ExpenseLine.amount"; /*)*/
|
||||
public static final String EXPENSE_LINE_UNTAXED_AMOUNT = /*$$(*/
|
||||
"ExpenseLine.untaxedAmount"; /*)*/
|
||||
public static final String EXPENSE_LINE_TOTAL_TAXED = /*$$(*/ "ExpenseLine.totalTax"; /*)*/
|
||||
public static final String EXPENSE_LINE_DISTANCE = /*$$(*/ "ExpenseLine.distance"; /*)*/
|
||||
public static final String EXPENSE_LINE_CITY_FROM = /*$$(*/ "ExpenseLine.cityFrom"; /*)*/
|
||||
public static final String EXPENSE_LINE_CITY_TO = /*$$(*/ "ExpenseLine.cityTo"; /*)*/
|
||||
public static final String EXPENSE_LINE_KILOMETRIC_ALLOW_PARAM = /*$$(*/
|
||||
"ExpenseLine.kilometricAllowParam"; /*)*/
|
||||
public static final String EXPENSE_LINE_KILOMETRIC_EXPENSE_TYPE = /*$$(*/
|
||||
"ExpenseLine.kilometricExpenseType"; /*)*/
|
||||
|
||||
public static final String TIMESHEET_OF = /*$$(*/ "Timesheet.timesheetOf"; /*)*/
|
||||
public static final String TIMESHEET_PROJECT = /*$$(*/ "TimesheetLine.project"; /*)*/
|
||||
public static final String TIMESHEET_PRODUCT = /*$$(*/ "TimesheetLine.product"; /*)*/
|
||||
public static final String TIMESHEET_DURATION = /*$$(*/ "TimesheetLine.duration"; /*)*/
|
||||
public static final String TIMESHEET_TOTAL_DURATION = /*$$(*/ "Timesheet.totalDuration"; /*)*/
|
||||
|
||||
public static final String ANNUAL_REPORT_OF = /*$$(*/ "Employee.annualReportOf"; /*)*/
|
||||
|
||||
public static final String TOTAL_TO_REFUND = /*$$(*/ "TotalToRefund"; /*)*/
|
||||
|
||||
public static final String LUNCH_VOUCHER_SIGNATURE_DOCUMENT = /*$$(*/
|
||||
"LunchVoucher.signatureDocument"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_MONTH = /*$$(*/ "LunchVoucher.month"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_FROM = /*$$(*/ "LunchVoucher.lvFrom"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_LEAVES_FROM = /*$$(*/ "LunchVoucher.leavesFrom"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_TO = /*$$(*/ "LunchVoucher.to"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_NAMES = /*$$(*/ "LunchVoucher.names"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_QTY = /*$$(*/ "LunchVoucher.qty"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_AMOUNT = /*$$(*/ "LunchVoucher.amount"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_COMMENT = /*$$(*/ "LunchVoucher.comment"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_EMPLOYER_SHARE = /*$$(*/
|
||||
"LunchVoucher.employerShare"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_EMPLOYEE_SHARE = /*$$(*/
|
||||
"LunchVoucher.employeeShare"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_TOTAL = /*$$(*/ "LunchVoucher.total"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_SUBTOTAL = /*$$(*/ "LunchVoucher.subtotal"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_HANDED_ON = /*$$(*/ "LunchVoucher.handedOn"; /*)*/
|
||||
public static final String LUNCH_VOUCHER_SIGNATURE = /*$$(*/ "LunchVoucher.signature"; /*)*/
|
||||
|
||||
public static final String EDITOR_ADD_LINE = /*$$(*/ "Add a line"; /*)*/
|
||||
|
||||
public static final String PHONE_BOOK_COMPANY_PHONE_BOOK = /*$$(*/
|
||||
"Phonebook.employeePhonebook"; /*)*/
|
||||
|
||||
public static final String EMPLOYEE_TIMESHEET_FROM_DATE = /*$$(*/
|
||||
"EmployeeTimesheet.fromDate"; /*)*/
|
||||
public static final String EMPLOYEE_TIMESHEET_TO_DATE = /*$$(*/ "EmployeeTimesheet.toDate"; /*)*/
|
||||
public static final String EMPLOYEE_TIMESHEET_USER = /*$$(*/ "EmployeeTimesheet.user"; /*)*/
|
||||
public static final String EMPLOYEE_TIMESHEET_WEEK_TOTAL = /*$$(*/
|
||||
"EmployeeTimesheet.weekTotal"; /*)*/
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.hr.db.Absence;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public interface AbsenceService {
|
||||
|
||||
@Transactional
|
||||
void attachTheAbsenceWithDailyReport(Absence absence, List<DailyReport> dailyreports);
|
||||
|
||||
@Transactional
|
||||
void deAttachTheAbsenceWithDailyReport(
|
||||
Absence absence, List<DailyReport> dailyreports, Boolean archive);
|
||||
|
||||
@Transactional
|
||||
void chooseAbsenceType(Absence absence, Integer selectedType);
|
||||
|
||||
@Transactional
|
||||
BigDecimal calculateTotalAbsenceHours(
|
||||
LocalDateTime absenceStartDate, LocalDateTime absenceEndDate);
|
||||
|
||||
BigDecimal calculateTotalAbsenceMinutes(
|
||||
LocalDateTime absenceStartDate, LocalDateTime absenceEndDate);
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.base.db.EventsPlanningLine;
|
||||
import com.axelor.apps.base.db.repo.EventsPlanningLineRepository;
|
||||
import com.axelor.apps.hr.db.Absence;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
public class AbsenceServiceImpl implements AbsenceService {
|
||||
|
||||
private final AbsenceRepository absenceRepository;
|
||||
private final DailyReportRepository dailyReportRepository;
|
||||
private List<EventsPlanningLine> eventsPlanningLines;
|
||||
|
||||
@Inject
|
||||
public AbsenceServiceImpl(
|
||||
AbsenceRepository absenceRepository, DailyReportRepository dailyReportRepository) {
|
||||
this.absenceRepository = absenceRepository;
|
||||
this.dailyReportRepository = dailyReportRepository;
|
||||
eventsPlanningLines =
|
||||
Beans.get(EventsPlanningLineRepository.class).all().filter("self.id = 4").fetch();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void attachTheAbsenceWithDailyReport(Absence absence, List<DailyReport> dailyreports) {
|
||||
// Iterate over each DailyReport in the list
|
||||
for (DailyReport dailyreport : dailyreports) {
|
||||
dailyreport.addAbsenceSetItem(absence); // Set the absence for each report
|
||||
dailyReportRepository.save(dailyreport);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deAttachTheAbsenceWithDailyReport(
|
||||
Absence absence, List<DailyReport> dailyreports, Boolean archive) {
|
||||
if (dailyreports != null) {
|
||||
// Iterate over each DailyReport in the list
|
||||
for (DailyReport dailyreport : dailyreports) {
|
||||
dailyreport.removeAbsenceSetItem(null); // Set the absence for each report
|
||||
dailyReportRepository.save(dailyreport);
|
||||
}
|
||||
}
|
||||
|
||||
if (archive) {
|
||||
absence.setArchived(true);
|
||||
absenceRepository.save(absence);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void chooseAbsenceType(Absence absence, Integer selectedType) {
|
||||
// Set the selected absence type to the absence entity
|
||||
// Assuming you have a field named 'typeAbsence' in the Absence entity
|
||||
absence.setAbsenceType(selectedType);
|
||||
|
||||
// Save the absence entity
|
||||
absenceRepository.save(absence);
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalAbsenceHours(
|
||||
LocalDateTime absenceStartDate, LocalDateTime absenceEndDate) {
|
||||
BigDecimal totalAbsenceHours = BigDecimal.ZERO;
|
||||
|
||||
if (absenceStartDate.equals(absenceEndDate)) {
|
||||
totalAbsenceHours = BigDecimal.valueOf(8);
|
||||
} else if (absenceStartDate.toLocalDate().equals(absenceEndDate.toLocalDate())) {
|
||||
// If the start and end dates are the same, calculate the hour difference
|
||||
long hours = ChronoUnit.HOURS.between(absenceStartDate, absenceEndDate);
|
||||
totalAbsenceHours = BigDecimal.valueOf(hours);
|
||||
} else {
|
||||
long absenceDays = 0;
|
||||
LocalDate currentDate = absenceStartDate.toLocalDate();
|
||||
|
||||
// Loop through each day between start and end date
|
||||
while (!currentDate.isAfter(absenceEndDate.toLocalDate())) {
|
||||
DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
|
||||
|
||||
// Exclude Friday (5) and Saturday (6) and holidays
|
||||
if (dayOfWeek != DayOfWeek.FRIDAY
|
||||
&& dayOfWeek != DayOfWeek.SATURDAY
|
||||
&& !isSpecialOvertimeDay(currentDate)) {
|
||||
absenceDays++;
|
||||
}
|
||||
currentDate = currentDate.plusDays(1);
|
||||
}
|
||||
|
||||
// Multiply the counted days by 8 hours per day
|
||||
totalAbsenceHours = BigDecimal.valueOf(absenceDays).multiply(BigDecimal.valueOf(8));
|
||||
}
|
||||
return totalAbsenceHours;
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalAbsenceMinutes(
|
||||
LocalDateTime absenceStartDate, LocalDateTime absenceEndDate) {
|
||||
// Calculate the duration between the two LocalDateTime objects
|
||||
Duration duration = Duration.between(absenceStartDate, absenceEndDate);
|
||||
|
||||
// Convert the duration to minutes and then divide by 60 to get hours
|
||||
long minutes = duration.toMinutes();
|
||||
BigDecimal hours =
|
||||
BigDecimal.valueOf(minutes).divide(BigDecimal.valueOf(60), 2, BigDecimal.ROUND_HALF_UP);
|
||||
|
||||
return customRound(hours);
|
||||
}
|
||||
|
||||
private boolean isSpecialOvertimeDay(LocalDate date) {
|
||||
for (EventsPlanningLine line : eventsPlanningLines) {
|
||||
if (line.getDate().equals(date)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static BigDecimal customRound(BigDecimal value) {
|
||||
// Get the fractional part of the number
|
||||
BigDecimal fractionalPart = value.remainder(BigDecimal.ONE);
|
||||
|
||||
// Define the intervals and their corresponding rounded values
|
||||
if (fractionalPart.compareTo(new BigDecimal("0.125")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN);
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.125")) >= 0
|
||||
&& fractionalPart.compareTo(new BigDecimal("0.375")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN).add(new BigDecimal("0.25"));
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.375")) >= 0
|
||||
&& fractionalPart.compareTo(new BigDecimal("0.625")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN).add(new BigDecimal("0.50"));
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.625")) >= 0
|
||||
&& fractionalPart.compareTo(new BigDecimal("0.875")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN).add(new BigDecimal("0.75"));
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.875")) >= 0) {
|
||||
return value.setScale(0, RoundingMode.UP);
|
||||
} else {
|
||||
return value; // In case no rounding is needed
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
public interface AuthorizationService {
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveAA(JSONObject jsonObject) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveAE(JSONObject jsonObject) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveBS(JSONObject jsonObject) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveAP(JSONObject jsonObject) throws AxelorException;
|
||||
}
|
||||
@ -0,0 +1,668 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.hr.db.Authorization;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.repo.AuthorizationRepository;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import javax.inject.Inject;
|
||||
import wslite.json.JSONException;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
public class AuthorizationServiceImpl implements AuthorizationService {
|
||||
|
||||
protected EmployeeRepository employeeRepo;
|
||||
protected AuthorizationRepository authorizationRepository;
|
||||
protected DailyReportRepository dailyReportRepo;
|
||||
|
||||
@Inject
|
||||
public AuthorizationServiceImpl(
|
||||
EmployeeRepository employeeRepo,
|
||||
AuthorizationRepository authorizationRepository,
|
||||
DailyReportRepository dailyReportRepo) {
|
||||
this.employeeRepo = employeeRepo;
|
||||
this.authorizationRepository = authorizationRepository;
|
||||
this.dailyReportRepo = dailyReportRepo;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveAA(JSONObject jsonObject) throws AxelorException {
|
||||
|
||||
try {
|
||||
// Extract fields
|
||||
int idInt = jsonObject.getInt("id");
|
||||
String id = Integer.toString(idInt);
|
||||
String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
|
||||
String matricule = jsonObject.getString("matricule");
|
||||
String date_absence = jsonObject.getString("date_absence");
|
||||
String commentaire = jsonObject.getString("commentaire");
|
||||
int validation_status = jsonObject.optInt("validation_status", 2);
|
||||
String validateByUser = jsonObject.optString("validate_by_user", null);
|
||||
String dateValidation =
|
||||
jsonObject.optString("validation_date", null); // Safely get validation_date
|
||||
|
||||
// GET EMPLOYEES
|
||||
Employee employee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", matricule)
|
||||
.fetchOne();
|
||||
|
||||
if (employee == null) {
|
||||
System.err.println("Employee with matricule " + matricule + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
Employee validatedByEmployee = null;
|
||||
|
||||
if (validateByUser != null) {
|
||||
validatedByEmployee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", validateByUser)
|
||||
.fetchOne();
|
||||
|
||||
if (validatedByEmployee == null) {
|
||||
System.err.println("Validator employee with matricule " + validateByUser + " not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse validation date (handle null case)
|
||||
LocalDate validationDate = null;
|
||||
if (dateValidation != null && !dateValidation.isEmpty()) {
|
||||
try {
|
||||
OffsetDateTime offsetDateTime =
|
||||
OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing dateValidation: " + dateValidation);
|
||||
validationDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse absence Date
|
||||
LocalDate absenceDate;
|
||||
try {
|
||||
absenceDate = LocalDate.parse(date_absence);
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing date_absence: " + date_absence);
|
||||
absenceDate = null;
|
||||
}
|
||||
|
||||
// Check if Authorization exists by ticketId
|
||||
Authorization authorization =
|
||||
authorizationRepository
|
||||
.all()
|
||||
.filter("self.ticketId = :ticketId")
|
||||
.bind("ticketId", idInt)
|
||||
.fetchOne();
|
||||
|
||||
if (authorization != null) {
|
||||
// Authorization exists, compare previous and new status
|
||||
int previousStatus = authorization.getStatusSelect(); // Previous status
|
||||
int newStatus = validation_status; // New status
|
||||
|
||||
if (previousStatus == 2 && newStatus == 3) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
// Update the fields of the existing Authorization
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
dailyReport.setIsAuthorizedAbsence(true);
|
||||
}
|
||||
|
||||
} else if (previousStatus == 2 && newStatus == 4) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
} else {
|
||||
// Authorization does not exist, create a new one as per the validation_status logic
|
||||
authorization = new Authorization();
|
||||
authorization.setEmployee(employee);
|
||||
authorization.setTicketId(idInt);
|
||||
authorization.setTicket(ticketLink);
|
||||
authorization.setRequisitionDate(absenceDate);
|
||||
authorization.setDescription(commentaire);
|
||||
authorization.setStatusSelect(validation_status);
|
||||
authorization.setAuthorizationType(2); // Set default authorization type
|
||||
|
||||
if (validation_status == 3) {
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
} else if (validation_status == 4) {
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
}
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
authorization.setDailyReport(dailyReport);
|
||||
if (validation_status == 3) dailyReport.setIsAuthorizedAbsence(true);
|
||||
}
|
||||
// Save the new Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
System.err.println("Failed to parse JSON: " + jsonObject.toString());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveAE(JSONObject jsonObject) throws AxelorException {
|
||||
|
||||
try {
|
||||
// Extract fields
|
||||
int idInt = jsonObject.getInt("id");
|
||||
String id = Integer.toString(idInt);
|
||||
String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
|
||||
String matricule = jsonObject.getString("matricule");
|
||||
String date_absence = jsonObject.getString("date_reprise");
|
||||
String commentaire = jsonObject.getString("commentaire");
|
||||
int validation_status = jsonObject.optInt("validation_status", 2);
|
||||
String validateByUser = jsonObject.optString("validate_by_user", null);
|
||||
String dateValidation = jsonObject.optString("validation_date", null);
|
||||
|
||||
// GET EMPLOYEES
|
||||
Employee employee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", matricule)
|
||||
.fetchOne();
|
||||
|
||||
if (employee == null) {
|
||||
System.err.println("Employee with matricule " + matricule + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
Employee validatedByEmployee = null;
|
||||
|
||||
if (validateByUser != null) {
|
||||
validatedByEmployee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", validateByUser)
|
||||
.fetchOne();
|
||||
|
||||
if (validatedByEmployee == null) {
|
||||
System.err.println("Validator employee with matricule " + validateByUser + " not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse validation date (handle null case)
|
||||
LocalDate validationDate = null;
|
||||
if (dateValidation != null && !dateValidation.isEmpty()) {
|
||||
try {
|
||||
OffsetDateTime offsetDateTime =
|
||||
OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing dateValidation: " + dateValidation);
|
||||
validationDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse Requisition Date
|
||||
LocalDate absenceDate;
|
||||
try {
|
||||
absenceDate = LocalDate.parse(date_absence);
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing date_absence: " + date_absence);
|
||||
absenceDate = null;
|
||||
}
|
||||
|
||||
// Check if Authorization exists by ticketId
|
||||
Authorization authorization =
|
||||
authorizationRepository
|
||||
.all()
|
||||
.filter("self.ticketId = :ticketId")
|
||||
.bind("ticketId", idInt)
|
||||
.fetchOne();
|
||||
|
||||
if (authorization != null) {
|
||||
// Authorization exists, compare previous and new status
|
||||
int previousStatus = authorization.getStatusSelect(); // Previous status
|
||||
int newStatus = validation_status; // New status
|
||||
|
||||
if (previousStatus == 2 && newStatus == 3) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
// Update the fields of the existing Authorization
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
dailyReport.setIsAuthorizedLateArrival(true);
|
||||
}
|
||||
} else if (previousStatus == 2 && newStatus == 4) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
} else {
|
||||
// Authorization does not exist, create a new one as per the validation_status logic
|
||||
authorization = new Authorization();
|
||||
authorization.setEmployee(employee);
|
||||
authorization.setTicketId(idInt);
|
||||
authorization.setTicket(ticketLink);
|
||||
authorization.setRequisitionDate(absenceDate);
|
||||
authorization.setDescription(commentaire);
|
||||
authorization.setStatusSelect(validation_status);
|
||||
authorization.setAuthorizationType(1); // Set default authorization type
|
||||
|
||||
if (validation_status == 3) {
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
} else if (validation_status == 4) {
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
}
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
authorization.setDailyReport(dailyReport);
|
||||
if (validation_status == 3) dailyReport.setIsAuthorizedLateArrival(true);
|
||||
}
|
||||
// Save the new Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
System.err.println("Failed to parse JSON: " + jsonObject.toString());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveBS(JSONObject jsonObject) throws AxelorException {
|
||||
|
||||
try {
|
||||
// Extract fields
|
||||
int idInt = jsonObject.getInt("id");
|
||||
String id = Integer.toString(idInt);
|
||||
String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
|
||||
String matricule = jsonObject.getString("matricule");
|
||||
String date_absence = jsonObject.getString("date_sortie");
|
||||
String commentaire = jsonObject.getString("motif");
|
||||
String heure_sortie = jsonObject.getString("heure_sortie");
|
||||
int validation_status = jsonObject.optInt("validation_status", 2);
|
||||
String validateByUser = jsonObject.optString("validate_by_user", null);
|
||||
String dateValidation = jsonObject.optString("validation_date", null);
|
||||
|
||||
// GET EMPLOYEES
|
||||
Employee employee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", matricule)
|
||||
.fetchOne();
|
||||
|
||||
if (employee == null) {
|
||||
System.err.println("Employee with matricule " + matricule + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
Employee validatedByEmployee = null;
|
||||
|
||||
if (validateByUser != null) {
|
||||
validatedByEmployee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", validateByUser)
|
||||
.fetchOne();
|
||||
|
||||
if (validatedByEmployee == null) {
|
||||
System.err.println("Validator employee with matricule " + validateByUser + " not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse validation date (handle null case)
|
||||
LocalDate validationDate = null;
|
||||
if (dateValidation != null && !dateValidation.isEmpty()) {
|
||||
try {
|
||||
OffsetDateTime offsetDateTime =
|
||||
OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing dateValidation: " + dateValidation);
|
||||
validationDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse Requisition Date
|
||||
LocalDate absenceDate;
|
||||
try {
|
||||
absenceDate = LocalDate.parse(date_absence);
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing date_absence: " + date_absence);
|
||||
absenceDate = null;
|
||||
}
|
||||
|
||||
// Check if Authorization exists by ticketId
|
||||
Authorization authorization =
|
||||
authorizationRepository
|
||||
.all()
|
||||
.filter("self.ticketId = :ticketId")
|
||||
.bind("ticketId", idInt)
|
||||
.fetchOne();
|
||||
|
||||
if (authorization != null) {
|
||||
// Authorization exists, compare previous and new status
|
||||
int previousStatus = authorization.getStatusSelect(); // Previous status
|
||||
int newStatus = validation_status; // New status
|
||||
|
||||
if (previousStatus == 2 && newStatus == 3) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
// Update the fields of the existing Authorization
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
dailyReport.setIsAuthorizedEarlyDeparture(true);
|
||||
}
|
||||
|
||||
} else if (previousStatus == 2 && newStatus == 4) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
} else {
|
||||
String updatedDescription = commentaire + " - " + heure_sortie;
|
||||
// Create an instance of Authorization
|
||||
authorization = new Authorization();
|
||||
authorization.setEmployee(employee);
|
||||
authorization.setTicketId(idInt);
|
||||
authorization.setTicket(ticketLink);
|
||||
authorization.setRequisitionDate(absenceDate);
|
||||
authorization.setDescription(updatedDescription);
|
||||
authorization.setStatusSelect(validation_status);
|
||||
authorization.setAuthorizationType(0);
|
||||
|
||||
if (validation_status == 3) {
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
} else if (validation_status == 4) {
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
}
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
authorization.setDailyReport(dailyReport);
|
||||
if (validation_status == 3) dailyReport.setIsAuthorizedEarlyDeparture(true);
|
||||
}
|
||||
// Save the new Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
System.err.println("Failed to parse JSON: " + jsonObject.toString());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveAP(JSONObject jsonObject) throws AxelorException {
|
||||
|
||||
try {
|
||||
// Extract fields
|
||||
int idInt = jsonObject.getInt("id");
|
||||
String id = Integer.toString(idInt);
|
||||
String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
|
||||
String matricule = jsonObject.getString("matricule");
|
||||
String date_absence = jsonObject.getString("date_sortie");
|
||||
String commentaire = jsonObject.getString("motif");
|
||||
String heure_sortie = jsonObject.getString("heure_sortie");
|
||||
int validation_status = jsonObject.optInt("validation_status", 2);
|
||||
String validateByUser = jsonObject.optString("validate_by_user", null);
|
||||
String dateValidation = jsonObject.optString("validation_date", null);
|
||||
|
||||
// GET EMPLOYEES
|
||||
Employee employee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", matricule)
|
||||
.fetchOne();
|
||||
|
||||
if (employee == null) {
|
||||
System.err.println("Employee with matricule " + matricule + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
Employee validatedByEmployee = null;
|
||||
|
||||
if (validateByUser != null) {
|
||||
validatedByEmployee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", validateByUser)
|
||||
.fetchOne();
|
||||
|
||||
if (validatedByEmployee == null) {
|
||||
System.err.println("Validator employee with matricule " + validateByUser + " not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse validation date (handle null case)
|
||||
LocalDate validationDate = null;
|
||||
if (dateValidation != null && !dateValidation.isEmpty()) {
|
||||
try {
|
||||
OffsetDateTime offsetDateTime =
|
||||
OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing dateValidation: " + dateValidation);
|
||||
validationDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse Requisition Date
|
||||
LocalDate absenceDate;
|
||||
try {
|
||||
absenceDate = LocalDate.parse(date_absence);
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing date_absence: " + date_absence);
|
||||
absenceDate = null;
|
||||
}
|
||||
|
||||
// Check if Authorization exists by ticketId
|
||||
Authorization authorization =
|
||||
authorizationRepository
|
||||
.all()
|
||||
.filter("self.ticketId = :ticketId")
|
||||
.bind("ticketId", idInt)
|
||||
.fetchOne();
|
||||
|
||||
if (authorization != null) {
|
||||
// Authorization exists, compare previous and new status
|
||||
int previousStatus = authorization.getStatusSelect(); // Previous status
|
||||
int newStatus = validation_status; // New status
|
||||
|
||||
if (previousStatus == 2 && newStatus == 3) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
// Update the fields of the existing Authorization
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
dailyReport.setIsAuthorizedAbsence(true);
|
||||
}
|
||||
|
||||
} else if (previousStatus == 2 && newStatus == 4) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
authorization.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
} else {
|
||||
String updatedDescription = commentaire + " - " + heure_sortie;
|
||||
// Create an instance of Authorization
|
||||
authorization = new Authorization();
|
||||
authorization.setEmployee(employee);
|
||||
authorization.setTicketId(idInt);
|
||||
authorization.setTicket(ticketLink);
|
||||
authorization.setRequisitionDate(absenceDate);
|
||||
authorization.setDescription(updatedDescription);
|
||||
authorization.setStatusSelect(validation_status);
|
||||
authorization.setAuthorizationType(0);
|
||||
|
||||
if (validation_status == 3) {
|
||||
authorization.setValidatedByEmployee(validatedByEmployee);
|
||||
authorization.setValidationDate(validationDate);
|
||||
} else if (validation_status == 4) {
|
||||
authorization.setRefusedByEmployee(validatedByEmployee);
|
||||
authorization.setRefusalDate(validationDate);
|
||||
}
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", absenceDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
authorization.setDailyReport(dailyReport);
|
||||
if (validation_status == 3) dailyReport.setIsAuthorizedAbsence(true);
|
||||
}
|
||||
// Save the new Authorization
|
||||
authorizationRepository.save(authorization);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
System.err.println("Failed to parse JSON: " + jsonObject.toString());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to parse dates
|
||||
private LocalDate parseDate(String dateString) {
|
||||
try {
|
||||
OffsetDateTime offsetDateTime =
|
||||
OffsetDateTime.parse(dateString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
return offsetDateTime.toLocalDate();
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing date: " + dateString);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public interface DailyReportService {
|
||||
|
||||
@Transactional
|
||||
void workingHours(DailyReport DailyReport);
|
||||
|
||||
@Transactional
|
||||
void determineShift(DailyReport DailyReport);
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void deducePrimes(DailyReport DailyReport, Integer primeSelection, BigDecimal valueToDeduce) throws AxelorException ;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void massDeducePrimes(List<DailyReport> DailyReportList, Integer primeSelection, BigDecimal valueToDeduce) throws AxelorException;
|
||||
}
|
||||
@ -0,0 +1,750 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.base.db.EventsPlanning;
|
||||
import com.axelor.apps.base.db.EventsPlanningLine;
|
||||
import com.axelor.apps.base.db.repo.EventsPlanningLineRepository;
|
||||
import com.axelor.apps.hr.db.Absence;
|
||||
import com.axelor.apps.hr.db.Authorization;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.OffDayWork;
|
||||
import com.axelor.apps.hr.db.Shift;
|
||||
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||
import com.axelor.apps.hr.db.repo.AuthorizationRepository;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.db.repo.OffDayWorkRepository;
|
||||
import com.axelor.apps.hr.db.repo.ShiftRepository;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DailyReportServiceImpl implements DailyReportService {
|
||||
|
||||
private final DailyReportRepository dailyReportRepository;
|
||||
private final AuthorizationRepository autorizationRepository;
|
||||
private final AbsenceRepository absenceRepository;
|
||||
private final String HOLIDAYS_STRING = "Planning jours de Féries DZ";
|
||||
private EventsPlanning eventsPlanning;
|
||||
private List<EventsPlanningLine> eventsPlanningLines;
|
||||
private static final LocalTime NIGHT_START = LocalTime.of(21, 0); // 9:00 PM
|
||||
private static final LocalTime NIGHT_END = LocalTime.of(5, 0); // 5:00 AM
|
||||
|
||||
private LocalTime SHIFT_8h16_min;
|
||||
private LocalTime SHIFT_8h16_max;
|
||||
private LocalTime SHIFT_14h22_min;
|
||||
private LocalTime SHIFT_14h22_max;
|
||||
private LocalTime SHIFT_22h6_min;
|
||||
private LocalTime SHIFT_22h6_max;
|
||||
private LocalTime SHIFT_6h14_min;
|
||||
private LocalTime SHIFT_6h14_max;
|
||||
|
||||
@Inject
|
||||
public DailyReportServiceImpl(
|
||||
DailyReportRepository dailyReportRepository,
|
||||
AuthorizationRepository autorizationRepository,
|
||||
AbsenceRepository absenceRepository) {
|
||||
this.dailyReportRepository = dailyReportRepository;
|
||||
this.autorizationRepository = autorizationRepository;
|
||||
this.absenceRepository = absenceRepository;
|
||||
eventsPlanningLines =
|
||||
Beans.get(EventsPlanningLineRepository.class)
|
||||
.all()
|
||||
.filter("self.eventsPlanning = 4")
|
||||
.fetch();
|
||||
|
||||
SHIFT_8h16_min =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 0").fetchOne().getEnterMin();
|
||||
SHIFT_8h16_max =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 0").fetchOne().getEnterMax();
|
||||
SHIFT_14h22_min =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 1").fetchOne().getEnterMin();
|
||||
SHIFT_14h22_max =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 1").fetchOne().getEnterMax();
|
||||
SHIFT_22h6_min =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 2").fetchOne().getEnterMin();
|
||||
SHIFT_22h6_max =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 2").fetchOne().getEnterMax();
|
||||
SHIFT_6h14_min =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 3").fetchOne().getEnterMin();
|
||||
SHIFT_6h14_max =
|
||||
Beans.get(ShiftRepository.class).all().filter("self.shift = 3").fetchOne().getEnterMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void workingHours(DailyReport dailyReport) {
|
||||
|
||||
LocalDateTime[] enters = {
|
||||
dailyReport.getEnter1(), dailyReport.getEnter2(), dailyReport.getEnter3(),
|
||||
dailyReport.getEnter4(), dailyReport.getEnter5(), dailyReport.getEnter6()
|
||||
};
|
||||
LocalDateTime[] quits = {
|
||||
dailyReport.getQuit1(), dailyReport.getQuit2(), dailyReport.getQuit3(),
|
||||
dailyReport.getQuit4(), dailyReport.getQuit5(), dailyReport.getQuit6()
|
||||
};
|
||||
|
||||
Employee employee = dailyReport.getEmployee();
|
||||
LocalDate reportDate = dailyReport.getReportDate();
|
||||
Integer shift = dailyReport.getShift().getShift();
|
||||
|
||||
LocalDateTime firstEnter, lastQuit;
|
||||
|
||||
LocalTime shiftStartHour = null,
|
||||
shiftEndHour = null,
|
||||
shiftStartPauseHour = null,
|
||||
shiftEndPauseHour = null;
|
||||
if (shift != null) {
|
||||
shiftStartHour = dailyReport.getShift().getStartHour();
|
||||
shiftEndHour = dailyReport.getShift().getEndHour();
|
||||
shiftStartPauseHour = dailyReport.getShift().getStartPause();
|
||||
shiftEndPauseHour = dailyReport.getShift().getEndPause();
|
||||
}
|
||||
|
||||
if (enters[0] != null && quits[0] != null) {
|
||||
// Calculate total work duration
|
||||
Duration totalDuration = Duration.ZERO;
|
||||
Duration totalSupDuration = Duration.ZERO;
|
||||
Duration nightDuration = Duration.ZERO;
|
||||
Duration breakDuration = Duration.ZERO;
|
||||
firstEnter = enters[0];
|
||||
lastQuit = quits[0];
|
||||
|
||||
for (int i = 0; i < enters.length; i++) {
|
||||
if (enters[i] != null && quits[i] != null) {
|
||||
// totalDuration = totalDuration.plus(Duration.between(enters[i], quits[i]));
|
||||
lastQuit = quits[i];
|
||||
}
|
||||
}
|
||||
|
||||
dailyReport.setLastQuit(lastQuit);
|
||||
LocalTime firstEnterTime = firstEnter.toLocalTime();
|
||||
LocalTime lastQuitTime = lastQuit.toLocalTime();
|
||||
|
||||
// Calculate late arrival if firstEnter is later than shift start
|
||||
if (shiftStartHour != null) {
|
||||
if (firstEnterTime.isAfter(shiftStartHour)) {
|
||||
long minutesLate = Duration.between(shiftStartHour, firstEnterTime).toMinutes();
|
||||
BigDecimal lateArrival =
|
||||
BigDecimal.valueOf(minutesLate)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setLateArrival(lateArrival);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate early departure if lastQuit is earlier than shift end
|
||||
if (shiftEndHour != null) {
|
||||
if (lastQuitTime.isBefore(shiftEndHour)) {
|
||||
long minutesEarly = Duration.between(lastQuitTime, shiftEndHour).toMinutes();
|
||||
BigDecimal earlyDeparture =
|
||||
BigDecimal.valueOf(minutesEarly)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setEarlyDeparture(earlyDeparture);
|
||||
}
|
||||
}
|
||||
|
||||
// Total hours
|
||||
totalDuration = totalDuration.plus(Duration.between(firstEnter, lastQuit));
|
||||
long totalMinutes = totalDuration.toMinutes();
|
||||
BigDecimal totalHours =
|
||||
BigDecimal.valueOf(totalMinutes).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setWorkHours(totalHours);
|
||||
|
||||
// Calculate night hours
|
||||
nightDuration = calculateNightDuration(firstEnter, lastQuit);
|
||||
long totalNightMinutes = nightDuration.toMinutes();
|
||||
BigDecimal totalNightHours =
|
||||
BigDecimal.valueOf(totalNightMinutes)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setNightHours(totalNightHours);
|
||||
|
||||
// Break Hours
|
||||
breakDuration = calculateBreakDuration(enters, quits);
|
||||
long breakMinutes = breakDuration.toMinutes();
|
||||
BigDecimal breakHours =
|
||||
BigDecimal.valueOf(breakMinutes).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setBreakHours(breakHours);
|
||||
|
||||
if (shiftStartPauseHour != null && shiftEndPauseHour != null) {
|
||||
boolean allInAllowedRange =
|
||||
areBreaksInAllowedRange(enters, quits, shiftStartPauseHour, shiftEndPauseHour);
|
||||
dailyReport.setBreakNotInTheAllowedRange(allInAllowedRange);
|
||||
}
|
||||
|
||||
// shift 2
|
||||
if (shift == 2) {
|
||||
BigDecimal extraHours50 = BigDecimal.ZERO;
|
||||
BigDecimal extraHours100 = BigDecimal.ZERO;
|
||||
|
||||
DayOfWeek enterDay = firstEnter.getDayOfWeek();
|
||||
DayOfWeek quitDay = lastQuit.getDayOfWeek();
|
||||
|
||||
LocalDateTime midnight = firstEnter.toLocalDate().atStartOfDay().plusDays(1);
|
||||
|
||||
// Calculate time from first enter to midnight
|
||||
Duration beforeMidnightDuration = Duration.between(firstEnter, midnight);
|
||||
long beforeMidnightMinutes = beforeMidnightDuration.toMinutes();
|
||||
BigDecimal beforeMidnightHours =
|
||||
BigDecimal.valueOf(beforeMidnightMinutes)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
|
||||
// Calculate time from midnight to last quit
|
||||
Duration afterMidnightDuration = Duration.between(midnight, lastQuit);
|
||||
long afterMidnightMinutes = afterMidnightDuration.toMinutes();
|
||||
BigDecimal afterMidnightHours =
|
||||
BigDecimal.valueOf(afterMidnightMinutes)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
|
||||
if (enterDay == DayOfWeek.THURSDAY && quitDay == DayOfWeek.FRIDAY
|
||||
|| isSpecialOvertimeDay(lastQuit)) {
|
||||
extraHours100 = afterMidnightHours;
|
||||
dailyReport.setAllowance(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
if (enterDay == DayOfWeek.THURSDAY && quitDay == DayOfWeek.FRIDAY)
|
||||
// No Extra Hours ticket needed
|
||||
dailyReport.setIsValidSupHours(true);
|
||||
} else if (isSpecialOvertimeDay(firstEnter)) {
|
||||
|
||||
// Add recup
|
||||
if (totalHours.compareTo(BigDecimal.valueOf(6)) >= 0)
|
||||
createOffDayWork(reportDate, employee);
|
||||
extraHours100 = beforeMidnightHours;
|
||||
dailyReport.setAllowanceRecall(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
} else if (enterDay == DayOfWeek.FRIDAY && quitDay == DayOfWeek.SATURDAY) {
|
||||
|
||||
// Add recup
|
||||
if (totalHours.compareTo(BigDecimal.valueOf(6)) >= 0)
|
||||
createOffDayWork(reportDate, employee);
|
||||
extraHours100 = beforeMidnightHours;
|
||||
extraHours50 = afterMidnightHours;
|
||||
dailyReport.setAllowanceRecall(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
|
||||
} else if ((enterDay == DayOfWeek.SATURDAY && quitDay == DayOfWeek.SUNDAY)) {
|
||||
extraHours50 = beforeMidnightHours;
|
||||
dailyReport.setAllowanceRecall(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
} else {
|
||||
totalSupDuration = calculateSupplementaryHours(firstEnter, lastQuit, shift, reportDate);
|
||||
long totalSupMinutes = totalSupDuration.toMinutes();
|
||||
extraHours50 =
|
||||
BigDecimal.valueOf(totalSupMinutes)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setAllowance(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
dailyReport.setExtraHours100(extraHours100);
|
||||
dailyReport.setExtraHours50(extraHours50);
|
||||
|
||||
// other shifts
|
||||
} else {
|
||||
// Calculate supplementary hours
|
||||
totalSupDuration = calculateSupplementaryHours(firstEnter, lastQuit, shift, reportDate);
|
||||
long totalSupMinutes = totalSupDuration.toMinutes();
|
||||
BigDecimal totalSupHours =
|
||||
BigDecimal.valueOf(totalSupMinutes)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
|
||||
// Holidays and weekends
|
||||
if (firstEnter.getDayOfWeek() == DayOfWeek.SATURDAY) {
|
||||
|
||||
if (shift == 0 || shift == 3) {
|
||||
dailyReport.setExtraHours50(totalHours.subtract(totalNightHours));
|
||||
dailyReport.setExtraHours100(totalNightHours);
|
||||
dailyReport.setAllowanceRecall(
|
||||
totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
} else {
|
||||
dailyReport.setExtraHours50(totalHours);
|
||||
dailyReport.setAllowanceRecall(
|
||||
totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
} else if (firstEnter.getDayOfWeek() == DayOfWeek.FRIDAY
|
||||
|| isSpecialOvertimeDay(firstEnter)) {
|
||||
|
||||
// Add recup
|
||||
if (totalHours.compareTo(BigDecimal.valueOf(6)) >= 0)
|
||||
createOffDayWork(reportDate, employee);
|
||||
dailyReport.setExtraHours100(totalHours);
|
||||
dailyReport.setAllowanceRecall(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
|
||||
} else {
|
||||
|
||||
if (shift == 0 || shift == 3) {
|
||||
dailyReport.setExtraHours50(totalSupHours.subtract(totalNightHours));
|
||||
dailyReport.setExtraHours100(totalNightHours);
|
||||
dailyReport.setAllowance(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
dailyReport.setAllowanceRecall(
|
||||
totalSupHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
} else {
|
||||
dailyReport.setExtraHours50(totalSupHours);
|
||||
dailyReport.setAllowance(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
dailyReport.setAllowanceRecall(
|
||||
totalSupHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate ITP
|
||||
dailyReport.setItp(calculateItp(totalHours, shift, dailyReport.getHasItp()));
|
||||
dailyReport.setIsCalculated(true);
|
||||
|
||||
} else if (enters[0] != null && quits[0] == null) {
|
||||
// When the employee registers attendance only once
|
||||
if (shift != 2) {
|
||||
dailyReport.setWorkHours(BigDecimal.valueOf(8));
|
||||
dailyReport.setAbsenceHours(BigDecimal.valueOf(0));
|
||||
dailyReport.setIsCalculated(true);
|
||||
}
|
||||
} else if (enters.length != quits.length) {
|
||||
|
||||
Duration totalDuration = Duration.ZERO;
|
||||
firstEnter = enters[0];
|
||||
lastQuit = quits[quits.length - 1];
|
||||
totalDuration = totalDuration.plus(Duration.between(firstEnter, lastQuit));
|
||||
long totalMinutes = totalDuration.toMinutes();
|
||||
BigDecimal totalHours =
|
||||
BigDecimal.valueOf(totalMinutes).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setWorkHours(totalHours);
|
||||
dailyReport.setAllowance(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||
|
||||
dailyReport.setLastQuit(lastQuit);
|
||||
LocalTime firstEnterTime = firstEnter.toLocalTime();
|
||||
LocalTime lastQuitTime = lastQuit.toLocalTime();
|
||||
// Calculate late arrival if firstEnter is later than shift start
|
||||
if (firstEnterTime.isAfter(shiftStartHour)) {
|
||||
long minutesLate = Duration.between(shiftStartHour, firstEnterTime).toMinutes();
|
||||
BigDecimal lateArrival =
|
||||
BigDecimal.valueOf(minutesLate).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setLateArrival(lateArrival);
|
||||
}
|
||||
|
||||
// Calculate early departure if lastQuit is earlier than shift end
|
||||
if (lastQuitTime.isBefore(shiftEndHour)) {
|
||||
long minutesEarly = Duration.between(lastQuitTime, shiftEndHour).toMinutes();
|
||||
BigDecimal earlyDeparture =
|
||||
BigDecimal.valueOf(minutesEarly)
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||
dailyReport.setEarlyDeparture(earlyDeparture);
|
||||
}
|
||||
|
||||
} else if (employee == null) {
|
||||
System.err.println("Warning: Employee doesn't exist.");
|
||||
dailyReport.setIsCalculated(true);
|
||||
} else {
|
||||
dailyReport.setWorkHours(BigDecimal.valueOf(0));
|
||||
dailyReport.setNightHours(BigDecimal.valueOf(0));
|
||||
dailyReport.setBreakHours(BigDecimal.valueOf(0));
|
||||
dailyReport.setExtraHours50(BigDecimal.valueOf(0));
|
||||
dailyReport.setExtraHours100(BigDecimal.valueOf(0));
|
||||
dailyReport.setItp(BigDecimal.valueOf(0));
|
||||
dailyReport.setLateArrival(BigDecimal.valueOf(0));
|
||||
dailyReport.setEarlyDeparture(BigDecimal.valueOf(0));
|
||||
dailyReport.setAllowance(0);
|
||||
dailyReport.setAllowanceRecall(0);
|
||||
dailyReport.setBreakNotInTheAllowedRange(false);
|
||||
dailyReport.setShift(Beans.get(ShiftRepository.class).find(50L));
|
||||
System.err.println("Warning: no attendances for this day.");
|
||||
dailyReport.setIsCalculated(true);
|
||||
}
|
||||
|
||||
// Absences
|
||||
if (dailyReport.getAbsence() == null) {
|
||||
Absence absence =
|
||||
Beans.get(AbsenceRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee = :employee and self.startDate <= :reportDate and self.endDate >= :reportDate and (self.archived = false or self.archived is null)")
|
||||
.bind("employee", employee)
|
||||
.bind(
|
||||
"reportDate",
|
||||
reportDate) // Changed from absenceStartDate and absenceEndDate to reportDate
|
||||
.fetchOne();
|
||||
|
||||
if (absence != null) {
|
||||
dailyReport.setAbsence(absence);
|
||||
}
|
||||
}
|
||||
|
||||
// Authorization
|
||||
if (dailyReport.getAuthorizationList() == null) {
|
||||
List<Authorization> authorizations =
|
||||
Beans.get(AuthorizationRepository.class)
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.requisitionDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", reportDate)
|
||||
.fetch();
|
||||
|
||||
if (authorizations != null) {
|
||||
List<Authorization> authorizationList =
|
||||
new ArrayList<>(); // Create a new list for authorizations
|
||||
|
||||
for (Authorization authorization : authorizations) {
|
||||
authorization.setDailyReport(dailyReport);
|
||||
authorizationList.add(authorization); // Add each authorization to the list
|
||||
|
||||
// Check authorization type and set corresponding flags in dailyReport
|
||||
if (authorization.getAuthorizationType() == 0 && authorization.getStatusSelect() == 3) {
|
||||
dailyReport.setIsAuthorizedEarlyDeparture(true);
|
||||
}
|
||||
if (authorization.getAuthorizationType() == 1 && authorization.getStatusSelect() == 3) {
|
||||
dailyReport.setIsAuthorizedLateArrival(true);
|
||||
}
|
||||
if (authorization.getAuthorizationType() == 2 && authorization.getStatusSelect() == 3) {
|
||||
dailyReport.setIsAuthorizedAbsence(true);
|
||||
}
|
||||
}
|
||||
// Set the authorization list to dailyReport
|
||||
dailyReport.setAuthorizationList(authorizationList);
|
||||
}
|
||||
}
|
||||
|
||||
// Holidays
|
||||
if (isSpecialOvertimeDay(reportDate.atStartOfDay())) {
|
||||
dailyReport.setIsFerieDay(true);
|
||||
}
|
||||
|
||||
// Weekends
|
||||
if (reportDate.getDayOfWeek() == DayOfWeek.FRIDAY
|
||||
|| reportDate.getDayOfWeek() == DayOfWeek.SATURDAY) {
|
||||
dailyReport.setIsWeekend(true);
|
||||
}
|
||||
|
||||
// Absence Hours
|
||||
if (!(dailyReport.getIsWeekend() || dailyReport.getIsFerieDay())
|
||||
&& dailyReport.getWorkHours().compareTo(BigDecimal.valueOf(8)) < 0) {
|
||||
dailyReport.setAbsenceHours(BigDecimal.valueOf(8).subtract(dailyReport.getWorkHours()));
|
||||
// Create Absence AI
|
||||
if (dailyReport.getAbsenceSet().isEmpty()) {
|
||||
Boolean isAuthorizedAbsence = dailyReport.getIsAuthorizedAbsence();
|
||||
Boolean isAuthorizedLateArrival = dailyReport.getIsAuthorizedLateArrival();
|
||||
Boolean isAuthorizedEarlyDeparture = dailyReport.getIsAuthorizedEarlyDeparture();
|
||||
// AI all day
|
||||
if (dailyReport.getAbsenceHours().compareTo(new BigDecimal("8")) == 0) {
|
||||
if (!isAuthorizedAbsence) {
|
||||
Absence absence = new Absence();
|
||||
absence.setEmployee(employee);
|
||||
absence.setAbsenceType(19); // Absence irrégulière
|
||||
absence.setStartDate(reportDate.atStartOfDay());
|
||||
absence.setEndDate(reportDate.atStartOfDay());
|
||||
BigDecimal totalAbsenceHours =
|
||||
Beans.get(AbsenceServiceImpl.class)
|
||||
.calculateTotalAbsenceHours(
|
||||
reportDate.atStartOfDay(), reportDate.atStartOfDay());
|
||||
absence.setTotalAbsenceHours(totalAbsenceHours);
|
||||
absenceRepository.save(absence);
|
||||
dailyReport.addAbsenceSetItem(absence);
|
||||
}
|
||||
} else {
|
||||
if (dailyReport.getShift().getMaxTimeLateArrival()
|
||||
!= null) { // to check that is different to shift N/A
|
||||
LocalTime firstEnterTime = dailyReport.getEnter1().toLocalTime();
|
||||
if (firstEnterTime.isAfter(dailyReport.getShift().getMaxTimeLateArrival())
|
||||
&& !isAuthorizedLateArrival) {
|
||||
Absence absence = new Absence();
|
||||
absence.setEmployee(employee);
|
||||
absence.setAbsenceType(20); // Retard irrégulier
|
||||
absence.setStartDate(reportDate.atTime(shiftStartHour));
|
||||
absence.setEndDate(dailyReport.getEnter1());
|
||||
BigDecimal totalAbsenceHours =
|
||||
Beans.get(AbsenceServiceImpl.class)
|
||||
.calculateTotalAbsenceMinutes(
|
||||
reportDate.atTime(shiftStartHour), dailyReport.getEnter1());
|
||||
absence.setTotalAbsenceHours(totalAbsenceHours);
|
||||
absenceRepository.save(absence);
|
||||
dailyReport.addAbsenceSetItem(absence);
|
||||
}
|
||||
if (dailyReport.getLastQuit() != null) {
|
||||
LocalTime lastQuitTime = dailyReport.getLastQuit().toLocalTime();
|
||||
if (lastQuitTime.isBefore(dailyReport.getShift().getMaxTimeEarlyDeparture())
|
||||
&& !isAuthorizedEarlyDeparture) {
|
||||
Absence absence = new Absence();
|
||||
absence.setEmployee(employee);
|
||||
absence.setAbsenceType(21); // Départ irrégulier
|
||||
absence.setStartDate(dailyReport.getLastQuit());
|
||||
absence.setEndDate(reportDate.atTime(shiftEndHour));
|
||||
BigDecimal totalAbsenceHours =
|
||||
Beans.get(AbsenceServiceImpl.class)
|
||||
.calculateTotalAbsenceMinutes(
|
||||
dailyReport.getLastQuit(), reportDate.atTime(shiftEndHour));
|
||||
absence.setTotalAbsenceHours(totalAbsenceHours);
|
||||
absenceRepository.save(absence);
|
||||
dailyReport.addAbsenceSetItem(absence);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dailyReport.setAbsenceHours(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
dailyReportRepository.save(dailyReport);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void determineShift(DailyReport dailyReport) {
|
||||
LocalDateTime enters1 = dailyReport.getEnter1();
|
||||
if (enters1 != null) {
|
||||
// Extract time from enters1
|
||||
LocalTime firstTime = enters1.toLocalTime();
|
||||
|
||||
// Define shifts
|
||||
Shift shift;
|
||||
if (firstTime.isAfter(SHIFT_6h14_min) && firstTime.isBefore(SHIFT_6h14_max)) {
|
||||
shift = Beans.get(ShiftRepository.class).find(3L); // Shift 6h14
|
||||
} else if (firstTime.isAfter(SHIFT_8h16_min) && firstTime.isBefore(SHIFT_8h16_max)) {
|
||||
shift = Beans.get(ShiftRepository.class).find(4L); // Shift 8h16
|
||||
} else if (firstTime.isAfter(SHIFT_14h22_min) && firstTime.isBefore(SHIFT_14h22_max)) {
|
||||
shift = Beans.get(ShiftRepository.class).find(1L); // Shift 14h22
|
||||
} else if (firstTime.isAfter(SHIFT_22h6_min) || firstTime.isBefore(SHIFT_22h6_max)) {
|
||||
shift = Beans.get(ShiftRepository.class).find(2L); // Shift 22h6
|
||||
} else {
|
||||
shift = Beans.get(ShiftRepository.class).find(50L); // N/A
|
||||
}
|
||||
dailyReport.setShift(shift);
|
||||
dailyReportRepository.save(dailyReport);
|
||||
}
|
||||
}
|
||||
|
||||
public void workingHoursForAll(List<DailyReport> DailyReportList) {
|
||||
for (int i = 0; i < DailyReportList.size(); i++) {
|
||||
// System.out.println(DailyReportList.get(i).getId());
|
||||
workingHours(DailyReportList.get(i));
|
||||
}
|
||||
System.out.println("Calculation Done");
|
||||
}
|
||||
|
||||
private boolean isSpecialOvertimeDay(LocalDateTime date) {
|
||||
LocalDate givenDate = date.toLocalDate();
|
||||
for (EventsPlanningLine line : eventsPlanningLines) {
|
||||
if (line.getDate().equals(givenDate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Duration calculateNightDuration(LocalDateTime enter, LocalDateTime quit) {
|
||||
|
||||
// Create LocalDateTime objects for night start and end
|
||||
LocalDateTime nightStartDateTime = enter.toLocalDate().atTime(NIGHT_START);
|
||||
LocalDateTime nightEndDateTime = enter.toLocalDate().plusDays(1).atTime(NIGHT_END);
|
||||
|
||||
// Initialize night duration to zero
|
||||
Duration nightDuration1 = Duration.ZERO;
|
||||
|
||||
// Check if there is an overlap with the night period
|
||||
if (enter.isBefore(nightEndDateTime) && quit.isAfter(nightStartDateTime)) {
|
||||
|
||||
// Calculate effective start and end times for night hours
|
||||
LocalDateTime effectiveStart =
|
||||
enter.isBefore(nightStartDateTime) ? nightStartDateTime : enter;
|
||||
LocalDateTime effectiveEnd = quit.isAfter(nightEndDateTime) ? nightEndDateTime : quit;
|
||||
|
||||
// Calculate and return the night duration
|
||||
if (effectiveStart.isBefore(effectiveEnd)) {
|
||||
nightDuration1 = Duration.between(effectiveStart, effectiveEnd);
|
||||
}
|
||||
}
|
||||
|
||||
return nightDuration1;
|
||||
}
|
||||
|
||||
private Duration calculateSupplementaryHours(
|
||||
LocalDateTime enter, LocalDateTime quit, int shift, LocalDate reportDate) {
|
||||
|
||||
// Calculate Supp hours for (0,1,2,3) shifts
|
||||
Shift shiftInstance =
|
||||
Beans.get(ShiftRepository.class)
|
||||
.all()
|
||||
.filter("self.shift = :shift")
|
||||
.bind("shift", shift)
|
||||
.fetchOne();
|
||||
|
||||
LocalTime shiftStart = shiftInstance.getStartHour();
|
||||
LocalTime shiftEnd = shiftInstance.getEndHour();
|
||||
|
||||
// Create LocalDateTime objects for shift start and end
|
||||
LocalDateTime shiftStartDateTime = reportDate.atTime(shiftStart);
|
||||
LocalDateTime shiftEndDateTime = quit.toLocalDate().atTime(shiftEnd);
|
||||
|
||||
// Initialize supplementary duration to zero
|
||||
Duration supDuration = Duration.ZERO;
|
||||
|
||||
// Calculate supplementary duration before shift start
|
||||
if (enter.isBefore(shiftStartDateTime)) {
|
||||
Duration beforeShiftDuration = Duration.between(enter, shiftStartDateTime);
|
||||
if (beforeShiftDuration.toMinutes() > 30) {
|
||||
supDuration = supDuration.plus(beforeShiftDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate supplementary duration after shift end
|
||||
if (quit.isAfter(shiftEndDateTime)) {
|
||||
Duration afterShiftDuration = Duration.between(shiftEndDateTime, quit);
|
||||
if (afterShiftDuration.toMinutes() > 30) {
|
||||
supDuration = supDuration.plus(afterShiftDuration);
|
||||
}
|
||||
}
|
||||
|
||||
return supDuration;
|
||||
}
|
||||
|
||||
private Duration calculateBreakDuration(LocalDateTime[] enters, LocalDateTime[] quits) {
|
||||
|
||||
Duration breakDuration = Duration.ZERO;
|
||||
for (int i = 1; i < quits.length; i++) {
|
||||
if (enters[i] != null && quits[i - 1] != null) {
|
||||
breakDuration = breakDuration.plus(Duration.between(quits[i - 1], enters[i]));
|
||||
}
|
||||
}
|
||||
return breakDuration;
|
||||
}
|
||||
|
||||
private boolean areBreaksInAllowedRange(
|
||||
LocalDateTime[] enters,
|
||||
LocalDateTime[] quits,
|
||||
LocalTime allowedStartTime,
|
||||
LocalTime allowedEndTime) {
|
||||
|
||||
for (int i = 1; i < quits.length; i++) {
|
||||
if (enters[i] != null && quits[i - 1] != null) {
|
||||
LocalTime breakStartTime = quits[i - 1].toLocalTime();
|
||||
LocalTime breakEndTime = enters[i].toLocalTime();
|
||||
|
||||
// Check if the break falls outside the allowed range
|
||||
if (breakStartTime.isBefore(allowedStartTime) || breakEndTime.isAfter(allowedEndTime)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private BigDecimal calculateItp(BigDecimal totalHours, Integer shift, Boolean hasItp) {
|
||||
// Shift 0 (no itp)
|
||||
if (hasItp == true && shift != 0) return totalHours.min(BigDecimal.valueOf(8));
|
||||
else return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
private void createOffDayWork(LocalDate reportDate, Employee employee) {
|
||||
|
||||
// Vérification si l'enregistrement existe déjà
|
||||
OffDayWork existingOffDayWork =
|
||||
Beans.get(OffDayWorkRepository.class)
|
||||
.all()
|
||||
.filter("self.employee = :employee AND self.offDay = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", reportDate)
|
||||
.fetchOne();
|
||||
|
||||
if (existingOffDayWork == null) {
|
||||
// Si aucun enregistrement n'est trouvé, créer un nouveau OffDayWork
|
||||
OffDayWork offDayWork = new OffDayWork();
|
||||
offDayWork.setEmployee(employee);
|
||||
offDayWork.setOffDay(reportDate);
|
||||
Beans.get(OffDayWorkRepository.class).save(offDayWork);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkShiftChange(Employee employee, LocalDate reportDate, Integer currentShift) {
|
||||
|
||||
LocalDate firstDayOfWeek = getPreviousWeekSunday(reportDate);
|
||||
DailyReport rapportOfFirstDayOfWeek =
|
||||
dailyReportRepository
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :firstDayOfWeek")
|
||||
.bind("employee", employee)
|
||||
.bind("firstDayOfWeek", firstDayOfWeek)
|
||||
.fetchOne();
|
||||
|
||||
Integer firstShift = rapportOfFirstDayOfWeek.getShift().getShift();
|
||||
// Corrected print statements
|
||||
System.out.println("The day: " + reportDate + " , Shift: " + currentShift);
|
||||
System.out.println("The Sunday day: " + firstDayOfWeek + " , Shift: " + firstShift);
|
||||
System.out.println("Result: " + !currentShift.equals(firstShift));
|
||||
return !currentShift.equals(firstShift);
|
||||
}
|
||||
|
||||
// private Duration calculateAbsencesHours(LocalDateTime quit, int shift){ }
|
||||
private static LocalDate getPreviousWeekSunday(LocalDate date) {
|
||||
if (date.getDayOfWeek() == DayOfWeek.SUNDAY) {
|
||||
return date;
|
||||
}
|
||||
|
||||
// Find the day of week for the given date
|
||||
DayOfWeek dayOfWeek = date.getDayOfWeek();
|
||||
// Calculate the number of days to the previous Sunday
|
||||
int daysToPreviousSunday = dayOfWeek.getValue() + 7 - DayOfWeek.SUNDAY.getValue();
|
||||
// Calculate the previous Sunday date
|
||||
return date.minusDays(daysToPreviousSunday);
|
||||
}
|
||||
|
||||
public static BigDecimal customRound(BigDecimal value) {
|
||||
// Get the fractional part of the number
|
||||
BigDecimal fractionalPart = value.remainder(BigDecimal.ONE);
|
||||
|
||||
// Define the intervals and their corresponding rounded values
|
||||
if (fractionalPart.compareTo(new BigDecimal("0.125")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN);
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.125")) >= 0
|
||||
&& fractionalPart.compareTo(new BigDecimal("0.375")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN).add(new BigDecimal("0.25"));
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.375")) >= 0
|
||||
&& fractionalPart.compareTo(new BigDecimal("0.625")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN).add(new BigDecimal("0.50"));
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.625")) >= 0
|
||||
&& fractionalPart.compareTo(new BigDecimal("0.875")) < 0) {
|
||||
return value.setScale(0, RoundingMode.DOWN).add(new BigDecimal("0.75"));
|
||||
} else if (fractionalPart.compareTo(new BigDecimal("0.875")) >= 0) {
|
||||
return value.setScale(0, RoundingMode.UP);
|
||||
} else {
|
||||
return value; // In case no rounding is needed
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void deducePrimes(
|
||||
DailyReport dailyReport, Integer primeSelection, BigDecimal valueToDeduce)
|
||||
throws AxelorException {
|
||||
switch (primeSelection) {
|
||||
case 1: // ITP
|
||||
dailyReport.setDeduceItp(true);
|
||||
dailyReport.setItpToDeduce(valueToDeduce);
|
||||
break;
|
||||
case 2: // Nuissance
|
||||
dailyReport.setDeduceNuissance(true);
|
||||
dailyReport.setItpToDeduce(valueToDeduce);
|
||||
break;
|
||||
case 3: // HS 50
|
||||
dailyReport.setDeduceSupHours50(true);
|
||||
dailyReport.setSupHours50ToDeduce(valueToDeduce);
|
||||
break;
|
||||
case 4: // HS 100
|
||||
dailyReport.setDeduceSupHours100(true);
|
||||
dailyReport.setSupHours100ToDeduce(valueToDeduce);
|
||||
break;
|
||||
default:
|
||||
return; // Invalid configSelect, stop processing
|
||||
}
|
||||
Beans.get(DailyReportRepository.class).save(dailyReport);
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void massDeducePrimes(
|
||||
List<DailyReport> dailyReportList, Integer primeSelection, BigDecimal valueToDeduce)
|
||||
throws AxelorException {
|
||||
for (DailyReport dailyReport : dailyReportList) {
|
||||
this.deducePrimes(dailyReport, primeSelection, valueToDeduce);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmployeeAdvance;
|
||||
import com.axelor.apps.hr.db.EmployeeAdvanceUsage;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeAdvanceRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeAdvanceUsageRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public class EmployeeAdvanceService {
|
||||
|
||||
@Inject private EmployeeAdvanceRepository employeeAdvanceRepository;
|
||||
|
||||
@Inject private EmployeeAdvanceUsageRepository employeeAdvanceUsageRepository;
|
||||
|
||||
@Transactional
|
||||
public void fillExpenseWithAdvances(Expense expense) {
|
||||
|
||||
Employee employee =
|
||||
Beans.get(EmployeeRepository.class).find(expense.getUser().getEmployee().getId());
|
||||
|
||||
List<EmployeeAdvance> advanceList =
|
||||
employeeAdvanceRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee.id = ?1 AND self.remainingAmount > 0 AND self.date < ?2 AND self.statusSelect = ?3 AND self.typeSelect = ?4",
|
||||
employee.getId(),
|
||||
expense.getPeriod().getToDate(),
|
||||
EmployeeAdvanceRepository.STATUS_VALIDATED,
|
||||
EmployeeAdvanceRepository.TYPE_OCCASIONAL)
|
||||
.fetch();
|
||||
|
||||
if (advanceList != null && !advanceList.isEmpty()) {
|
||||
|
||||
BigDecimal currentAmountToRefund =
|
||||
expense
|
||||
.getInTaxTotal()
|
||||
.subtract(expense.getPersonalExpenseAmount())
|
||||
.subtract(expense.getWithdrawnCash());
|
||||
|
||||
for (EmployeeAdvance advance : advanceList) {
|
||||
|
||||
if (currentAmountToRefund.signum() == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
currentAmountToRefund = withdrawFromAdvance(advance, expense, currentAmountToRefund);
|
||||
employeeAdvanceRepository.save(advance);
|
||||
}
|
||||
expense.setAdvanceAmount(
|
||||
expense
|
||||
.getInTaxTotal()
|
||||
.subtract(currentAmountToRefund)
|
||||
.subtract(expense.getPersonalExpenseAmount())
|
||||
.subtract(expense.getWithdrawnCash()));
|
||||
}
|
||||
}
|
||||
|
||||
public BigDecimal withdrawFromAdvance(
|
||||
EmployeeAdvance employeeAdvance, Expense expense, BigDecimal maxAmount) {
|
||||
|
||||
if (maxAmount.compareTo(employeeAdvance.getRemainingAmount()) > 0) {
|
||||
maxAmount = maxAmount.subtract(employeeAdvance.getRemainingAmount());
|
||||
createEmployeeAdvanceUsage(employeeAdvance, expense, employeeAdvance.getRemainingAmount());
|
||||
employeeAdvance.setRemainingAmount(BigDecimal.ZERO);
|
||||
|
||||
} else {
|
||||
createEmployeeAdvanceUsage(employeeAdvance, expense, maxAmount);
|
||||
employeeAdvance.setRemainingAmount(employeeAdvance.getRemainingAmount().subtract(maxAmount));
|
||||
maxAmount = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
return maxAmount;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void createEmployeeAdvanceUsage(
|
||||
EmployeeAdvance employeeAdvance, Expense expense, BigDecimal amount) {
|
||||
|
||||
EmployeeAdvanceUsage usage = new EmployeeAdvanceUsage();
|
||||
|
||||
usage.setEmployeeAdvance(employeeAdvance);
|
||||
usage.setExpense(expense);
|
||||
usage.setUsedAmount(amount);
|
||||
employeeAdvanceUsageRepository.save(usage);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.base.db.Period;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmployeeBonusMgt;
|
||||
import com.axelor.apps.hr.db.EmployeeBonusMgtLine;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeBonusMgtLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeBonusMgtRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.employee.EmployeeServiceImpl;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.tool.template.TemplateMaker;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import groovy.lang.Binding;
|
||||
import groovy.lang.GroovyShell;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
|
||||
public class EmployeeBonusService {
|
||||
|
||||
@Inject EmployeeBonusMgtRepository employeeBonusMgtRepo;
|
||||
|
||||
@Inject EmployeeBonusMgtLineRepository employeeBonusMgtLineRepo;
|
||||
|
||||
@Inject EmployeeServiceImpl employeeService;
|
||||
|
||||
private static final char TEMPLATE_DELIMITER = '$';
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void compute(EmployeeBonusMgt bonus) throws AxelorException {
|
||||
Map<Employee, EmployeeBonusMgtLine> employeeStatus = new HashMap<>();
|
||||
for (EmployeeBonusMgtLine line : bonus.getEmployeeBonusMgtLineList()) {
|
||||
employeeStatus.put(line.getEmployee(), line);
|
||||
}
|
||||
|
||||
List<Employee> allEmployee =
|
||||
Beans.get(EmployeeRepository.class)
|
||||
.all()
|
||||
.filter("self.mainEmploymentContract.payCompany = ?1", bonus.getCompany())
|
||||
.fetch();
|
||||
TemplateMaker maker = new TemplateMaker(Locale.FRENCH, TEMPLATE_DELIMITER, TEMPLATE_DELIMITER);
|
||||
String eval;
|
||||
CompilerConfiguration conf = new CompilerConfiguration();
|
||||
ImportCustomizer customizer = new ImportCustomizer();
|
||||
customizer.addStaticStars("java.lang.Math");
|
||||
conf.addCompilationCustomizers(customizer);
|
||||
Binding binding = new Binding();
|
||||
GroovyShell shell = new GroovyShell(binding, conf);
|
||||
|
||||
Integer employeeBonusStatus = EmployeeBonusMgtRepository.STATUS_CALCULATED;
|
||||
for (Employee employee : allEmployee) {
|
||||
|
||||
// check if line is already calculated
|
||||
if (employeeStatus.get(employee) != null) {
|
||||
if (employeeStatus
|
||||
.get(employee)
|
||||
.getStatusSelect()
|
||||
.equals(EmployeeBonusMgtLineRepository.STATUS_CALCULATED)) {
|
||||
continue;
|
||||
} else {
|
||||
bonus.removeEmployeeBonusMgtLineListItem(employeeStatus.get(employee));
|
||||
}
|
||||
}
|
||||
|
||||
maker.setContext(employee, "Employee");
|
||||
EmployeeBonusMgtLine line = new EmployeeBonusMgtLine();
|
||||
line.setEmployeeBonusMgt(bonus);
|
||||
line.setEmployee(employee);
|
||||
maker.addInContext("EmployeeBonusMgtLine", line);
|
||||
String formula = bonus.getEmployeeBonusType().getApplicationCondition();
|
||||
Integer lineStatus = EmployeeBonusMgtLineRepository.STATUS_CALCULATED;
|
||||
try {
|
||||
formula =
|
||||
replaceExpressionInFormula(
|
||||
formula, bonus.getCompany().getHrConfig(), employee, bonus.getPayPeriod());
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
formula = "true";
|
||||
lineStatus = EmployeeBonusMgtLineRepository.STATUS_ANOMALY;
|
||||
}
|
||||
maker.setTemplate(formula);
|
||||
eval = maker.make();
|
||||
|
||||
if (shell.evaluate(eval).toString().equals("true")) {
|
||||
try {
|
||||
formula =
|
||||
replaceExpressionInFormula(
|
||||
bonus.getEmployeeBonusType().getFormula(),
|
||||
bonus.getCompany().getHrConfig(),
|
||||
employee,
|
||||
bonus.getPayPeriod());
|
||||
} catch (Exception e) {
|
||||
lineStatus = EmployeeBonusMgtLineRepository.STATUS_ANOMALY;
|
||||
}
|
||||
|
||||
line.setStatusSelect(lineStatus);
|
||||
|
||||
if (lineStatus.equals(EmployeeBonusMgtLineRepository.STATUS_ANOMALY)) {
|
||||
employeeBonusStatus = EmployeeBonusMgtRepository.STATUS_ANOMALY;
|
||||
employeeBonusMgtLineRepo.save(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
line.setSeniorityDate(employee.getSeniorityDate());
|
||||
line.setCoef(employee.getBonusCoef());
|
||||
line.setWeeklyPlanning(employee.getWeeklyPlanning());
|
||||
|
||||
maker.setTemplate(formula);
|
||||
eval = maker.make();
|
||||
line.setAmount(new BigDecimal(shell.evaluate(eval).toString()));
|
||||
|
||||
employeeBonusMgtLineRepo.save(line);
|
||||
}
|
||||
}
|
||||
bonus.setStatusSelect(employeeBonusStatus);
|
||||
employeeBonusMgtRepo.save(bonus);
|
||||
}
|
||||
|
||||
public String replaceExpressionInFormula(
|
||||
String formula, HRConfig hrConfig, Employee employee, Period period) throws AxelorException {
|
||||
|
||||
if (!Strings.isNullOrEmpty(hrConfig.getAgeVariableName())) {
|
||||
formula =
|
||||
formula.replace(
|
||||
hrConfig.getAgeVariableName(),
|
||||
String.valueOf(employeeService.getAge(employee, period.getFromDate())));
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(hrConfig.getSeniorityVariableName())) {
|
||||
formula =
|
||||
formula.replace(
|
||||
hrConfig.getSeniorityVariableName(),
|
||||
String.valueOf(employeeService.getLengthOfService(employee, period.getFromDate())));
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(hrConfig.getWorkingDaysVariableName())) {
|
||||
formula =
|
||||
formula.replace(
|
||||
hrConfig.getWorkingDaysVariableName(),
|
||||
String.valueOf(
|
||||
employeeService.getDaysWorkedInPeriod(
|
||||
employee, period.getFromDate(), period.getToDate())));
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(hrConfig.getTotalWorkingDaysVariableName())) {
|
||||
formula =
|
||||
formula.replace(
|
||||
hrConfig.getTotalWorkingDaysVariableName(),
|
||||
String.valueOf(
|
||||
employeeService.getDaysWorksInPeriod(
|
||||
employee, period.getFromDate(), period.getToDate())));
|
||||
}
|
||||
|
||||
// For checking that formula contains variables like $*$
|
||||
if (formula.matches("(\\$\\w+\\$).+")) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_FORMULA_VARIABLE_MISSING),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return formula;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.ReportFactory;
|
||||
import com.axelor.apps.base.db.Address;
|
||||
import com.axelor.apps.base.db.Department;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.repo.EmploymentContractRepository;
|
||||
import com.axelor.apps.hr.report.IReport;
|
||||
import com.axelor.apps.report.engine.ReportSettings;
|
||||
import com.axelor.apps.tool.file.CsvTool;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EmploymentContractService {
|
||||
|
||||
@Inject private EmploymentContractRepository employmentContractRepo;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public int addAmendment(EmploymentContract employmentContract) throws AxelorException {
|
||||
String name =
|
||||
employmentContract.getFullName() + "_" + employmentContract.getEmploymentContractVersion();
|
||||
|
||||
ReportFactory.createReport(IReport.EMPLYOMENT_CONTRACT, name + "-${date}")
|
||||
.addParam("ContractId", employmentContract.getId())
|
||||
.addParam("Locale", ReportSettings.getPrintingLocale(null))
|
||||
.toAttach(employmentContract)
|
||||
.generate()
|
||||
.getFileLink();
|
||||
|
||||
int version = employmentContract.getEmploymentContractVersion() + 1;
|
||||
employmentContract.setEmploymentContractVersion(version);
|
||||
employmentContractRepo.save(employmentContract);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
public void exportEmploymentContract(EmploymentContract employmentContract) throws IOException {
|
||||
List<String[]> list = new ArrayList<>();
|
||||
|
||||
this.employmentContractExportSilae(employmentContract, list);
|
||||
|
||||
String fileName = this.employmentContractExportName() + ".csv";
|
||||
String filePath = AppSettings.get().get("file.upload.dir");
|
||||
new File(filePath).mkdirs();
|
||||
|
||||
String[] headers = employmentContractExportHeaders();
|
||||
|
||||
CsvTool.csvWriter(filePath, fileName, ';', headers, list);
|
||||
|
||||
Path path = Paths.get(filePath + System.getProperty("file.separator") + fileName);
|
||||
|
||||
try (InputStream is = new FileInputStream(path.toFile())) {
|
||||
Beans.get(MetaFiles.class).attach(is, fileName, employmentContract);
|
||||
}
|
||||
}
|
||||
|
||||
public void employmentContractExportSilae(
|
||||
EmploymentContract employmentContract, List<String[]> list) {
|
||||
String[] item = new String[21];
|
||||
|
||||
item[0] = employmentContract.getId().toString();
|
||||
item[1] =
|
||||
employmentContract.getStartDate() == null
|
||||
? ""
|
||||
: employmentContract.getStartDate().toString();
|
||||
item[2] =
|
||||
employmentContract.getEndDate() == null ? "" : employmentContract.getEndDate().toString();
|
||||
|
||||
Employee employee = employmentContract.getEmployee();
|
||||
item[4] = employee.getMaritalName();
|
||||
|
||||
Partner contactPartner = employee.getContactPartner();
|
||||
if (contactPartner != null) {
|
||||
item[3] = contactPartner.getName();
|
||||
item[5] = contactPartner.getFirstName();
|
||||
|
||||
Address mainAddress = contactPartner.getMainAddress();
|
||||
if (mainAddress != null) {
|
||||
item[6] = mainAddress.getAddressL4();
|
||||
item[7] = mainAddress.getAddressL2();
|
||||
item[8] = mainAddress.getZip();
|
||||
item[9] = mainAddress.getCity().getName();
|
||||
}
|
||||
|
||||
item[10] = contactPartner.getMobilePhone();
|
||||
item[11] = contactPartner.getFixedPhone();
|
||||
item[12] =
|
||||
contactPartner.getEmailAddress() == null
|
||||
? ""
|
||||
: contactPartner.getEmailAddress().getAddress();
|
||||
}
|
||||
|
||||
item[13] = employee.getBirthDate() == null ? "" : employee.getBirthDate().toString();
|
||||
|
||||
Department birthDepartment = employee.getDepartmentOfBirth();
|
||||
if (birthDepartment != null) {
|
||||
item[14] = birthDepartment.getName();
|
||||
item[16] = !birthDepartment.getCode().equals("99") ? "FR - FRANCE" : "Oui";
|
||||
}
|
||||
|
||||
item[15] = employee.getCityOfBirth() == null ? "" : employee.getCityOfBirth().getName();
|
||||
item[17] = employee.getSocialSecurityNumber();
|
||||
item[18] = employmentContract.getPayCompany().getName();
|
||||
item[19] =
|
||||
employmentContract.getContractType() == null
|
||||
? ""
|
||||
: employmentContract.getContractType().getId().toString();
|
||||
item[20] = employee.getMaidenName();
|
||||
|
||||
list.add(item);
|
||||
}
|
||||
|
||||
public String employmentContractExportName() {
|
||||
return I18n.get("Employment contract")
|
||||
+ " - "
|
||||
+ Beans.get(AppBaseService.class).getTodayDateTime().toLocalDateTime().toString();
|
||||
}
|
||||
|
||||
public String[] employmentContractExportHeaders() {
|
||||
String[] headers = {
|
||||
I18n.get("MATRICULE"),
|
||||
I18n.get("DATE D'ENTREE"),
|
||||
I18n.get("DATE DE SORTIE"),
|
||||
I18n.get("NOM"),
|
||||
I18n.get("NOM MARITAL"),
|
||||
I18n.get("PRENOM"),
|
||||
I18n.get("VOIE"),
|
||||
I18n.get("COMPLEMENT"),
|
||||
I18n.get("CP"),
|
||||
I18n.get("VILLE"),
|
||||
I18n.get("TEL"),
|
||||
I18n.get("TEL 2"),
|
||||
I18n.get("E-MAIL"),
|
||||
I18n.get("DATE NAISS"),
|
||||
I18n.get("DEPT NAISS"),
|
||||
I18n.get("LIEU"),
|
||||
I18n.get("ETRANGER"),
|
||||
I18n.get("NUMERO INSEE"),
|
||||
I18n.get("ETAB"),
|
||||
I18n.get("CDD"),
|
||||
I18n.get("NOM DE JEUNE FILLE")
|
||||
};
|
||||
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.db.Model;
|
||||
|
||||
public class HRMenuTagService {
|
||||
|
||||
/**
|
||||
* @param modelConcerned
|
||||
* @param status 1 : Draft 2 : Confirmed 3 : Validated 4 : Refused 5 : Canceled
|
||||
* @return The number of records
|
||||
*/
|
||||
public <T extends Model> String countRecordsTag(Class<T> modelConcerned, int status) {
|
||||
|
||||
User user = AuthUtils.getUser();
|
||||
Employee employee = user.getEmployee();
|
||||
|
||||
if (employee != null && employee.getHrManager()) {
|
||||
|
||||
return Long.toString(
|
||||
JPA.all(modelConcerned)
|
||||
.filter("self.statusSelect = :_statusSelect")
|
||||
.bind("_statusSelect", status)
|
||||
.count());
|
||||
|
||||
} else {
|
||||
|
||||
return Long.toString(
|
||||
JPA.all(modelConcerned)
|
||||
.filter(
|
||||
"self.user.employee.managerUser.id = :_userId AND self.statusSelect = :_statusSelect")
|
||||
.bind("_userId", user.getId())
|
||||
.bind("_statusSelect", status)
|
||||
.count());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseRepository;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
|
||||
public class HRMenuValidateService {
|
||||
|
||||
public void createValidateDomain(
|
||||
User user, Employee employee, ActionView.ActionViewBuilder actionView) {
|
||||
|
||||
actionView
|
||||
.domain("self.statusSelect = :_statusSelect")
|
||||
.context("_statusSelect", ExpenseRepository.STATUS_CONFIRMED);
|
||||
|
||||
if (employee == null || !employee.getHrManager()) {
|
||||
if (employee == null || employee.getManagerUser() == null) {
|
||||
actionView
|
||||
.domain(
|
||||
actionView.get().getDomain()
|
||||
+ " AND (self.user = :_user OR self.user.employee.managerUser = :_user)")
|
||||
.context("_user", user);
|
||||
} else {
|
||||
actionView
|
||||
.domain(actionView.get().getDomain() + " AND self.user.employee.managerUser = :_user")
|
||||
.context("_user", user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,484 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.base.db.AppBase;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Year;
|
||||
import com.axelor.apps.base.db.repo.AppBaseRepository;
|
||||
import com.axelor.apps.base.service.MapService;
|
||||
import com.axelor.apps.base.service.YearServiceImpl;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.ExpenseLine;
|
||||
import com.axelor.apps.hr.db.KilometricAllowanceRate;
|
||||
import com.axelor.apps.hr.db.KilometricAllowanceRule;
|
||||
import com.axelor.apps.hr.db.KilometricLog;
|
||||
import com.axelor.apps.hr.db.repo.KilometricAllowanceRateRepository;
|
||||
import com.axelor.apps.hr.db.repo.KilometricLogRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.apps.hr.translation.ITranslation;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.common.ObjectUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import wslite.json.JSONException;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
public class KilometricService {
|
||||
|
||||
private AppBaseService appBaseService;
|
||||
private KilometricLogRepository kilometricLogRepo;
|
||||
private MapService mapService;
|
||||
|
||||
@Inject
|
||||
public KilometricService(
|
||||
AppBaseService appBaseService,
|
||||
KilometricLogRepository kilometricLogRepo,
|
||||
MapService mapService) {
|
||||
this.appBaseService = appBaseService;
|
||||
this.kilometricLogRepo = kilometricLogRepo;
|
||||
this.mapService = mapService;
|
||||
}
|
||||
|
||||
public KilometricLog getKilometricLog(Employee employee, LocalDate refDate) {
|
||||
|
||||
for (KilometricLog log : employee.getKilometricLogList()) {
|
||||
|
||||
if (log.getYear().getFromDate().isBefore(refDate)
|
||||
&& log.getYear().getToDate().isAfter(refDate)) {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public KilometricLog getCurrentKilometricLog(Employee employee) {
|
||||
return getKilometricLog(employee, appBaseService.getTodayDate());
|
||||
}
|
||||
|
||||
public KilometricLog createKilometricLog(Employee employee, BigDecimal distance, Year year) {
|
||||
|
||||
KilometricLog log = new KilometricLog();
|
||||
log.setEmployee(employee);
|
||||
log.setDistanceTravelled(distance);
|
||||
log.setYear(year);
|
||||
return log;
|
||||
}
|
||||
|
||||
public KilometricLog getOrCreateKilometricLog(Employee employee, LocalDate date)
|
||||
throws AxelorException {
|
||||
|
||||
KilometricLog log = getKilometricLog(employee, date);
|
||||
|
||||
if (log != null) {
|
||||
return log;
|
||||
}
|
||||
if (employee.getMainEmploymentContract() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_CONTRACT_OF_EMPLOYMENT),
|
||||
employee.getName());
|
||||
}
|
||||
|
||||
Year year =
|
||||
Beans.get(YearServiceImpl.class)
|
||||
.getYear(date, employee.getMainEmploymentContract().getPayCompany());
|
||||
|
||||
if (year == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.KILOMETRIC_LOG_NO_YEAR),
|
||||
employee.getMainEmploymentContract().getPayCompany(),
|
||||
date);
|
||||
}
|
||||
|
||||
return createKilometricLog(employee, new BigDecimal("0.00"), year);
|
||||
}
|
||||
|
||||
public BigDecimal computeKilometricExpense(ExpenseLine expenseLine, Employee employee)
|
||||
throws AxelorException {
|
||||
|
||||
BigDecimal distance = expenseLine.getDistance();
|
||||
EmploymentContract mainEmploymentContract = employee.getMainEmploymentContract();
|
||||
if (mainEmploymentContract == null || mainEmploymentContract.getPayCompany() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_CONTRACT_OF_EMPLOYMENT),
|
||||
employee.getName());
|
||||
}
|
||||
Company company = mainEmploymentContract.getPayCompany();
|
||||
|
||||
KilometricLog log = getKilometricLog(employee, expenseLine.getExpenseDate());
|
||||
BigDecimal previousDistance = log == null ? BigDecimal.ZERO : log.getDistanceTravelled();
|
||||
|
||||
KilometricAllowanceRate allowance =
|
||||
expenseLine.getKilometricAllowParam() != null
|
||||
? Beans.get(KilometricAllowanceRateRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.kilometricAllowParam.id = :_kilometricAllowParamId "
|
||||
+ "and self.hrConfig.id = :_hrConfigId")
|
||||
.bind("_kilometricAllowParamId", expenseLine.getKilometricAllowParam().getId())
|
||||
.bind("_hrConfigId", Beans.get(HRConfigService.class).getHRConfig(company).getId())
|
||||
.fetchOne()
|
||||
: null;
|
||||
if (allowance == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.KILOMETRIC_ALLOWANCE_RATE_MISSING),
|
||||
expenseLine.getKilometricAllowParam() != null
|
||||
? expenseLine.getKilometricAllowParam().getName()
|
||||
: "",
|
||||
company.getName());
|
||||
}
|
||||
|
||||
List<KilometricAllowanceRule> ruleList = new ArrayList<>();
|
||||
List<KilometricAllowanceRule> allowanceRuleList = allowance.getKilometricAllowanceRuleList();
|
||||
if (ObjectUtils.notEmpty(allowanceRuleList)) {
|
||||
for (KilometricAllowanceRule rule : allowanceRuleList) {
|
||||
|
||||
if (rule.getMinimumCondition().compareTo(previousDistance.add(distance)) <= 0
|
||||
&& rule.getMaximumCondition().compareTo(previousDistance) >= 0) {
|
||||
ruleList.add(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ruleList.isEmpty()) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.KILOMETRIC_ALLOWANCE_NO_RULE),
|
||||
allowance.getKilometricAllowParam().getName());
|
||||
}
|
||||
|
||||
BigDecimal price = BigDecimal.ZERO;
|
||||
|
||||
if (ruleList.size() == 1) {
|
||||
price = distance.multiply(ruleList.get(0).getRate());
|
||||
} else {
|
||||
Collections.sort(
|
||||
ruleList,
|
||||
(object1, object2) ->
|
||||
object1.getMinimumCondition().compareTo(object2.getMinimumCondition()));
|
||||
for (KilometricAllowanceRule rule : ruleList) {
|
||||
BigDecimal min = rule.getMinimumCondition().max(previousDistance);
|
||||
BigDecimal max = rule.getMaximumCondition().min(previousDistance.add(distance));
|
||||
price = price.add(max.subtract(min).multiply(rule.getRate()));
|
||||
}
|
||||
}
|
||||
|
||||
return price.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void updateKilometricLog(ExpenseLine expenseLine, Employee employee)
|
||||
throws AxelorException {
|
||||
|
||||
KilometricLog log = getOrCreateKilometricLog(employee, expenseLine.getExpenseDate());
|
||||
log.setDistanceTravelled(log.getDistanceTravelled().add(expenseLine.getDistance()));
|
||||
if (log.getExpenseLineList() == null || !log.getExpenseLineList().contains(expenseLine)) {
|
||||
log.addExpenseLineListItem(expenseLine);
|
||||
}
|
||||
kilometricLogRepo.save(log);
|
||||
}
|
||||
|
||||
public BigDecimal computeDistance(ExpenseLine expenseLine) throws AxelorException {
|
||||
return computeDistance(expenseLine.getFromCity(), expenseLine.getToCity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the distance between two cities.
|
||||
*
|
||||
* @param fromCity
|
||||
* @param toCity
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected BigDecimal computeDistance(String fromCity, String toCity) throws AxelorException {
|
||||
|
||||
BigDecimal distance = BigDecimal.ZERO;
|
||||
if (StringUtils.isEmpty(fromCity)
|
||||
|| StringUtils.isEmpty(toCity)
|
||||
|| fromCity.equalsIgnoreCase(toCity)) return distance;
|
||||
|
||||
AppBase appBase = appBaseService.getAppBase();
|
||||
try {
|
||||
switch (appBase.getMapApiSelect()) {
|
||||
case AppBaseRepository.MAP_API_GOOGLE:
|
||||
distance = this.getDistanceUsingGoogle(fromCity, toCity);
|
||||
break;
|
||||
|
||||
case AppBaseRepository.MAP_API_OPEN_STREET_MAP:
|
||||
distance = this.getDistanceUsingOSM(fromCity, toCity);
|
||||
break;
|
||||
}
|
||||
return distance;
|
||||
} catch (URISyntaxException | IOException | JSONException e) {
|
||||
throw new AxelorException(e, TraceBackRepository.CATEGORY_CONFIGURATION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
protected BigDecimal getDistanceUsingGoogle(String fromCity, String toCity)
|
||||
throws JSONException, AxelorException, URISyntaxException, IOException {
|
||||
User user = AuthUtils.getUser();
|
||||
JSONObject json = getGoogleMapsDistanceMatrixResponse(fromCity, toCity, user.getLanguage());
|
||||
String status = json.getString("status");
|
||||
|
||||
if (status.equals("OK")) {
|
||||
JSONObject response =
|
||||
json.getJSONArray("rows").getJSONObject(0).getJSONArray("elements").getJSONObject(0);
|
||||
status = response.getString("status");
|
||||
if (status.equals("OK")) {
|
||||
return BigDecimal.valueOf(response.getJSONObject("distance").getDouble("value") / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
String msg =
|
||||
json.has("error_message")
|
||||
? String.format("%s / %s", status, json.getString("error_message"))
|
||||
: status;
|
||||
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
IExceptionMessage.KILOMETRIC_ALLOWANCE_GOOGLE_MAPS_ERROR,
|
||||
msg);
|
||||
}
|
||||
|
||||
protected BigDecimal getDistanceUsingOSM(String fromCity, String toCity)
|
||||
throws JSONException, AxelorException, URISyntaxException, IOException {
|
||||
AppBase appBase = appBaseService.getAppBase();
|
||||
BigDecimal distance = BigDecimal.ZERO;
|
||||
|
||||
if (appBase.getOsmRoutingServiceApiSelect() == AppBaseRepository.ROUTING_API_YOURS) {
|
||||
distance = this.getDistanceUsingYOURSApi(fromCity, toCity);
|
||||
} else if (appBase.getOsmRoutingServiceApiSelect() == AppBaseRepository.ROUTING_API_OSRM) {
|
||||
distance = this.getDistanceUsingOSRMApi(fromCity, toCity);
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
protected BigDecimal getDistanceUsingYOURSApi(String fromCity, String toCity)
|
||||
throws AxelorException, JSONException, URISyntaxException, IOException {
|
||||
BigDecimal distance = BigDecimal.ZERO;
|
||||
JSONObject json = getYOURSApiResponse(fromCity, toCity);
|
||||
distance = BigDecimal.valueOf(json.getJSONObject("properties").getDouble("distance"));
|
||||
if (distance.compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
IExceptionMessage.KILOMETRIC_ALLOWANCE_OSM_ERROR,
|
||||
ITranslation.NO_ROUTE);
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
protected BigDecimal getDistanceUsingOSRMApi(String fromCity, String toCity)
|
||||
throws AxelorException, JSONException, URISyntaxException, IOException {
|
||||
JSONObject json = getOSRMApiResponse(fromCity, toCity);
|
||||
String status = json.getString("code");
|
||||
|
||||
if (status.equals("Ok")) {
|
||||
return BigDecimal.valueOf(
|
||||
json.getJSONArray("routes").getJSONObject(0).getDouble("distance") / 1000);
|
||||
}
|
||||
|
||||
String msg = json.has("message") ? String.format("%s", json.getString("message")) : status;
|
||||
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
IExceptionMessage.KILOMETRIC_ALLOWANCE_OSM_ERROR,
|
||||
msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON response from Google Maps Distance Matrix API.
|
||||
*
|
||||
* @param origins
|
||||
* @param destinations
|
||||
* @param language
|
||||
* @return
|
||||
* @throws URISyntaxException
|
||||
* @throws IOException
|
||||
* @throws JSONException
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected JSONObject getGoogleMapsDistanceMatrixResponse(
|
||||
String origins, String destinations, String language)
|
||||
throws URISyntaxException, IOException, JSONException, AxelorException {
|
||||
|
||||
URIBuilder ub = new URIBuilder("https://maps.googleapis.com/maps/api/distancematrix/json");
|
||||
ub.addParameter("origins", origins);
|
||||
ub.addParameter("destinations", destinations);
|
||||
ub.addParameter("language", language);
|
||||
ub.addParameter("key", mapService.getGoogleMapsApiKey());
|
||||
|
||||
return this.getApiResponse(
|
||||
ub.toString(), IExceptionMessage.KILOMETRIC_ALLOWANCE_GOOGLE_MAPS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON response from Open Street Route Machine API.
|
||||
*
|
||||
* @param origins
|
||||
* @param destinations
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
* @throws JSONException
|
||||
* @throws URISyntaxException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected JSONObject getOSRMApiResponse(String origins, String destinations)
|
||||
throws AxelorException, JSONException, URISyntaxException, IOException {
|
||||
|
||||
Map<String, Object> originMap = this.getLocationMap(origins);
|
||||
Map<String, Object> destinationMap = this.getLocationMap(destinations);
|
||||
|
||||
String originCoordinates = originMap.get("longitude") + "," + originMap.get("latitude");
|
||||
String destinationCoordinates =
|
||||
destinationMap.get("longitude") + "," + destinationMap.get("latitude");
|
||||
String uri =
|
||||
String.format(
|
||||
"https://router.project-osrm.org/route/v1/driving/%s;%s",
|
||||
originCoordinates, destinationCoordinates);
|
||||
|
||||
return this.getApiResponse(uri, IExceptionMessage.KILOMETRIC_ALLOWANCE_OSM_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON response from YOURS(Yet Another Openstreetmap Route Service) API.
|
||||
*
|
||||
* @param origins
|
||||
* @param destinations
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
* @throws JSONException
|
||||
* @throws URISyntaxException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected JSONObject getYOURSApiResponse(String origins, String destinations)
|
||||
throws AxelorException, JSONException, URISyntaxException, IOException {
|
||||
|
||||
Map<String, Object> originMap = this.getLocationMap(origins);
|
||||
Map<String, Object> destinationMap = this.getLocationMap(destinations);
|
||||
|
||||
String flat = originMap.get("latitude").toString();
|
||||
String flon = originMap.get("longitude").toString();
|
||||
String tlat = destinationMap.get("latitude").toString();
|
||||
String tlon = destinationMap.get("longitude").toString();
|
||||
|
||||
URIBuilder ub = new URIBuilder("http://www.yournavigation.org/api/1.0/gosmore.php");
|
||||
ub.addParameter("format", "geojson");
|
||||
ub.addParameter("flat", flat);
|
||||
ub.addParameter("flon", flon);
|
||||
ub.addParameter("tlat", tlat);
|
||||
ub.addParameter("tlon", tlon);
|
||||
ub.addParameter("v", "motorcar");
|
||||
ub.addParameter("fast", "0");
|
||||
return this.getApiResponse(ub.toString(), IExceptionMessage.KILOMETRIC_ALLOWANCE_OSM_ERROR);
|
||||
}
|
||||
|
||||
protected Map<String, Object> getLocationMap(String location) throws AxelorException {
|
||||
Map<String, Object> locationMap;
|
||||
try {
|
||||
locationMap = mapService.getMap(location);
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
IExceptionMessage.KILOMETRIC_ALLOWANCE_OSM_ERROR,
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
if (locationMap == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
IExceptionMessage.KILOMETRIC_ALLOWANCE_OSM_ERROR,
|
||||
ITranslation.NO_SUCH_PLACE);
|
||||
}
|
||||
return locationMap;
|
||||
}
|
||||
|
||||
protected JSONObject getApiResponse(String urlString, String exceptionMessage)
|
||||
throws IOException, JSONException, AxelorException {
|
||||
|
||||
URL url = new URL(urlString);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
int responseCode = connection.getResponseCode();
|
||||
|
||||
this.checkResponseStatus(responseCode, exceptionMessage);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try (BufferedReader in =
|
||||
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String inputLine;
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
sb.append(inputLine + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
String response = sb.toString();
|
||||
JSONObject json;
|
||||
// throw exception if response is not json
|
||||
try {
|
||||
json = new JSONObject(response);
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, exceptionMessage, response);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
protected void checkResponseStatus(int responseCode, String exceptionMessage)
|
||||
throws AxelorException {
|
||||
if (responseCode == 200) {
|
||||
return;
|
||||
} else if (responseCode == 429) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
exceptionMessage,
|
||||
ITranslation.REQUEST_OVERFLOW);
|
||||
} else {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
exceptionMessage,
|
||||
"Server returned status code " + responseCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.base.db.Period;
|
||||
import com.axelor.apps.hr.db.Absence;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.MonthlyReport;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface MonthlyReportService {
|
||||
|
||||
@Transactional
|
||||
void createMensuelReport(Employee employee, Period period, LocalDate startDate, LocalDate endDate, List<DailyReport> employeeDailyReports, List<Absence> employeeAbsences);
|
||||
|
||||
void updateMensuelReport(MonthlyReport monthlyReport, Employee employee, Period period, LocalDate startDate, LocalDate endDate, List<DailyReport> employeeDailyReports, List<Absence> employeeAbsences);
|
||||
|
||||
/*void calculePrimeAssiduite(Mensuels mensuels);*/
|
||||
}
|
||||
@ -0,0 +1,683 @@
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.apps.base.db.Period;
|
||||
import com.axelor.apps.hr.db.Absence;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.LeaveRequest;
|
||||
import com.axelor.apps.hr.db.MonthlyReport;
|
||||
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||
import com.axelor.apps.hr.db.repo.AuthorizationRepository;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.db.repo.MonthlyReportRepository;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class MonthlyReportServiceImpl implements MonthlyReportService {
|
||||
|
||||
private final MonthlyReportRepository monthlyReportRepository;
|
||||
private final DailyReportRepository dailyReportRepository;
|
||||
private final AuthorizationRepository authorizationRepository;
|
||||
private final AbsenceRepository absenceRepository;
|
||||
|
||||
@Inject
|
||||
public MonthlyReportServiceImpl(
|
||||
MonthlyReportRepository monthlyReportRepository,
|
||||
DailyReportRepository dailyReportRepository,
|
||||
AuthorizationRepository authorizationRepository,
|
||||
AbsenceRepository absenceRepository) {
|
||||
|
||||
this.monthlyReportRepository = monthlyReportRepository;
|
||||
this.dailyReportRepository = dailyReportRepository;
|
||||
this.authorizationRepository = authorizationRepository;
|
||||
this.absenceRepository = absenceRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void createMensuelReport(
|
||||
Employee employee,
|
||||
Period period,
|
||||
LocalDate startDate,
|
||||
LocalDate endDate,
|
||||
List<DailyReport> employeeDailyReports,
|
||||
List<Absence> employeeAbsences) {
|
||||
|
||||
Boolean hasNuissance = employee.getHasNuissance();
|
||||
LocalDate firstDayOfMonth = endDate.with(TemporalAdjusters.firstDayOfMonth());
|
||||
// Perform calculations
|
||||
Integer monthlyAllowance = 0;
|
||||
Integer monthlyAllowanceRecall = 0;
|
||||
BigDecimal monthlyNightHours = BigDecimal.ZERO;
|
||||
BigDecimal monthlyExtraHours50 = BigDecimal.ZERO;
|
||||
BigDecimal monthlyExtraHours100 = BigDecimal.ZERO;
|
||||
BigDecimal excessHours50 = BigDecimal.ZERO;
|
||||
BigDecimal excessHours100 = BigDecimal.ZERO;
|
||||
BigDecimal totalSupHours = BigDecimal.ZERO;
|
||||
|
||||
BigDecimal monthlyITP = BigDecimal.ZERO;
|
||||
BigDecimal totalNuissance = BigDecimal.ZERO;
|
||||
BigDecimal totalAbsence = BigDecimal.ZERO;
|
||||
BigDecimal totalWorkHours = BigDecimal.ZERO;
|
||||
|
||||
BigDecimal breastfeedingAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal authorizedPaidAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal recuperationLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal trainingAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal missionAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal hospitalizationAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal sicknessAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal workAccidentMonth = BigDecimal.ZERO;
|
||||
BigDecimal maternityMonth = BigDecimal.ZERO;
|
||||
BigDecimal authorizedUnpaidAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal annualLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal unpaidLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal statutoryLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal resignationAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal contractEndAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal justifiedAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal recruitmentAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal suspensionAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal militaryServiceAbsence = BigDecimal.ZERO;
|
||||
BigDecimal irregularAbsenceMonth = BigDecimal.ZERO;
|
||||
|
||||
// monthlyAllowance = monthlyAllowance + remainingDateToLastOfMonth;
|
||||
|
||||
// Calculate totals for DailyReport
|
||||
for (DailyReport dailyReport : employeeDailyReports) {
|
||||
// Panier
|
||||
/*LocalDate reportDate = dailyReport.getReportDate();
|
||||
Integer panier = dailyReport.getPanier();
|
||||
if (reportDate.isAfter(firstDayOfMonth) && panier == 1) {
|
||||
monthlyAllowance = monthlyAllowance + 1;
|
||||
}*/
|
||||
|
||||
monthlyAllowance = monthlyAllowance + dailyReport.getAllowance();
|
||||
;
|
||||
monthlyAllowanceRecall = monthlyAllowanceRecall + dailyReport.getAllowanceRecall();
|
||||
monthlyNightHours = monthlyNightHours.add(dailyReport.getNightHours());
|
||||
totalWorkHours = totalWorkHours.add(dailyReport.getWorkHours());
|
||||
|
||||
BigDecimal heureSup50 =
|
||||
dailyReport.getExtraHours50() != null ? dailyReport.getExtraHours50() : BigDecimal.ZERO;
|
||||
BigDecimal heureSup100 =
|
||||
dailyReport.getExtraHours100() != null ? dailyReport.getExtraHours100() : BigDecimal.ZERO;
|
||||
BigDecimal itp = dailyReport.getItp() != null ? dailyReport.getItp() : BigDecimal.ZERO;
|
||||
BigDecimal nuissance =
|
||||
dailyReport.getNuissance() != null ? dailyReport.getNuissance() : BigDecimal.ZERO;
|
||||
|
||||
BigDecimal supHours50ToDeduce =
|
||||
dailyReport.getSupHours50ToDeduce() != null
|
||||
? dailyReport.getSupHours50ToDeduce()
|
||||
: BigDecimal.ZERO;
|
||||
BigDecimal supHours100ToDeduce =
|
||||
dailyReport.getSupHours100ToDeduce() != null
|
||||
? dailyReport.getSupHours100ToDeduce()
|
||||
: BigDecimal.ZERO;
|
||||
BigDecimal itpToDeduce =
|
||||
dailyReport.getItpToDeduce() != null ? dailyReport.getItpToDeduce() : BigDecimal.ZERO;
|
||||
BigDecimal nuissanceToDeduce =
|
||||
dailyReport.getNuissanceToDeduce() != null
|
||||
? dailyReport.getNuissanceToDeduce()
|
||||
: BigDecimal.ZERO;
|
||||
|
||||
if (dailyReport.getDeduceSupHours50() && heureSup50.compareTo(supHours50ToDeduce) > 0) {
|
||||
heureSup50 = heureSup50.subtract(supHours50ToDeduce);
|
||||
}
|
||||
|
||||
if (dailyReport.getDeduceSupHours100() && heureSup100.compareTo(supHours100ToDeduce) > 0) {
|
||||
heureSup100 = heureSup100.subtract(supHours100ToDeduce);
|
||||
}
|
||||
|
||||
if (dailyReport.getDeduceItp() && itp.compareTo(itpToDeduce) > 0) {
|
||||
itp = itp.subtract(itpToDeduce);
|
||||
}
|
||||
|
||||
if (dailyReport.getDeduceNuissance() && nuissance.compareTo(nuissanceToDeduce) > 0) {
|
||||
nuissance = nuissance.subtract(nuissanceToDeduce);
|
||||
}
|
||||
|
||||
monthlyITP = monthlyITP.add(itp);
|
||||
totalNuissance = totalNuissance.add(nuissance);
|
||||
|
||||
// Sup Hours
|
||||
if (dailyReport.getIsValidSupHours()) {
|
||||
|
||||
// Handle HeureSup50
|
||||
if (heureSup50 != null) {
|
||||
if (totalSupHours.add(heureSup50).compareTo(new BigDecimal(32)) <= 0) {
|
||||
// If the total hours are still less than or equal to 32 after adding new hours
|
||||
monthlyExtraHours50 = monthlyExtraHours50.add(heureSup50);
|
||||
totalSupHours = totalSupHours.add(heureSup50);
|
||||
} else if (totalSupHours.compareTo(new BigDecimal(32)) < 0) {
|
||||
// If totalSupHours is less than 32, but adding heureSup50 exceeds 32
|
||||
BigDecimal remainingHours = new BigDecimal(32).subtract(totalSupHours);
|
||||
monthlyExtraHours50 = monthlyExtraHours50.add(remainingHours);
|
||||
totalSupHours = totalSupHours.add(remainingHours);
|
||||
|
||||
// Add the excess to excessHours50
|
||||
excessHours50 = excessHours50.add(heureSup50.subtract(remainingHours));
|
||||
} else {
|
||||
// If totalSupHours already exceeds 32, all new hours go to excess
|
||||
excessHours50 = excessHours50.add(heureSup50);
|
||||
}
|
||||
}
|
||||
// Handle HeureSup100
|
||||
if (heureSup100 != null) {
|
||||
if (totalSupHours.add(heureSup100).compareTo(new BigDecimal(32)) <= 0) {
|
||||
// If the total hours are still less than or equal to 32 after adding new hours
|
||||
monthlyExtraHours100 = monthlyExtraHours100.add(heureSup100);
|
||||
totalSupHours = totalSupHours.add(heureSup100);
|
||||
} else if (totalSupHours.compareTo(new BigDecimal(32)) < 0) {
|
||||
// If totalSupHours is less than 32, but adding heureSup100 exceeds 32
|
||||
BigDecimal remainingHours = new BigDecimal(32).subtract(totalSupHours);
|
||||
monthlyExtraHours100 = monthlyExtraHours100.add(remainingHours);
|
||||
totalSupHours = totalSupHours.add(remainingHours);
|
||||
|
||||
// Add the excess to excessHours100
|
||||
excessHours100 = excessHours100.add(heureSup100.subtract(remainingHours));
|
||||
} else {
|
||||
// If totalSupHours already exceeds 32, all new hours go to excess
|
||||
excessHours100 = excessHours100.add(heureSup100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Boolean isAuthorizedAbsence = dailyReport.getIsAuthorizedAbsence();
|
||||
Boolean isAuthorizedLateArrival = dailyReport.getIsAuthorizedLateArrival();
|
||||
Boolean isAuthorizedEarlyDeparture = dailyReport.getIsAuthorizedEarlyDeparture();
|
||||
LeaveRequest leaveRequest = dailyReport.getLeaveRequest();
|
||||
Set<Absence> absences = dailyReport.getAbsenceSet();
|
||||
|
||||
if (dailyReport.getAbsenceHours() != null
|
||||
&& dailyReport.getAbsenceHours().compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (isAuthorizedAbsence == false
|
||||
&& isAuthorizedLateArrival == false
|
||||
&& isAuthorizedEarlyDeparture == false
|
||||
&& leaveRequest == null
|
||||
&& absences == null) {
|
||||
irregularAbsenceMonth = irregularAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||
} else if (isAuthorizedAbsence) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||
} else if (isAuthorizedLateArrival) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getLateArrival());
|
||||
} else if (isAuthorizedEarlyDeparture) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getEarlyDeparture());
|
||||
} else if (leaveRequest != null) {
|
||||
recuperationLeaveAbsenceMonth =
|
||||
recuperationLeaveAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||
} else if (absences != null) {
|
||||
for (Absence absence : absences) {
|
||||
totalAbsence = dailyReport.getAbsenceHours();
|
||||
switch (absence.getAbsenceType()) {
|
||||
case 0:
|
||||
breastfeedingAbsenceMonth = breastfeedingAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 1:
|
||||
recuperationLeaveAbsenceMonth = recuperationLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 2:
|
||||
breastfeedingAbsenceMonth = breastfeedingAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 3:
|
||||
trainingAbsenceMonth = trainingAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 4:
|
||||
missionAbsenceMonth = missionAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 5:
|
||||
hospitalizationAbsenceMonth = hospitalizationAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 6:
|
||||
sicknessAbsenceMonth = sicknessAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 7:
|
||||
workAccidentMonth = workAccidentMonth.add(totalAbsence);
|
||||
break;
|
||||
case 8:
|
||||
maternityMonth = maternityMonth.add(totalAbsence);
|
||||
break;
|
||||
case 9:
|
||||
authorizedUnpaidAbsenceMonth = authorizedUnpaidAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 10:
|
||||
annualLeaveAbsenceMonth = annualLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 11:
|
||||
unpaidLeaveAbsenceMonth = unpaidLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 12:
|
||||
statutoryLeaveAbsenceMonth = statutoryLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 13:
|
||||
resignationAbsenceMonth = resignationAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 14:
|
||||
contractEndAbsenceMonth = contractEndAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 15:
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 16:
|
||||
recruitmentAbsenceMonth = recruitmentAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 17:
|
||||
suspensionAbsenceMonth = suspensionAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 18:
|
||||
militaryServiceAbsence = militaryServiceAbsence.add(totalAbsence);
|
||||
break;
|
||||
case 19:
|
||||
if (dailyReport.getIsAuthorizedAbsence()) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(totalAbsence);
|
||||
} else {
|
||||
irregularAbsenceMonth = irregularAbsenceMonth.add(totalAbsence);
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
if (dailyReport.getIsAuthorizedLateArrival()) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getLateArrival());
|
||||
} else {
|
||||
irregularAbsenceMonth = irregularAbsenceMonth.add(dailyReport.getLateArrival());
|
||||
}
|
||||
break;
|
||||
case 21:
|
||||
if (dailyReport.getIsAuthorizedEarlyDeparture()) {
|
||||
justifiedAbsenceMonth =
|
||||
justifiedAbsenceMonth.add(dailyReport.getEarlyDeparture());
|
||||
} else {
|
||||
irregularAbsenceMonth =
|
||||
irregularAbsenceMonth.add(dailyReport.getEarlyDeparture());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Handle default case
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update or create MonthlyReport instance with calculated values
|
||||
MonthlyReport monthlyReport = new MonthlyReport();
|
||||
monthlyReport.setPeriod(period);
|
||||
monthlyReport.setEmployee(employee);
|
||||
monthlyReport.setMonthlyAllowance(monthlyAllowance);
|
||||
monthlyReport.setMonthlyAllowanceRecall(monthlyAllowanceRecall);
|
||||
monthlyReport.setMonthlyNightHours(monthlyNightHours);
|
||||
monthlyReport.setMonthlyExtraHours50(monthlyExtraHours50);
|
||||
monthlyReport.setMonthlyExtraHours100(monthlyExtraHours100);
|
||||
monthlyReport.setExcessHours50(excessHours50);
|
||||
monthlyReport.setExcessHours100(excessHours100);
|
||||
|
||||
monthlyReport.setMonthlyITP(monthlyITP);
|
||||
monthlyReport.setTotalNuissance(totalNuissance);
|
||||
monthlyReport.setTotalWorkHours(totalWorkHours);
|
||||
|
||||
// Set total absence values for each specific type
|
||||
monthlyReport.setBreastfeedingAbsenceMonth(breastfeedingAbsenceMonth);
|
||||
monthlyReport.setAuthorizedPaidAbsenceMonth(authorizedPaidAbsenceMonth);
|
||||
monthlyReport.setAuthorizedUnpaidAbsenceMonth(authorizedUnpaidAbsenceMonth);
|
||||
monthlyReport.setAnnualLeaveAbsenceMonth(annualLeaveAbsenceMonth);
|
||||
monthlyReport.setRecuperationLeaveAbsenceMonth(recuperationLeaveAbsenceMonth);
|
||||
monthlyReport.setUnpaidLeaveAbsenceMonth(unpaidLeaveAbsenceMonth);
|
||||
monthlyReport.setStatutoryLeaveAbsenceMonth(statutoryLeaveAbsenceMonth);
|
||||
monthlyReport.setResignationAbsenceMonth(resignationAbsenceMonth);
|
||||
monthlyReport.setContractEndAbsenceMonth(contractEndAbsenceMonth);
|
||||
monthlyReport.setTrainingAbsenceMonth(trainingAbsenceMonth);
|
||||
monthlyReport.setHospitalizationAbsenceMonth(hospitalizationAbsenceMonth);
|
||||
monthlyReport.setMissionAbsenceMonth(missionAbsenceMonth);
|
||||
monthlyReport.setSicknessAbsenceMonth(sicknessAbsenceMonth);
|
||||
monthlyReport.setWorkAccidentMonth(workAccidentMonth);
|
||||
monthlyReport.setMaternityMonth(maternityMonth);
|
||||
monthlyReport.setJustifiedAbsenceMonth(justifiedAbsenceMonth);
|
||||
monthlyReport.setRecruitmentAbsenceMonth(recruitmentAbsenceMonth);
|
||||
monthlyReport.setSuspensionAbsenceMonth(suspensionAbsenceMonth);
|
||||
monthlyReport.setMilitaryServiceAbsence(militaryServiceAbsence);
|
||||
monthlyReport.setIrregularAbsenceMonth(irregularAbsenceMonth);
|
||||
|
||||
// Save the MonthlyReport instance
|
||||
monthlyReportRepository.save(monthlyReport);
|
||||
}
|
||||
|
||||
public void updateMensuelReport(
|
||||
MonthlyReport monthlyReport,
|
||||
Employee employee,
|
||||
Period period,
|
||||
LocalDate startDate,
|
||||
LocalDate endDate,
|
||||
List<DailyReport> employeeDailyReports,
|
||||
List<Absence> employeeAbsences) {
|
||||
|
||||
Boolean hasNuissance = employee.getHasNuissance();
|
||||
LocalDate firstDayOfMonth = endDate.with(TemporalAdjusters.firstDayOfMonth());
|
||||
// Perform calculations
|
||||
Integer monthlyAllowance = 0;
|
||||
Integer monthlyAllowanceRecall = 0;
|
||||
BigDecimal monthlyNightHours = BigDecimal.ZERO;
|
||||
BigDecimal monthlyExtraHours50 = BigDecimal.ZERO;
|
||||
BigDecimal monthlyExtraHours100 = BigDecimal.ZERO;
|
||||
BigDecimal excessHours50 = BigDecimal.ZERO;
|
||||
BigDecimal excessHours100 = BigDecimal.ZERO;
|
||||
BigDecimal totalSupHours = BigDecimal.ZERO;
|
||||
|
||||
BigDecimal monthlyITP = BigDecimal.ZERO;
|
||||
BigDecimal totalNuissance = BigDecimal.ZERO;
|
||||
BigDecimal totalAbsence = BigDecimal.ZERO;
|
||||
BigDecimal totalWorkHours = BigDecimal.ZERO;
|
||||
|
||||
BigDecimal breastfeedingAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal authorizedPaidAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal recuperationLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal trainingAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal missionAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal hospitalizationAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal sicknessAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal workAccidentMonth = BigDecimal.ZERO;
|
||||
BigDecimal maternityMonth = BigDecimal.ZERO;
|
||||
BigDecimal authorizedUnpaidAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal annualLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal unpaidLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal statutoryLeaveAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal resignationAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal contractEndAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal justifiedAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal recruitmentAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal suspensionAbsenceMonth = BigDecimal.ZERO;
|
||||
BigDecimal militaryServiceAbsence = BigDecimal.ZERO;
|
||||
BigDecimal irregularAbsenceMonth = BigDecimal.ZERO;
|
||||
|
||||
// monthlyAllowance = monthlyAllowance + remainingDateToLastOfMonth;
|
||||
|
||||
// Calculate totals for DailyReport
|
||||
for (DailyReport dailyReport : employeeDailyReports) {
|
||||
// Panier
|
||||
/*LocalDate reportDate = dailyReport.getReportDate();
|
||||
Integer panier = dailyReport.getPanier();
|
||||
if (reportDate.isAfter(firstDayOfMonth) && panier == 1) {
|
||||
monthlyAllowance = monthlyAllowance + 1;
|
||||
}*/
|
||||
|
||||
monthlyAllowance = monthlyAllowance + dailyReport.getAllowance();
|
||||
;
|
||||
monthlyAllowanceRecall = monthlyAllowanceRecall + dailyReport.getAllowanceRecall();
|
||||
monthlyNightHours = monthlyNightHours.add(dailyReport.getNightHours());
|
||||
totalWorkHours = totalWorkHours.add(dailyReport.getWorkHours());
|
||||
|
||||
BigDecimal heureSup50 =
|
||||
dailyReport.getExtraHours50() != null ? dailyReport.getExtraHours50() : BigDecimal.ZERO;
|
||||
BigDecimal heureSup100 =
|
||||
dailyReport.getExtraHours100() != null ? dailyReport.getExtraHours100() : BigDecimal.ZERO;
|
||||
BigDecimal itp = dailyReport.getItp() != null ? dailyReport.getItp() : BigDecimal.ZERO;
|
||||
BigDecimal nuissance =
|
||||
dailyReport.getNuissance() != null ? dailyReport.getNuissance() : BigDecimal.ZERO;
|
||||
|
||||
BigDecimal supHours50ToDeduce =
|
||||
dailyReport.getSupHours50ToDeduce() != null
|
||||
? dailyReport.getSupHours50ToDeduce()
|
||||
: BigDecimal.ZERO;
|
||||
BigDecimal supHours100ToDeduce =
|
||||
dailyReport.getSupHours100ToDeduce() != null
|
||||
? dailyReport.getSupHours100ToDeduce()
|
||||
: BigDecimal.ZERO;
|
||||
BigDecimal itpToDeduce =
|
||||
dailyReport.getItpToDeduce() != null ? dailyReport.getItpToDeduce() : BigDecimal.ZERO;
|
||||
BigDecimal nuissanceToDeduce =
|
||||
dailyReport.getNuissanceToDeduce() != null
|
||||
? dailyReport.getNuissanceToDeduce()
|
||||
: BigDecimal.ZERO;
|
||||
|
||||
if (dailyReport.getDeduceSupHours50() && heureSup50.compareTo(supHours50ToDeduce) > 0) {
|
||||
heureSup50 = heureSup50.subtract(supHours50ToDeduce);
|
||||
}
|
||||
|
||||
if (dailyReport.getDeduceSupHours100() && heureSup100.compareTo(supHours100ToDeduce) > 0) {
|
||||
heureSup100 = heureSup100.subtract(supHours100ToDeduce);
|
||||
}
|
||||
|
||||
if (dailyReport.getDeduceItp() && itp.compareTo(itpToDeduce) > 0) {
|
||||
itp = itp.subtract(itpToDeduce);
|
||||
}
|
||||
|
||||
if (dailyReport.getDeduceNuissance() && nuissance.compareTo(nuissanceToDeduce) > 0) {
|
||||
nuissance = nuissance.subtract(nuissanceToDeduce);
|
||||
}
|
||||
|
||||
monthlyITP = monthlyITP.add(itp);
|
||||
totalNuissance = totalNuissance.add(nuissance);
|
||||
|
||||
// Sup Hours
|
||||
if (dailyReport.getIsValidSupHours()) {
|
||||
|
||||
// Handle HeureSup50
|
||||
if (heureSup50 != null) {
|
||||
if (totalSupHours.add(heureSup50).compareTo(new BigDecimal(32)) <= 0) {
|
||||
// If the total hours are still less than or equal to 32 after adding new hours
|
||||
monthlyExtraHours50 = monthlyExtraHours50.add(heureSup50);
|
||||
totalSupHours = totalSupHours.add(heureSup50);
|
||||
} else if (totalSupHours.compareTo(new BigDecimal(32)) < 0) {
|
||||
// If totalSupHours is less than 32, but adding heureSup50 exceeds 32
|
||||
BigDecimal remainingHours = new BigDecimal(32).subtract(totalSupHours);
|
||||
monthlyExtraHours50 = monthlyExtraHours50.add(remainingHours);
|
||||
totalSupHours = totalSupHours.add(remainingHours);
|
||||
|
||||
// Add the excess to excessHours50
|
||||
excessHours50 = excessHours50.add(heureSup50.subtract(remainingHours));
|
||||
} else {
|
||||
// If totalSupHours already exceeds 32, all new hours go to excess
|
||||
excessHours50 = excessHours50.add(heureSup50);
|
||||
}
|
||||
}
|
||||
// Handle HeureSup100
|
||||
if (heureSup100 != null) {
|
||||
if (totalSupHours.add(heureSup100).compareTo(new BigDecimal(32)) <= 0) {
|
||||
// If the total hours are still less than or equal to 32 after adding new hours
|
||||
monthlyExtraHours100 = monthlyExtraHours100.add(heureSup100);
|
||||
totalSupHours = totalSupHours.add(heureSup100);
|
||||
} else if (totalSupHours.compareTo(new BigDecimal(32)) < 0) {
|
||||
// If totalSupHours is less than 32, but adding heureSup100 exceeds 32
|
||||
BigDecimal remainingHours = new BigDecimal(32).subtract(totalSupHours);
|
||||
monthlyExtraHours100 = monthlyExtraHours100.add(remainingHours);
|
||||
totalSupHours = totalSupHours.add(remainingHours);
|
||||
|
||||
// Add the excess to excessHours100
|
||||
excessHours100 = excessHours100.add(heureSup100.subtract(remainingHours));
|
||||
} else {
|
||||
// If totalSupHours already exceeds 32, all new hours go to excess
|
||||
excessHours100 = excessHours100.add(heureSup100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Boolean isAuthorizedAbsence = dailyReport.getIsAuthorizedAbsence();
|
||||
Boolean isAuthorizedLateArrival = dailyReport.getIsAuthorizedLateArrival();
|
||||
Boolean isAuthorizedEarlyDeparture = dailyReport.getIsAuthorizedEarlyDeparture();
|
||||
LeaveRequest leaveRequest = dailyReport.getLeaveRequest();
|
||||
Set<Absence> absences = dailyReport.getAbsenceSet();
|
||||
|
||||
if (dailyReport.getAbsenceHours() != null
|
||||
&& dailyReport.getAbsenceHours().compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (isAuthorizedAbsence == false
|
||||
&& isAuthorizedLateArrival == false
|
||||
&& isAuthorizedEarlyDeparture == false
|
||||
&& leaveRequest == null
|
||||
&& absences == null) {
|
||||
irregularAbsenceMonth = irregularAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||
} else if (isAuthorizedAbsence) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||
} else if (isAuthorizedLateArrival) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getLateArrival());
|
||||
} else if (isAuthorizedEarlyDeparture) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getEarlyDeparture());
|
||||
} else if (leaveRequest != null) {
|
||||
recuperationLeaveAbsenceMonth =
|
||||
recuperationLeaveAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||
} else if (absences != null) {
|
||||
for (Absence absence : absences) {
|
||||
totalAbsence = dailyReport.getAbsenceHours();
|
||||
switch (absence.getAbsenceType()) {
|
||||
case 0:
|
||||
breastfeedingAbsenceMonth = breastfeedingAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 1:
|
||||
recuperationLeaveAbsenceMonth = recuperationLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 2:
|
||||
breastfeedingAbsenceMonth = breastfeedingAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 3:
|
||||
trainingAbsenceMonth = trainingAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 4:
|
||||
missionAbsenceMonth = missionAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 5:
|
||||
hospitalizationAbsenceMonth = hospitalizationAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 6:
|
||||
sicknessAbsenceMonth = sicknessAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 7:
|
||||
workAccidentMonth = workAccidentMonth.add(totalAbsence);
|
||||
break;
|
||||
case 8:
|
||||
maternityMonth = maternityMonth.add(totalAbsence);
|
||||
break;
|
||||
case 9:
|
||||
authorizedUnpaidAbsenceMonth = authorizedUnpaidAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 10:
|
||||
annualLeaveAbsenceMonth = annualLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 11:
|
||||
unpaidLeaveAbsenceMonth = unpaidLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 12:
|
||||
statutoryLeaveAbsenceMonth = statutoryLeaveAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 13:
|
||||
resignationAbsenceMonth = resignationAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 14:
|
||||
contractEndAbsenceMonth = contractEndAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 15:
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 16:
|
||||
recruitmentAbsenceMonth = recruitmentAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 17:
|
||||
suspensionAbsenceMonth = suspensionAbsenceMonth.add(totalAbsence);
|
||||
break;
|
||||
case 18:
|
||||
militaryServiceAbsence = militaryServiceAbsence.add(totalAbsence);
|
||||
break;
|
||||
case 19:
|
||||
if (dailyReport.getIsAuthorizedAbsence()) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(totalAbsence);
|
||||
} else {
|
||||
irregularAbsenceMonth = irregularAbsenceMonth.add(totalAbsence);
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
if (dailyReport.getIsAuthorizedLateArrival()) {
|
||||
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getLateArrival());
|
||||
} else {
|
||||
irregularAbsenceMonth = irregularAbsenceMonth.add(dailyReport.getLateArrival());
|
||||
}
|
||||
break;
|
||||
case 21:
|
||||
if (dailyReport.getIsAuthorizedEarlyDeparture()) {
|
||||
justifiedAbsenceMonth =
|
||||
justifiedAbsenceMonth.add(dailyReport.getEarlyDeparture());
|
||||
} else {
|
||||
irregularAbsenceMonth =
|
||||
irregularAbsenceMonth.add(dailyReport.getEarlyDeparture());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Handle default case
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update or create MonthlyReport instance with calculated values
|
||||
monthlyReport.setPeriod(period);
|
||||
monthlyReport.setEmployee(employee);
|
||||
monthlyReport.setMonthlyAllowance(monthlyAllowance);
|
||||
monthlyReport.setMonthlyAllowanceRecall(monthlyAllowanceRecall);
|
||||
monthlyReport.setMonthlyNightHours(monthlyNightHours);
|
||||
monthlyReport.setMonthlyExtraHours50(monthlyExtraHours50);
|
||||
monthlyReport.setMonthlyExtraHours100(monthlyExtraHours100);
|
||||
monthlyReport.setExcessHours50(excessHours50);
|
||||
monthlyReport.setExcessHours100(excessHours100);
|
||||
|
||||
monthlyReport.setMonthlyITP(monthlyITP);
|
||||
monthlyReport.setTotalNuissance(totalNuissance);
|
||||
monthlyReport.setTotalWorkHours(totalWorkHours);
|
||||
|
||||
// Set total absence values for each specific type
|
||||
monthlyReport.setBreastfeedingAbsenceMonth(breastfeedingAbsenceMonth);
|
||||
monthlyReport.setAuthorizedPaidAbsenceMonth(authorizedPaidAbsenceMonth);
|
||||
monthlyReport.setAuthorizedUnpaidAbsenceMonth(authorizedUnpaidAbsenceMonth);
|
||||
monthlyReport.setAnnualLeaveAbsenceMonth(annualLeaveAbsenceMonth);
|
||||
monthlyReport.setRecuperationLeaveAbsenceMonth(recuperationLeaveAbsenceMonth);
|
||||
monthlyReport.setUnpaidLeaveAbsenceMonth(unpaidLeaveAbsenceMonth);
|
||||
monthlyReport.setStatutoryLeaveAbsenceMonth(statutoryLeaveAbsenceMonth);
|
||||
monthlyReport.setResignationAbsenceMonth(resignationAbsenceMonth);
|
||||
monthlyReport.setContractEndAbsenceMonth(contractEndAbsenceMonth);
|
||||
monthlyReport.setTrainingAbsenceMonth(trainingAbsenceMonth);
|
||||
monthlyReport.setHospitalizationAbsenceMonth(hospitalizationAbsenceMonth);
|
||||
monthlyReport.setMissionAbsenceMonth(missionAbsenceMonth);
|
||||
monthlyReport.setSicknessAbsenceMonth(sicknessAbsenceMonth);
|
||||
monthlyReport.setWorkAccidentMonth(workAccidentMonth);
|
||||
monthlyReport.setMaternityMonth(maternityMonth);
|
||||
monthlyReport.setJustifiedAbsenceMonth(justifiedAbsenceMonth);
|
||||
monthlyReport.setRecruitmentAbsenceMonth(recruitmentAbsenceMonth);
|
||||
monthlyReport.setSuspensionAbsenceMonth(suspensionAbsenceMonth);
|
||||
monthlyReport.setMilitaryServiceAbsence(militaryServiceAbsence);
|
||||
monthlyReport.setIrregularAbsenceMonth(irregularAbsenceMonth);
|
||||
|
||||
// Save the MonthlyReport instance
|
||||
monthlyReportRepository.save(monthlyReport);
|
||||
}
|
||||
|
||||
/*
|
||||
@Transactional
|
||||
public void calculePrimeAssiduite(MonthlyReport monthlyReport) {
|
||||
BigDecimal primeAssiduite = BigDecimal.ZERO;
|
||||
BigDecimal excessHours50 = MonthlyReport.getExcessHours50();
|
||||
BigDecimal excessHours100 = MonthlyReport.getExcessHours100();
|
||||
|
||||
// Calculate primeAssiduite using the provided formula
|
||||
BigDecimal salaireBase = monthlyReport.getEmployee().getSalaireBase();
|
||||
BigDecimal supHours50Bonus = excessHours50.multiply(salaireBase
|
||||
.multiply(new BigDecimal(1.5).setScale(2, RoundingMode.HALF_UP))
|
||||
.divide(new BigDecimal(176), 2, RoundingMode.HALF_UP)
|
||||
.setScale(2, RoundingMode.HALF_UP))
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
|
||||
BigDecimal supHours100Bonus = excessHours100.multiply(salaireBase
|
||||
.multiply(new BigDecimal(2).setScale(2, RoundingMode.HALF_UP))
|
||||
.divide(new BigDecimal(176), 2, RoundingMode.HALF_UP)
|
||||
.setScale(2, RoundingMode.HALF_UP))
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
|
||||
primeAssiduite = supHours50Bonus.add(supHours100Bonus);
|
||||
|
||||
monthlyReport.setPrimeAssiduite(primeAssiduite.setScale(2, RoundingMode.HALF_UP));
|
||||
// Save the MonthlyReport instance
|
||||
monthlyReportRepository.save(monthlyReport);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Period;
|
||||
import com.axelor.apps.base.db.repo.PeriodRepository;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.base.service.weeklyplanning.WeeklyPlanningService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmployeeBonusMgtLine;
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.ExtraHoursLine;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.LeaveRequest;
|
||||
import com.axelor.apps.hr.db.LunchVoucherMgtLine;
|
||||
import com.axelor.apps.hr.db.PayrollLeave;
|
||||
import com.axelor.apps.hr.db.PayrollPreparation;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeBonusMgtLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeBonusMgtRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExtraHoursLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveRequestRepository;
|
||||
import com.axelor.apps.hr.db.repo.LunchVoucherMgtLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.PayrollPreparationRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.apps.hr.service.leave.LeaveService;
|
||||
import com.axelor.apps.tool.file.CsvTool;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PayrollPreparationService {
|
||||
|
||||
protected LeaveService leaveService;
|
||||
protected LeaveRequestRepository leaveRequestRepo;
|
||||
protected WeeklyPlanningService weeklyPlanningService;
|
||||
|
||||
@Inject protected PayrollPreparationRepository payrollPreparationRepo;
|
||||
|
||||
@Inject protected AppBaseService appBaseService;
|
||||
|
||||
@Inject HRConfigService hrConfigService;
|
||||
|
||||
@Inject
|
||||
public PayrollPreparationService(
|
||||
LeaveService leaveService,
|
||||
LeaveRequestRepository leaveRequestRepo,
|
||||
WeeklyPlanningService weeklyPlanningService) {
|
||||
|
||||
this.leaveService = leaveService;
|
||||
this.leaveRequestRepo = leaveRequestRepo;
|
||||
this.weeklyPlanningService = weeklyPlanningService;
|
||||
}
|
||||
|
||||
public PayrollPreparation generateFromEmploymentContract(
|
||||
PayrollPreparation payrollPreparation, EmploymentContract employmentContract) {
|
||||
if (payrollPreparation.getEmployee() == null) {
|
||||
payrollPreparation.setEmployee(employmentContract.getEmployee());
|
||||
}
|
||||
if (payrollPreparation.getCompany() == null) {
|
||||
payrollPreparation.setCompany(employmentContract.getPayCompany());
|
||||
}
|
||||
if (payrollPreparation.getEmploymentContract() == null) {
|
||||
payrollPreparation.setEmploymentContract(employmentContract);
|
||||
}
|
||||
|
||||
payrollPreparation.setOtherCostsEmployeeSet(employmentContract.getOtherCostsEmployeeSet());
|
||||
payrollPreparation.setAnnualGrossSalary(employmentContract.getAnnualGrossSalary());
|
||||
return payrollPreparation;
|
||||
}
|
||||
|
||||
public List<PayrollLeave> fillInPayrollPreparation(PayrollPreparation payrollPreparation)
|
||||
throws AxelorException {
|
||||
|
||||
List<PayrollLeave> payrollLeaveList = fillInLeaves(payrollPreparation);
|
||||
|
||||
payrollPreparation.setDuration(
|
||||
this.computeWorkingDaysNumber(payrollPreparation, payrollLeaveList));
|
||||
|
||||
payrollPreparation.setExpenseAmount(this.computeExpenseAmount(payrollPreparation));
|
||||
payrollPreparation.setLunchVoucherNumber(this.computeLunchVoucherNumber(payrollPreparation));
|
||||
payrollPreparation.setEmployeeBonusAmount(computeEmployeeBonusAmount(payrollPreparation));
|
||||
payrollPreparation.setExtraHoursNumber(computeExtraHoursNumber(payrollPreparation));
|
||||
|
||||
return payrollLeaveList;
|
||||
}
|
||||
|
||||
public List<PayrollLeave> fillInLeaves(PayrollPreparation payrollPreparation)
|
||||
throws AxelorException {
|
||||
|
||||
List<PayrollLeave> payrollLeaveList = new ArrayList<>();
|
||||
LocalDate fromDate = payrollPreparation.getPeriod().getFromDate();
|
||||
LocalDate toDate = payrollPreparation.getPeriod().getToDate();
|
||||
Employee employee = payrollPreparation.getEmployee();
|
||||
|
||||
if (employee.getWeeklyPlanning() == null) {
|
||||
throw new AxelorException(
|
||||
payrollPreparation,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_PLANNING),
|
||||
employee.getName());
|
||||
}
|
||||
|
||||
List<LeaveRequest> leaveRequestList =
|
||||
leaveRequestRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.statusSelect = ?4 AND self.user.employee = ?3 AND ((self.fromDateT BETWEEN ?2 AND ?1 OR self.toDateT BETWEEN ?2 AND ?1) OR (?1 BETWEEN self.fromDateT AND self.toDateT OR ?2 BETWEEN self.fromDateT AND self.toDateT))",
|
||||
toDate,
|
||||
fromDate,
|
||||
employee,
|
||||
LeaveRequestRepository.STATUS_VALIDATED)
|
||||
.fetch();
|
||||
|
||||
for (LeaveRequest leaveRequest : leaveRequestList) {
|
||||
|
||||
PayrollLeave payrollLeave = new PayrollLeave();
|
||||
|
||||
if (leaveRequest.getFromDateT().toLocalDate().isBefore(fromDate)) {
|
||||
payrollLeave.setFromDate(fromDate);
|
||||
} else {
|
||||
payrollLeave.setFromDate(leaveRequest.getFromDateT().toLocalDate());
|
||||
}
|
||||
|
||||
if (leaveRequest.getToDateT().toLocalDate().isAfter(toDate)) {
|
||||
payrollLeave.setToDate(toDate);
|
||||
} else {
|
||||
payrollLeave.setToDate(leaveRequest.getToDateT().toLocalDate());
|
||||
}
|
||||
|
||||
payrollLeave.setDuration(
|
||||
leaveService.computeLeaveDaysByLeaveRequest(fromDate, toDate, leaveRequest, employee));
|
||||
payrollLeave.setLeaveReason(leaveRequest.getLeaveLine().getLeaveReason());
|
||||
payrollLeave.setLeaveRequest(leaveRequest);
|
||||
payrollLeaveList.add(payrollLeave);
|
||||
}
|
||||
return payrollLeaveList;
|
||||
}
|
||||
|
||||
public BigDecimal computeWorkingDaysNumber(
|
||||
PayrollPreparation payrollPreparation, List<PayrollLeave> payrollLeaveList) {
|
||||
LocalDate fromDate = payrollPreparation.getPeriod().getFromDate();
|
||||
LocalDate toDate = payrollPreparation.getPeriod().getToDate();
|
||||
LocalDate itDate = LocalDate.parse(fromDate.toString(), DateTimeFormatter.ISO_DATE);
|
||||
BigDecimal workingDays = BigDecimal.ZERO;
|
||||
BigDecimal leaveDays = BigDecimal.ZERO;
|
||||
while (!itDate.isAfter(toDate)) {
|
||||
workingDays =
|
||||
workingDays.add(
|
||||
BigDecimal.valueOf(
|
||||
weeklyPlanningService.getWorkingDayValueInDays(
|
||||
payrollPreparation.getEmployee().getWeeklyPlanning(), itDate)));
|
||||
itDate = itDate.plusDays(1);
|
||||
}
|
||||
if (payrollLeaveList != null) {
|
||||
for (PayrollLeave payrollLeave : payrollLeaveList) {
|
||||
workingDays = workingDays.subtract(payrollLeave.getDuration());
|
||||
leaveDays = leaveDays.add(payrollLeave.getDuration());
|
||||
}
|
||||
}
|
||||
payrollPreparation.setLeaveDuration(leaveDays);
|
||||
return workingDays;
|
||||
}
|
||||
|
||||
public BigDecimal computeExtraHoursNumber(PayrollPreparation payrollPreparation) {
|
||||
LocalDate fromDate = payrollPreparation.getPeriod().getFromDate();
|
||||
LocalDate toDate = payrollPreparation.getPeriod().getToDate();
|
||||
BigDecimal extraHoursNumber = BigDecimal.ZERO;
|
||||
for (ExtraHoursLine extraHoursLine :
|
||||
Beans.get(ExtraHoursLineRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.user.employee = ?1 AND self.extraHours.statusSelect = 3 AND self.date BETWEEN ?2 AND ?3 AND (self.payrollPreparation = null OR self.payrollPreparation.id = ?4)",
|
||||
payrollPreparation.getEmployee(),
|
||||
fromDate,
|
||||
toDate,
|
||||
payrollPreparation.getId())
|
||||
.fetch()) {
|
||||
payrollPreparation.addExtraHoursLineListItem(extraHoursLine);
|
||||
extraHoursNumber = extraHoursNumber.add(extraHoursLine.getQty());
|
||||
}
|
||||
return extraHoursNumber;
|
||||
}
|
||||
|
||||
public BigDecimal computeExpenseAmount(PayrollPreparation payrollPreparation) {
|
||||
BigDecimal expenseAmount = BigDecimal.ZERO;
|
||||
List<Expense> expenseList =
|
||||
Beans.get(ExpenseRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.user.employee = ?1 "
|
||||
+ "AND self.statusSelect = ?2 "
|
||||
+ "AND (self.payrollPreparation IS NULL OR self.payrollPreparation.id = ?3) "
|
||||
+ "AND self.companyCbSelect = ?4 "
|
||||
+ "AND self.validationDate BETWEEN ?5 AND ?6",
|
||||
payrollPreparation.getEmployee(),
|
||||
ExpenseRepository.STATUS_VALIDATED,
|
||||
payrollPreparation.getId(),
|
||||
ExpenseRepository.COMPANY_CB_PAYMENT_NO,
|
||||
payrollPreparation.getPeriod().getFromDate(),
|
||||
payrollPreparation.getPeriod().getToDate())
|
||||
.fetch();
|
||||
for (Expense expense : expenseList) {
|
||||
expenseAmount = expenseAmount.add(expense.getInTaxTotal());
|
||||
payrollPreparation.addExpenseListItem(expense);
|
||||
}
|
||||
return expenseAmount;
|
||||
}
|
||||
|
||||
public BigDecimal computeLunchVoucherNumber(PayrollPreparation payrollPreparation) {
|
||||
BigDecimal lunchVoucherNumber = BigDecimal.ZERO;
|
||||
List<LunchVoucherMgtLine> lunchVoucherList =
|
||||
Beans.get(LunchVoucherMgtLineRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee = ?1 AND self.lunchVoucherMgt.statusSelect = 3 AND (self.payrollPreparation = null OR self.payrollPreparation.id = ?2) AND self.lunchVoucherMgt.payPeriod = ?3",
|
||||
payrollPreparation.getEmployee(),
|
||||
payrollPreparation.getId(),
|
||||
payrollPreparation.getPeriod())
|
||||
.fetch();
|
||||
for (LunchVoucherMgtLine lunchVoucherMgtLine : lunchVoucherList) {
|
||||
lunchVoucherNumber =
|
||||
lunchVoucherNumber.add(new BigDecimal(lunchVoucherMgtLine.getLunchVoucherNumber()));
|
||||
lunchVoucherNumber =
|
||||
lunchVoucherNumber.add(new BigDecimal(lunchVoucherMgtLine.getInAdvanceNbr()));
|
||||
payrollPreparation.addLunchVoucherMgtLineListItem(lunchVoucherMgtLine);
|
||||
}
|
||||
return lunchVoucherNumber;
|
||||
}
|
||||
|
||||
public BigDecimal computeEmployeeBonusAmount(PayrollPreparation payrollPreparation) {
|
||||
BigDecimal employeeBonusAmount = BigDecimal.ZERO;
|
||||
List<EmployeeBonusMgtLine> employeeBonusList =
|
||||
Beans.get(EmployeeBonusMgtLineRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee = ?1"
|
||||
+ " AND self.employeeBonusMgt.statusSelect = ?4"
|
||||
+ " AND (self.payrollPreparation = null"
|
||||
+ " OR self.payrollPreparation.id = ?2)"
|
||||
+ " AND self.employeeBonusMgt.payPeriod = ?3",
|
||||
payrollPreparation.getEmployee(),
|
||||
payrollPreparation.getId(),
|
||||
payrollPreparation.getPeriod(),
|
||||
EmployeeBonusMgtRepository.STATUS_CALCULATED)
|
||||
.fetch();
|
||||
for (EmployeeBonusMgtLine employeeBonusMgtLine : employeeBonusList) {
|
||||
payrollPreparation.addEmployeeBonusMgtLineListItem(employeeBonusMgtLine);
|
||||
employeeBonusAmount = employeeBonusAmount.add(employeeBonusMgtLine.getAmount());
|
||||
}
|
||||
return employeeBonusAmount;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public String exportSinglePayrollPreparation(PayrollPreparation payrollPreparation)
|
||||
throws IOException {
|
||||
|
||||
List<String[]> list = new ArrayList<>();
|
||||
|
||||
String[] item = new String[5];
|
||||
item[0] = payrollPreparation.getEmployee().getName();
|
||||
item[1] = payrollPreparation.getDuration().toString();
|
||||
item[2] = payrollPreparation.getLunchVoucherNumber().toString();
|
||||
item[3] = payrollPreparation.getEmployeeBonusAmount().toString();
|
||||
item[4] = payrollPreparation.getExtraHoursNumber().toString();
|
||||
list.add(item);
|
||||
|
||||
String fileName = this.getPayrollPreparationExportName();
|
||||
String filePath = AppSettings.get().get("file.upload.dir");
|
||||
|
||||
new File(filePath).mkdirs();
|
||||
CsvTool.csvWriter(filePath, fileName, ';', getPayrollPreparationExportHeader(), list);
|
||||
|
||||
payrollPreparation.setExported(true);
|
||||
payrollPreparation.setExportDate(Beans.get(AppBaseService.class).getTodayDate());
|
||||
|
||||
payrollPreparationRepo.save(payrollPreparation);
|
||||
|
||||
Path path = Paths.get(filePath + System.getProperty("file.separator") + fileName);
|
||||
|
||||
try (InputStream is = new FileInputStream(path.toFile())) {
|
||||
Beans.get(MetaFiles.class).attach(is, fileName, payrollPreparation);
|
||||
}
|
||||
|
||||
return filePath + System.getProperty("file.separator") + fileName;
|
||||
}
|
||||
|
||||
public String[] createExportFileLine(PayrollPreparation payrollPreparation) {
|
||||
|
||||
String[] item = new String[7];
|
||||
item[0] = payrollPreparation.getEmployee().getExportCode();
|
||||
item[1] = payrollPreparation.getEmployee().getContactPartner().getName();
|
||||
item[2] = payrollPreparation.getEmployee().getContactPartner().getFirstName();
|
||||
return item;
|
||||
}
|
||||
|
||||
public String exportNibelisPayrollPreparation(PayrollPreparation payrollPreparation)
|
||||
throws AxelorException, IOException {
|
||||
|
||||
List<String[]> list = new ArrayList<>();
|
||||
|
||||
exportNibelis(payrollPreparation, list);
|
||||
|
||||
String fileName = this.getPayrollPreparationExportName();
|
||||
String filePath = AppSettings.get().get("file.upload.dir");
|
||||
new File(filePath).mkdirs();
|
||||
|
||||
CsvTool.csvWriter(
|
||||
filePath, fileName, ';', getPayrollPreparationMeilleurGestionExportHeader(), list);
|
||||
|
||||
Path path = Paths.get(filePath + System.getProperty("file.separator") + fileName);
|
||||
|
||||
try (InputStream is = new FileInputStream(path.toFile())) {
|
||||
Beans.get(MetaFiles.class).attach(is, fileName, payrollPreparation);
|
||||
}
|
||||
|
||||
return filePath + System.getProperty("file.separator") + fileName;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void exportNibelis(PayrollPreparation payrollPreparation, List<String[]> list)
|
||||
throws AxelorException {
|
||||
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(payrollPreparation.getCompany());
|
||||
|
||||
// LEAVES
|
||||
if (payrollPreparation.getLeaveDuration().compareTo(BigDecimal.ZERO) > 0) {
|
||||
List<PayrollLeave> payrollLeaveList = fillInLeaves(payrollPreparation);
|
||||
for (PayrollLeave payrollLeave : payrollLeaveList) {
|
||||
if (payrollLeave.getLeaveReason().getPayrollPreprationExport()) {
|
||||
String[] leaveLine = createExportFileLine(payrollPreparation);
|
||||
leaveLine[3] = payrollLeave.getLeaveReason().getExportCode();
|
||||
leaveLine[4] =
|
||||
payrollLeave.getFromDate().format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
leaveLine[5] = payrollLeave.getToDate().format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
leaveLine[6] = payrollLeave.getDuration().toString();
|
||||
list.add(leaveLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LUNCH VOUCHER MANAGEMENT
|
||||
if (payrollPreparation.getLunchVoucherNumber().compareTo(BigDecimal.ZERO) > 0) {
|
||||
String[] lunchVoucherLine = createExportFileLine(payrollPreparation);
|
||||
lunchVoucherLine[3] = hrConfig.getExportCodeForLunchVoucherManagement();
|
||||
lunchVoucherLine[6] = payrollPreparation.getLunchVoucherNumber().toString();
|
||||
list.add(lunchVoucherLine);
|
||||
}
|
||||
|
||||
// EMPLOYEE BONUS MANAGEMENT
|
||||
if (payrollPreparation.getEmployeeBonusAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
Map<String, BigDecimal> map = new HashMap<>();
|
||||
for (EmployeeBonusMgtLine bonus : payrollPreparation.getEmployeeBonusMgtLineList()) {
|
||||
if (bonus.getEmployeeBonusMgt().getEmployeeBonusType().getPayrollPreparationExport()) {
|
||||
if (map.containsKey(bonus.getEmployeeBonusMgt().getEmployeeBonusType().getExportCode())) {
|
||||
map.put(
|
||||
bonus.getEmployeeBonusMgt().getEmployeeBonusType().getExportCode(),
|
||||
bonus
|
||||
.getAmount()
|
||||
.add(
|
||||
map.get(
|
||||
bonus.getEmployeeBonusMgt().getEmployeeBonusType().getExportCode())));
|
||||
} else {
|
||||
map.put(
|
||||
bonus.getEmployeeBonusMgt().getEmployeeBonusType().getExportCode(),
|
||||
bonus.getAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, BigDecimal> entry : map.entrySet()) {
|
||||
String[] employeeBonusLine = createExportFileLine(payrollPreparation);
|
||||
employeeBonusLine[3] = entry.getKey();
|
||||
employeeBonusLine[6] = entry.getValue().toString();
|
||||
list.add(employeeBonusLine);
|
||||
}
|
||||
}
|
||||
|
||||
// EXTRA HOURS
|
||||
if (payrollPreparation.getExtraHoursNumber().compareTo(BigDecimal.ZERO) > 0) {
|
||||
String[] extraHourLine = createExportFileLine(payrollPreparation);
|
||||
extraHourLine[3] = hrConfig.getExportCodeForLunchVoucherManagement();
|
||||
extraHourLine[6] = payrollPreparation.getExtraHoursNumber().toString();
|
||||
list.add(extraHourLine);
|
||||
}
|
||||
|
||||
payrollPreparation.setExported(true);
|
||||
payrollPreparation.setExportDate(appBaseService.getTodayDate());
|
||||
payrollPreparation.setExportTypeSelect(HrBatchRepository.EXPORT_TYPE_NIBELIS);
|
||||
payrollPreparationRepo.save(payrollPreparation);
|
||||
}
|
||||
|
||||
public String getPayrollPreparationExportName() {
|
||||
return I18n.get("Payroll preparation")
|
||||
+ " - "
|
||||
+ Beans.get(AppBaseService.class).getTodayDateTime().toLocalDateTime().toString()
|
||||
+ ".csv";
|
||||
}
|
||||
|
||||
public String[] getPayrollPreparationExportHeader() {
|
||||
|
||||
String[] headers = new String[5];
|
||||
headers[0] = I18n.get("Employee");
|
||||
headers[1] = I18n.get("Working days' number");
|
||||
headers[2] = I18n.get("Lunch vouchers' number");
|
||||
headers[3] = I18n.get("Employee bonus amount");
|
||||
headers[4] = I18n.get("Extra hours' number");
|
||||
return headers;
|
||||
}
|
||||
|
||||
public String[] getPayrollPreparationMeilleurGestionExportHeader() {
|
||||
String[] headers = new String[7];
|
||||
headers[0] = I18n.get("Registration number");
|
||||
headers[1] = I18n.get("Employee lastname");
|
||||
headers[2] = I18n.get("Employee firstname");
|
||||
headers[3] = I18n.get("Code");
|
||||
headers[4] = I18n.get("Start date");
|
||||
headers[5] = I18n.get("End date");
|
||||
headers[6] = I18n.get("Value");
|
||||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* If each employee's payroll preparation has been exported, close the pay period.
|
||||
*
|
||||
* @param payrollPreparation
|
||||
*/
|
||||
@Transactional
|
||||
public void closePayPeriodIfExported(PayrollPreparation payrollPreparation) {
|
||||
Company company = payrollPreparation.getCompany();
|
||||
Period payPeriod = payrollPreparation.getPeriod();
|
||||
|
||||
long nbNotExportedPayroll =
|
||||
Beans.get(PayrollPreparationRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.company = :_company AND self.exported = false "
|
||||
+ "AND self.period = :_period")
|
||||
.bind("_company", company)
|
||||
.bind("_period", payPeriod)
|
||||
.count();
|
||||
|
||||
if (nbNotExportedPayroll == 0) {
|
||||
payPeriod.setStatusSelect(PeriodRepository.STATUS_CLOSED);
|
||||
payPeriod.setClosureDateTime(
|
||||
Beans.get(AppBaseService.class).getTodayDateTime().toLocalDateTime());
|
||||
}
|
||||
Beans.get(PeriodRepository.class).save(payPeriod);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.app;
|
||||
|
||||
import com.axelor.apps.base.db.AppExpense;
|
||||
import com.axelor.apps.base.db.AppLeave;
|
||||
import com.axelor.apps.base.db.AppTimesheet;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
|
||||
public interface AppHumanResourceService extends AppBaseService {
|
||||
|
||||
public AppTimesheet getAppTimesheet();
|
||||
|
||||
public AppLeave getAppLeave();
|
||||
|
||||
public AppExpense getAppExpense();
|
||||
|
||||
public void getHrmAppSettings(ActionRequest request, ActionResponse response);
|
||||
|
||||
public void generateHrConfigurations();
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.app;
|
||||
|
||||
import com.axelor.apps.base.db.AppExpense;
|
||||
import com.axelor.apps.base.db.AppLeave;
|
||||
import com.axelor.apps.base.db.AppTimesheet;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.repo.AppExpenseRepository;
|
||||
import com.axelor.apps.base.db.repo.AppLeaveRepository;
|
||||
import com.axelor.apps.base.db.repo.AppTimesheetRepository;
|
||||
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||
import com.axelor.apps.base.service.app.AppBaseServiceImpl;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.repo.HRConfigRepository;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Singleton
|
||||
public class AppHumanResourceServiceImpl extends AppBaseServiceImpl
|
||||
implements AppHumanResourceService {
|
||||
|
||||
private AppTimesheetRepository appTimesheetRepo;
|
||||
private AppLeaveRepository appLeaveRepo;
|
||||
private AppExpenseRepository appExpenseRepo;
|
||||
|
||||
@Inject private CompanyRepository companyRepo;
|
||||
|
||||
@Inject private HRConfigRepository hrConfigRepo;
|
||||
|
||||
@Inject
|
||||
public AppHumanResourceServiceImpl(
|
||||
AppTimesheetRepository appTimesheetRepo,
|
||||
AppLeaveRepository appLeaveRepo,
|
||||
AppExpenseRepository appExpense) {
|
||||
this.appTimesheetRepo = appTimesheetRepo;
|
||||
this.appLeaveRepo = appLeaveRepo;
|
||||
this.appExpenseRepo = appExpense;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppTimesheet getAppTimesheet() {
|
||||
return appTimesheetRepo.all().fetchOne();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppLeave getAppLeave() {
|
||||
return appLeaveRepo.all().fetchOne();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppExpense getAppExpense() {
|
||||
return appExpenseRepo.all().fetchOne();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getHrmAppSettings(ActionRequest request, ActionResponse response) {
|
||||
|
||||
try {
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
map.put("hasInvoicingAppEnable", isApp("invoice"));
|
||||
map.put("hasLeaveAppEnable", isApp("leave"));
|
||||
map.put("hasExpenseAppEnable", isApp("expense"));
|
||||
map.put("hasTimesheetAppEnable", isApp("timesheet"));
|
||||
map.put("hasProjectAppEnable", isApp("project"));
|
||||
|
||||
response.setData(map);
|
||||
response.setTotal(map.size());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
response.setException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void generateHrConfigurations() {
|
||||
|
||||
List<Company> companies = companyRepo.all().filter("self.hrConfig is null").fetch();
|
||||
|
||||
for (Company company : companies) {
|
||||
HRConfig hrConfig = new HRConfig();
|
||||
hrConfig.setCompany(company);
|
||||
hrConfigRepo.save(hrConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.PaymentMode;
|
||||
import com.axelor.apps.account.service.invoice.InvoiceService;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderCreateService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderLineService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderService;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BankOrderCreateServiceHr extends BankOrderCreateService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Inject
|
||||
public BankOrderCreateServiceHr(
|
||||
BankOrderRepository bankOrderRepo,
|
||||
BankOrderService bankOrderService,
|
||||
BankOrderLineService bankOrderLineService,
|
||||
InvoiceService invoiceService) {
|
||||
super(bankOrderRepo, bankOrderService, bankOrderLineService, invoiceService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a bank order for an expense
|
||||
*
|
||||
* @param expense An expense
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public BankOrder createBankOrder(Expense expense, BankDetails bankDetails)
|
||||
throws AxelorException {
|
||||
Company company = expense.getCompany();
|
||||
Partner partner = expense.getUser().getPartner();
|
||||
PaymentMode paymentMode = expense.getPaymentMode();
|
||||
BigDecimal amount =
|
||||
expense
|
||||
.getInTaxTotal()
|
||||
.subtract(expense.getAdvanceAmount())
|
||||
.subtract(expense.getWithdrawnCash())
|
||||
.subtract(expense.getPersonalExpenseAmount());
|
||||
Currency currency = company.getCurrency();
|
||||
LocalDate paymentDate = Beans.get(AppBaseService.class).getTodayDate();
|
||||
|
||||
BankOrder bankOrder =
|
||||
super.createBankOrder(
|
||||
paymentMode,
|
||||
BankOrderRepository.PARTNER_TYPE_EMPLOYEE,
|
||||
paymentDate,
|
||||
company,
|
||||
bankDetails,
|
||||
currency,
|
||||
expense.getFullName(),
|
||||
expense.getFullName(),
|
||||
BankOrderRepository.TECHNICAL_ORIGIN_AUTOMATIC);
|
||||
|
||||
bankOrder.addBankOrderLineListItem(
|
||||
bankOrderLineService.createBankOrderLine(
|
||||
paymentMode.getBankOrderFileFormat(),
|
||||
partner,
|
||||
amount,
|
||||
currency,
|
||||
paymentDate,
|
||||
expense.getExpenseSeq(),
|
||||
expense.getFullName(),
|
||||
expense));
|
||||
bankOrder = bankOrderRepo.save(bankOrder);
|
||||
|
||||
return bankOrder;
|
||||
}
|
||||
|
||||
public BankOrder createBankOrder(Expense expense) throws AxelorException {
|
||||
return createBankOrder(expense, expense.getCompany().getDefaultBankDetails());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.bankorder;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderLineOriginRepository;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderLineOriginServiceImpl;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.db.Model;
|
||||
import com.google.inject.Inject;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class BankOrderLineOriginServiceHRImpl extends BankOrderLineOriginServiceImpl {
|
||||
|
||||
@Inject
|
||||
public BankOrderLineOriginServiceHRImpl(
|
||||
BankOrderLineOriginRepository bankOrderLineOriginRepository) {
|
||||
super(bankOrderLineOriginRepository);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String computeRelatedToSelectName(Model model) {
|
||||
|
||||
if (model instanceof Expense) {
|
||||
|
||||
return ((Expense) model).getExpenseSeq();
|
||||
|
||||
} else {
|
||||
|
||||
return super.computeRelatedToSelectName(model);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalDate computeRelatedToSelectDate(Model model) {
|
||||
|
||||
if (model instanceof Expense) {
|
||||
|
||||
return ((Expense) model).getValidationDate();
|
||||
|
||||
} else {
|
||||
|
||||
return super.computeRelatedToSelectDate(model);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalDate computeRelatedToSelectDueDate(Model model) {
|
||||
|
||||
if (model instanceof Expense) {
|
||||
|
||||
return ((Expense) model).getValidationDate();
|
||||
|
||||
} else {
|
||||
|
||||
return super.computeRelatedToSelectDueDate(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
|
||||
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
||||
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderMergeServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderService;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseHRRepository;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BankOrderMergeHRServiceImpl extends BankOrderMergeServiceImpl {
|
||||
|
||||
protected ExpenseHRRepository expenseHRRepository;
|
||||
|
||||
@Inject
|
||||
public BankOrderMergeHRServiceImpl(
|
||||
BankOrderRepository bankOrderRepo,
|
||||
InvoicePaymentRepository invoicePaymentRepo,
|
||||
BankOrderService bankOrderService,
|
||||
InvoiceRepository invoiceRepository,
|
||||
PaymentScheduleLineRepository paymentScheduleLineRepository,
|
||||
ExpenseHRRepository expenseHRRepository) {
|
||||
super(
|
||||
bankOrderRepo,
|
||||
invoicePaymentRepo,
|
||||
bankOrderService,
|
||||
invoiceRepository,
|
||||
paymentScheduleLineRepository);
|
||||
this.expenseHRRepository = expenseHRRepository;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {AxelorException.class, Exception.class})
|
||||
@Override
|
||||
public BankOrder mergeBankOrders(Collection<BankOrder> bankOrders) throws AxelorException {
|
||||
List<Expense> expenseList =
|
||||
expenseHRRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.bankOrder.id IN (?)",
|
||||
bankOrders.stream().map(BankOrder::getId).collect(Collectors.toList()))
|
||||
.fetch();
|
||||
|
||||
for (Expense expense : expenseList) {
|
||||
expense.setBankOrder(null);
|
||||
expenseHRRepository.save(expense);
|
||||
}
|
||||
|
||||
BankOrder bankOrder = super.mergeBankOrders(bankOrders);
|
||||
|
||||
for (Expense expense : expenseList) {
|
||||
expense.setBankOrder(bankOrder);
|
||||
expenseHRRepository.save(expense);
|
||||
}
|
||||
|
||||
return bankOrder;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
|
||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelService;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderLineOriginService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderLineService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.config.BankPaymentConfigService;
|
||||
import com.axelor.apps.base.service.administration.SequenceService;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseRepository;
|
||||
import com.axelor.apps.hr.service.expense.ExpenseService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
public class BankOrderServiceHRImpl extends BankOrderServiceImpl {
|
||||
|
||||
protected ExpenseService expenseService;
|
||||
|
||||
@Inject
|
||||
public BankOrderServiceHRImpl(
|
||||
BankOrderRepository bankOrderRepo,
|
||||
InvoicePaymentRepository invoicePaymentRepo,
|
||||
BankOrderLineService bankOrderLineService,
|
||||
EbicsService ebicsService,
|
||||
InvoicePaymentCancelService invoicePaymentCancelService,
|
||||
BankPaymentConfigService bankPaymentConfigService,
|
||||
SequenceService sequenceService,
|
||||
BankOrderLineOriginService bankOrderLineOriginService,
|
||||
ExpenseService expenseService) {
|
||||
super(
|
||||
bankOrderRepo,
|
||||
invoicePaymentRepo,
|
||||
bankOrderLineService,
|
||||
ebicsService,
|
||||
invoicePaymentCancelService,
|
||||
bankPaymentConfigService,
|
||||
sequenceService,
|
||||
bankOrderLineOriginService);
|
||||
this.expenseService = expenseService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validatePayment(BankOrder bankOrder) throws AxelorException {
|
||||
super.validatePayment(bankOrder);
|
||||
List<Expense> expenseList =
|
||||
Beans.get(ExpenseRepository.class)
|
||||
.all()
|
||||
.filter("self.bankOrder.id = ?", bankOrder.getId())
|
||||
.fetch();
|
||||
for (Expense expense : expenseList) {
|
||||
if (expense != null && expense.getStatusSelect() != ExpenseRepository.STATUS_REIMBURSED) {
|
||||
expense.setStatusSelect(ExpenseRepository.STATUS_REIMBURSED);
|
||||
expense.setPaymentStatusSelect(InvoicePaymentRepository.STATUS_VALIDATED);
|
||||
expenseService.createMoveForExpensePayment(expense);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancelPayment(BankOrder bankOrder) throws AxelorException {
|
||||
super.cancelPayment(bankOrder);
|
||||
List<Expense> expenseList =
|
||||
Beans.get(ExpenseRepository.class)
|
||||
.all()
|
||||
.filter("self.bankOrder.id = ?", bankOrder.getId())
|
||||
.fetch();
|
||||
for (Expense expense : expenseList) {
|
||||
if (expense != null
|
||||
&& expense.getPaymentStatusSelect() != InvoicePaymentRepository.STATUS_CANCELED) {
|
||||
expenseService.cancelPayment(expense);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.account.db.AccountingBatch;
|
||||
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
|
||||
import com.axelor.apps.account.exception.IExceptionMessage;
|
||||
import com.axelor.apps.account.service.app.AppAccountService;
|
||||
import com.axelor.apps.account.service.batch.BatchCreditTransferExpensePayment;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderMergeService;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseRepository;
|
||||
import com.axelor.apps.hr.service.expense.ExpenseService;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.db.Query;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.ExceptionOriginRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BatchCreditTransferExpensePaymentHR extends BatchCreditTransferExpensePayment {
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
protected final AppAccountService appAccountService;
|
||||
protected final ExpenseRepository expenseRepo;
|
||||
protected final ExpenseService expenseService;
|
||||
protected final BankOrderMergeService bankOrderMergeService;
|
||||
|
||||
@Inject
|
||||
public BatchCreditTransferExpensePaymentHR(
|
||||
AppAccountService appAccountService,
|
||||
ExpenseRepository expenseRepo,
|
||||
ExpenseService expenseService,
|
||||
BankOrderMergeService bankOrderMergeService) {
|
||||
this.appAccountService = appAccountService;
|
||||
this.expenseRepo = expenseRepo;
|
||||
this.expenseService = expenseService;
|
||||
this.bankOrderMergeService = bankOrderMergeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
List<Expense> doneList = processExpenses();
|
||||
|
||||
try {
|
||||
mergeBankOrders(doneList);
|
||||
} catch (Exception ex) {
|
||||
TraceBackService.trace(ex);
|
||||
ex.printStackTrace();
|
||||
log.error("Credit transfer batch for expense payments: mergeBankOrders");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(I18n.get(IExceptionMessage.BATCH_CREDIT_TRANSFER_REPORT_TITLE)).append(" ");
|
||||
sb.append(
|
||||
String.format(
|
||||
I18n.get(
|
||||
com.axelor.apps.hr.exception.IExceptionMessage
|
||||
.BATCH_CREDIT_TRANSFER_EXPENSE_DONE_SINGULAR,
|
||||
com.axelor.apps.hr.exception.IExceptionMessage
|
||||
.BATCH_CREDIT_TRANSFER_EXPENSE_DONE_PLURAL,
|
||||
batch.getDone())
|
||||
+ " ",
|
||||
batch.getDone()));
|
||||
sb.append(
|
||||
String.format(
|
||||
I18n.get(
|
||||
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_SINGULAR,
|
||||
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_PLURAL,
|
||||
batch.getAnomaly()),
|
||||
batch.getAnomaly()));
|
||||
addComment(sb.toString());
|
||||
super.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process expenses that need to be paid.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected List<Expense> processExpenses() {
|
||||
List<Expense> doneList = new ArrayList<>();
|
||||
List<Long> anomalyList = Lists.newArrayList(0L); // Can't pass an empty collection to the query
|
||||
AccountingBatch accountingBatch = batch.getAccountingBatch();
|
||||
boolean manageMultiBanks = appAccountService.getAppBase().getManageMultiBanks();
|
||||
String filter =
|
||||
"self.ventilated = true "
|
||||
+ "AND self.paymentStatusSelect = :paymentStatusSelect "
|
||||
+ "AND self.company = :company "
|
||||
+ "AND self.user.partner.outPaymentMode = :paymentMode "
|
||||
+ "AND self.id NOT IN (:anomalyList)";
|
||||
|
||||
if (manageMultiBanks) {
|
||||
filter += " AND self.bankDetails IN (:bankDetailsSet)";
|
||||
}
|
||||
|
||||
Query<Expense> query =
|
||||
expenseRepo
|
||||
.all()
|
||||
.filter(filter)
|
||||
.bind("paymentStatusSelect", InvoicePaymentRepository.STATUS_DRAFT)
|
||||
.bind("company", accountingBatch.getCompany())
|
||||
.bind("paymentMode", accountingBatch.getPaymentMode())
|
||||
.bind("anomalyList", anomalyList);
|
||||
|
||||
if (manageMultiBanks) {
|
||||
Set<BankDetails> bankDetailsSet = Sets.newHashSet(accountingBatch.getBankDetails());
|
||||
|
||||
if (accountingBatch.getIncludeOtherBankAccounts()) {
|
||||
bankDetailsSet.addAll(accountingBatch.getCompany().getBankDetailsSet());
|
||||
}
|
||||
|
||||
query.bind("bankDetailsSet", bankDetailsSet);
|
||||
}
|
||||
|
||||
for (List<Expense> expenseList;
|
||||
!(expenseList = query.fetch(FETCH_LIMIT)).isEmpty();
|
||||
JPA.clear()) {
|
||||
for (Expense expense : expenseList) {
|
||||
try {
|
||||
addPayment(expense, accountingBatch.getBankDetails());
|
||||
doneList.add(expense);
|
||||
incrementDone();
|
||||
} catch (Exception ex) {
|
||||
incrementAnomaly();
|
||||
anomalyList.add(expense.getId());
|
||||
query.bind("anomalyList", anomalyList);
|
||||
TraceBackService.trace(ex, ExceptionOriginRepository.CREDIT_TRANSFER, batch.getId());
|
||||
ex.printStackTrace();
|
||||
log.error(
|
||||
String.format(
|
||||
"Credit transfer batch for expense payment: anomaly for expense %s",
|
||||
expense.getExpenseSeq()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return doneList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a payment to the specified expense.
|
||||
*
|
||||
* @param expense
|
||||
* @param bankDetails
|
||||
* @throws AxelorException
|
||||
*/
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
protected void addPayment(Expense expense, BankDetails bankDetails) throws AxelorException {
|
||||
log.debug(
|
||||
String.format(
|
||||
"Credit transfer batch for expense payment: adding payment for expense %s",
|
||||
expense.getExpenseSeq()));
|
||||
expenseService.addPayment(expense, bankDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge bank orders.
|
||||
*
|
||||
* @param doneList
|
||||
* @throws AxelorException
|
||||
*/
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
protected void mergeBankOrders(List<Expense> doneList) throws AxelorException {
|
||||
List<Expense> expenseList = new ArrayList<>();
|
||||
List<BankOrder> bankOrderList = new ArrayList<>();
|
||||
|
||||
for (Expense expense : doneList) {
|
||||
BankOrder bankOrder = expense.getBankOrder();
|
||||
if (bankOrder != null) {
|
||||
expenseList.add(expense);
|
||||
bankOrderList.add(bankOrder);
|
||||
}
|
||||
}
|
||||
|
||||
if (bankOrderList.size() > 1) {
|
||||
BankOrder mergedBankOrder = bankOrderMergeService.mergeBankOrders(bankOrderList);
|
||||
for (Expense expense : expenseList) {
|
||||
expense.setBankOrder(mergedBankOrder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
import com.axelor.apps.hr.db.repo.EmploymentContractRepository;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.EmploymentContractService;
|
||||
import com.axelor.apps.tool.file.CsvTool;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BatchEmploymentContractExport extends BatchStrategy {
|
||||
|
||||
protected int total;
|
||||
protected HrBatch hrBatch;
|
||||
|
||||
@Override
|
||||
protected void start() throws IllegalAccessException {
|
||||
|
||||
super.start();
|
||||
|
||||
total = 0;
|
||||
hrBatch = Beans.get(HrBatchRepository.class).find(batch.getHrBatch().getId());
|
||||
|
||||
checkPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
|
||||
List<EmploymentContract> employmentContractList =
|
||||
Beans.get(EmploymentContractRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.payCompany = ?1 AND self.status = ?2",
|
||||
hrBatch.getCompany(),
|
||||
EmploymentContractRepository.STATUS_ACTIVE)
|
||||
.fetch();
|
||||
|
||||
switch (hrBatch.getEmploymentContractExportTypeSelect()) {
|
||||
case HrBatchRepository.EMPLOYMENT_CONTRACT_EXPORT_TYPE_SILAE:
|
||||
try {
|
||||
batch.setMetaFile(employmentContractExportSilae(employmentContractList));
|
||||
} catch (IOException e) {
|
||||
incrementAnomaly();
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public MetaFile employmentContractExportSilae(List<EmploymentContract> employmentContractList)
|
||||
throws IOException {
|
||||
|
||||
List<String[]> list = new ArrayList<>();
|
||||
|
||||
for (EmploymentContract employmentContract : employmentContractList) {
|
||||
Beans.get(EmploymentContractService.class)
|
||||
.employmentContractExportSilae(employmentContract, list);
|
||||
|
||||
total++;
|
||||
incrementDone();
|
||||
}
|
||||
|
||||
File tempFile =
|
||||
MetaFiles.createTempFile(
|
||||
Beans.get(EmploymentContractService.class).employmentContractExportName(), ".csv")
|
||||
.toFile();
|
||||
|
||||
String[] headers = Beans.get(EmploymentContractService.class).employmentContractExportHeaders();
|
||||
|
||||
CsvTool.csvWriter(tempFile.getParent(), tempFile.getName(), ';', headers, list);
|
||||
|
||||
MetaFiles metaFiles = Beans.get(MetaFiles.class);
|
||||
MetaFile metaFile = metaFiles.upload(tempFile);
|
||||
tempFile.delete();
|
||||
|
||||
return metaFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
|
||||
String comment =
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_EMPLOYMENT_CONTRACT_EXPORT_RECAP) + '\n', total);
|
||||
|
||||
addComment(comment);
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
import com.axelor.apps.hr.db.LeaveLine;
|
||||
import com.axelor.apps.hr.db.LeaveManagement;
|
||||
import com.axelor.apps.hr.db.LeaveReason;
|
||||
import com.axelor.apps.hr.db.repo.LeaveLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveManagementRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.leave.LeaveService;
|
||||
import com.axelor.apps.hr.service.leave.management.LeaveManagementService;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.ExceptionOriginRepository;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.Digits;
|
||||
|
||||
public class BatchLeaveManagement extends BatchStrategy {
|
||||
|
||||
int total;
|
||||
int noValueAnomaly;
|
||||
int confAnomaly;
|
||||
|
||||
protected LeaveLineRepository leaveLineRepository;
|
||||
protected LeaveManagementRepository leaveManagementRepository;
|
||||
|
||||
@Inject private Provider<LeaveService> leaveServiceProvider;
|
||||
|
||||
@Inject
|
||||
public BatchLeaveManagement(
|
||||
LeaveManagementService leaveManagementService,
|
||||
LeaveLineRepository leaveLineRepository,
|
||||
LeaveManagementRepository leaveManagementRepository) {
|
||||
|
||||
super(leaveManagementService);
|
||||
this.leaveLineRepository = leaveLineRepository;
|
||||
this.leaveManagementRepository = leaveManagementRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() throws IllegalAccessException {
|
||||
|
||||
super.start();
|
||||
|
||||
if (batch.getHrBatch().getDayNumber() == null
|
||||
|| batch.getHrBatch().getDayNumber().signum() == 0
|
||||
|| batch.getHrBatch().getLeaveReason() == null) {
|
||||
TraceBackService.trace(
|
||||
new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.BATCH_MISSING_FIELD)),
|
||||
ExceptionOriginRepository.LEAVE_MANAGEMENT,
|
||||
batch.getId());
|
||||
}
|
||||
total = 0;
|
||||
noValueAnomaly = 0;
|
||||
confAnomaly = 0;
|
||||
checkPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
|
||||
List<Employee> employeeList = this.getEmployees(batch.getHrBatch());
|
||||
generateLeaveManagementLines(employeeList);
|
||||
}
|
||||
|
||||
public List<Employee> getEmployees(HrBatch hrBatch) {
|
||||
|
||||
List<String> query = Lists.newArrayList();
|
||||
|
||||
if (hrBatch.getEmployeeSet() != null && !hrBatch.getEmployeeSet().isEmpty()) {
|
||||
String employeeIds =
|
||||
Joiner.on(',')
|
||||
.join(Iterables.transform(hrBatch.getEmployeeSet(), obj -> obj.getId().toString()));
|
||||
query.add("self.id IN (" + employeeIds + ")");
|
||||
}
|
||||
if (hrBatch.getEmployeeSet() != null && !hrBatch.getPlanningSet().isEmpty()) {
|
||||
String planningIds =
|
||||
Joiner.on(',')
|
||||
.join(Iterables.transform(hrBatch.getPlanningSet(), obj -> obj.getId().toString()));
|
||||
|
||||
query.add("self.weeklyPlanning.id IN (" + planningIds + ")");
|
||||
}
|
||||
|
||||
List<Employee> employeeList;
|
||||
String liaison = query.isEmpty() ? "" : " AND";
|
||||
if (hrBatch.getCompany() != null) {
|
||||
employeeList =
|
||||
JPA.all(Employee.class)
|
||||
.filter(
|
||||
Joiner.on(" AND ").join(query)
|
||||
+ liaison
|
||||
+ " self.mainEmploymentContract.payCompany = :company")
|
||||
.bind("company", hrBatch.getCompany())
|
||||
.fetch();
|
||||
} else {
|
||||
employeeList = JPA.all(Employee.class).filter(Joiner.on(" AND ").join(query)).fetch();
|
||||
}
|
||||
|
||||
return employeeList;
|
||||
}
|
||||
|
||||
public void generateLeaveManagementLines(List<Employee> employeeList) {
|
||||
|
||||
for (Employee employee : employeeList) {
|
||||
|
||||
try {
|
||||
createLeaveManagement(employeeRepository.find(employee.getId()));
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(e, ExceptionOriginRepository.LEAVE_MANAGEMENT, batch.getId());
|
||||
incrementAnomaly();
|
||||
if (e.getCategory() == TraceBackRepository.CATEGORY_NO_VALUE) {
|
||||
noValueAnomaly++;
|
||||
}
|
||||
if (e.getCategory() == TraceBackRepository.CATEGORY_CONFIGURATION_ERROR) {
|
||||
confAnomaly++;
|
||||
}
|
||||
} finally {
|
||||
total++;
|
||||
JPA.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void createLeaveManagement(Employee employee) throws AxelorException {
|
||||
|
||||
batch = batchRepo.find(batch.getId());
|
||||
LeaveLine leaveLine = null;
|
||||
LeaveReason leaveReason = batch.getHrBatch().getLeaveReason();
|
||||
|
||||
if (employee != null) {
|
||||
leaveLine = leaveServiceProvider.get().addLeaveReasonOrCreateIt(employee, leaveReason);
|
||||
|
||||
BigDecimal dayNumber =
|
||||
batch.getHrBatch().getUseWeeklyPlanningCoef()
|
||||
? batch
|
||||
.getHrBatch()
|
||||
.getDayNumber()
|
||||
.multiply(employee.getWeeklyPlanning().getLeaveCoef())
|
||||
: batch.getHrBatch().getDayNumber();
|
||||
dayNumber =
|
||||
dayNumber.subtract(
|
||||
new BigDecimal(
|
||||
publicHolidayService.getImposedDayNumber(
|
||||
employee,
|
||||
batch.getHrBatch().getStartDate(),
|
||||
batch.getHrBatch().getEndDate())));
|
||||
LeaveManagement leaveManagement =
|
||||
leaveManagementService.createLeaveManagement(
|
||||
leaveLine,
|
||||
AuthUtils.getUser(),
|
||||
batch.getHrBatch().getComments(),
|
||||
null,
|
||||
batch.getHrBatch().getStartDate(),
|
||||
batch.getHrBatch().getEndDate(),
|
||||
dayNumber);
|
||||
BigDecimal qty = leaveLine.getQuantity().add(dayNumber);
|
||||
BigDecimal totalQty = leaveLine.getTotalQuantity().add(dayNumber);
|
||||
|
||||
try {
|
||||
int integer =
|
||||
LeaveLine.class.getDeclaredField("quantity").getAnnotation(Digits.class).integer();
|
||||
BigDecimal limit = new BigDecimal((long) Math.pow(10, integer));
|
||||
if (qty.compareTo(limit) >= 0 || totalQty.compareTo(limit) >= 0) {
|
||||
throw new AxelorException(
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_QTY_OUT_OF_BOUNDS),
|
||||
limit.longValue());
|
||||
}
|
||||
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
throw new AxelorException(e, TraceBackRepository.CATEGORY_CONFIGURATION_ERROR);
|
||||
}
|
||||
|
||||
leaveLine.setQuantity(qty.setScale(4, RoundingMode.HALF_EVEN));
|
||||
leaveLine.setTotalQuantity(totalQty.setScale(4, RoundingMode.HALF_EVEN));
|
||||
|
||||
leaveManagementRepository.save(leaveManagement);
|
||||
leaveLineRepository.save(leaveLine);
|
||||
updateEmployee(employee);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
|
||||
String comment =
|
||||
String.format(I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_0), total) + '\n';
|
||||
|
||||
comment +=
|
||||
String.format(I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_1), batch.getDone())
|
||||
+ '\n';
|
||||
|
||||
if (confAnomaly > 0) {
|
||||
comment +=
|
||||
String.format(I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_2), confAnomaly)
|
||||
+ '\n';
|
||||
}
|
||||
if (noValueAnomaly > 0) {
|
||||
comment +=
|
||||
String.format(I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_3), noValueAnomaly)
|
||||
+ '\n';
|
||||
}
|
||||
|
||||
addComment(comment);
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.LeaveLine;
|
||||
import com.axelor.apps.hr.db.LeaveReason;
|
||||
import com.axelor.apps.hr.db.repo.LeaveLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveManagementRepository;
|
||||
import com.axelor.apps.hr.service.leave.management.LeaveManagementService;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.ExceptionOriginRepository;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
public class BatchLeaveManagementReset extends BatchLeaveManagement {
|
||||
|
||||
@Inject
|
||||
public BatchLeaveManagementReset(
|
||||
LeaveManagementService leaveManagementService,
|
||||
LeaveLineRepository leaveLineRepository,
|
||||
LeaveManagementRepository leaveManagementRepository) {
|
||||
super(leaveManagementService, leaveLineRepository, leaveManagementRepository);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
List<Employee> employeeList = getEmployees(batch.getHrBatch());
|
||||
resetLeaveManagementLines(employeeList);
|
||||
}
|
||||
|
||||
public void resetLeaveManagementLines(List<Employee> employeeList) {
|
||||
for (Employee employee : employeeList) {
|
||||
try {
|
||||
resetLeaveManagement(employeeRepository.find(employee.getId()));
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(e, ExceptionOriginRepository.LEAVE_MANAGEMENT, batch.getId());
|
||||
incrementAnomaly();
|
||||
if (e.getCategory() == TraceBackRepository.CATEGORY_NO_VALUE) {
|
||||
noValueAnomaly++;
|
||||
}
|
||||
if (e.getCategory() == TraceBackRepository.CATEGORY_CONFIGURATION_ERROR) {
|
||||
confAnomaly++;
|
||||
}
|
||||
} finally {
|
||||
total++;
|
||||
JPA.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void resetLeaveManagement(Employee employee) throws AxelorException {
|
||||
LeaveReason leaveReason = batch.getHrBatch().getLeaveReason();
|
||||
for (LeaveLine leaveLine : employee.getLeaveLineList()) {
|
||||
if (leaveReason.equals(leaveLine.getLeaveReason())) {
|
||||
leaveManagementService.reset(
|
||||
leaveLine,
|
||||
AuthUtils.getUser(),
|
||||
batch.getHrBatch().getComments(),
|
||||
null,
|
||||
batch.getHrBatch().getStartDate(),
|
||||
batch.getHrBatch().getEndDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||
import com.axelor.apps.base.db.repo.PeriodRepository;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
import com.axelor.apps.hr.db.PayrollPreparation;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.apps.hr.db.repo.PayrollPreparationRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.PayrollPreparationService;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.apps.tool.file.CsvTool;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.ExceptionOriginRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.axelor.meta.db.repo.MetaFileRepository;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BatchPayrollPreparationExport extends BatchStrategy {
|
||||
|
||||
protected int total;
|
||||
protected HrBatch hrBatch;
|
||||
|
||||
protected PayrollPreparationService payrollPreparationService;
|
||||
|
||||
@Inject protected PayrollPreparationRepository payrollPreparationRepository;
|
||||
|
||||
@Inject CompanyRepository companyRepository;
|
||||
|
||||
@Inject PeriodRepository periodRepository;
|
||||
|
||||
@Inject HRConfigService hrConfigService;
|
||||
|
||||
@Inject
|
||||
public BatchPayrollPreparationExport(PayrollPreparationService payrollPreparationService) {
|
||||
super();
|
||||
this.payrollPreparationService = payrollPreparationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() throws IllegalAccessException {
|
||||
|
||||
super.start();
|
||||
|
||||
total = 0;
|
||||
hrBatch = Beans.get(HrBatchRepository.class).find(batch.getHrBatch().getId());
|
||||
|
||||
checkPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
|
||||
String exportAll = "";
|
||||
if (!hrBatch.getExportAlreadyExported()) {
|
||||
exportAll = " AND self.exported = false ";
|
||||
}
|
||||
|
||||
List<PayrollPreparation> payrollPreparationList =
|
||||
payrollPreparationRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.company = ?1 AND self.period = ?2 " + exportAll,
|
||||
hrBatch.getCompany(),
|
||||
hrBatch.getPeriod())
|
||||
.fetch();
|
||||
|
||||
switch (hrBatch.getPayrollPreparationExportTypeSelect()) {
|
||||
case HrBatchRepository.EXPORT_TYPE_STANDARD:
|
||||
try {
|
||||
batch.setMetaFile(standardExport(payrollPreparationList));
|
||||
} catch (IOException e) {
|
||||
incrementAnomaly();
|
||||
TraceBackService.trace(e, ExceptionOriginRepository.LEAVE_MANAGEMENT, batch.getId());
|
||||
}
|
||||
break;
|
||||
case HrBatchRepository.EXPORT_TYPE_NIBELIS:
|
||||
try {
|
||||
batch.setMetaFile(nibelisExport(payrollPreparationList));
|
||||
} catch (Exception e) {
|
||||
incrementAnomaly();
|
||||
TraceBackService.trace(e, ExceptionOriginRepository.LEAVE_MANAGEMENT, batch.getId());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public MetaFile standardExport(List<PayrollPreparation> payrollPreparationList)
|
||||
throws IOException {
|
||||
|
||||
List<String[]> list = new ArrayList<>();
|
||||
LocalDate today = Beans.get(AppBaseService.class).getTodayDate();
|
||||
|
||||
for (PayrollPreparation payrollPreparation : payrollPreparationList) {
|
||||
String[] item = new String[5];
|
||||
item[0] = payrollPreparation.getEmployee().getName();
|
||||
item[1] = payrollPreparation.getDuration().toString();
|
||||
item[2] = payrollPreparation.getLunchVoucherNumber().toString();
|
||||
item[3] = payrollPreparation.getEmployeeBonusAmount().toString();
|
||||
item[4] = payrollPreparation.getExtraHoursNumber().toString();
|
||||
list.add(item);
|
||||
|
||||
payrollPreparation.setExported(true);
|
||||
payrollPreparation.setExportDate(today);
|
||||
payrollPreparation.setExportTypeSelect(HrBatchRepository.EXPORT_TYPE_STANDARD);
|
||||
payrollPreparation.addBatchListItem(batch);
|
||||
payrollPreparationRepository.save(payrollPreparation);
|
||||
total++;
|
||||
incrementDone();
|
||||
}
|
||||
|
||||
String fileName = Beans.get(PayrollPreparationService.class).getPayrollPreparationExportName();
|
||||
String filePath = AppSettings.get().get("file.upload.dir");
|
||||
|
||||
MetaFile metaFile = new MetaFile();
|
||||
metaFile.setFileName(fileName);
|
||||
metaFile.setFilePath(fileName);
|
||||
metaFile = Beans.get(MetaFileRepository.class).save(metaFile);
|
||||
|
||||
new File(filePath).mkdirs();
|
||||
CsvTool.csvWriter(
|
||||
filePath,
|
||||
fileName,
|
||||
';',
|
||||
Beans.get(PayrollPreparationService.class).getPayrollPreparationExportHeader(),
|
||||
list);
|
||||
|
||||
return metaFile;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public MetaFile nibelisExport(List<PayrollPreparation> payrollPreparationList)
|
||||
throws IOException, AxelorException {
|
||||
|
||||
List<String[]> list = new ArrayList<>();
|
||||
|
||||
for (PayrollPreparation payrollPreparation : payrollPreparationList) {
|
||||
|
||||
payrollPreparation.addBatchListItem(batch);
|
||||
payrollPreparationService.exportNibelis(payrollPreparation, list);
|
||||
total++;
|
||||
}
|
||||
|
||||
String fileName = Beans.get(PayrollPreparationService.class).getPayrollPreparationExportName();
|
||||
String filePath = AppSettings.get().get("file.upload.dir");
|
||||
|
||||
MetaFile metaFile = new MetaFile();
|
||||
metaFile.setFileName(fileName);
|
||||
metaFile.setFilePath(fileName);
|
||||
metaFile = Beans.get(MetaFileRepository.class).save(metaFile);
|
||||
|
||||
new File(filePath).mkdirs();
|
||||
CsvTool.csvWriter(
|
||||
filePath,
|
||||
fileName,
|
||||
';',
|
||||
Beans.get(PayrollPreparationService.class)
|
||||
.getPayrollPreparationMeilleurGestionExportHeader(),
|
||||
list);
|
||||
|
||||
return metaFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
|
||||
String comment =
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_PAYROLL_PREPARATION_EXPORT_RECAP) + '\n', total);
|
||||
|
||||
addComment(comment);
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Period;
|
||||
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||
import com.axelor.apps.base.db.repo.PeriodRepository;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
import com.axelor.apps.hr.db.PayrollPreparation;
|
||||
import com.axelor.apps.hr.db.repo.EmploymentContractRepository;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.apps.hr.db.repo.PayrollPreparationRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.PayrollPreparationService;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.ExceptionOriginRepository;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BatchPayrollPreparationGeneration extends BatchStrategy {
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected int duplicateAnomaly;
|
||||
protected int configurationAnomaly;
|
||||
protected int total;
|
||||
protected HrBatch hrBatch;
|
||||
protected Company company;
|
||||
|
||||
protected PayrollPreparationService payrollPreparationService;
|
||||
|
||||
@Inject protected PayrollPreparationRepository payrollPreparationRepository;
|
||||
|
||||
@Inject protected CompanyRepository companyRepository;
|
||||
|
||||
@Inject protected PeriodRepository periodRepository;
|
||||
|
||||
@Inject
|
||||
public BatchPayrollPreparationGeneration(PayrollPreparationService payrollPreparationService) {
|
||||
super();
|
||||
this.payrollPreparationService = payrollPreparationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() throws IllegalAccessException {
|
||||
|
||||
super.start();
|
||||
|
||||
duplicateAnomaly = 0;
|
||||
configurationAnomaly = 0;
|
||||
total = 0;
|
||||
hrBatch = Beans.get(HrBatchRepository.class).find(batch.getHrBatch().getId());
|
||||
if (hrBatch.getCompany() != null) {
|
||||
company = Beans.get(CompanyRepository.class).find(hrBatch.getCompany().getId());
|
||||
}
|
||||
checkPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
|
||||
List<Employee> employeeList = this.getEmployees(hrBatch);
|
||||
generatePayrollPreparations(employeeList);
|
||||
}
|
||||
|
||||
public List<Employee> getEmployees(HrBatch hrBatch) {
|
||||
|
||||
List<String> query = Lists.newArrayList();
|
||||
|
||||
if (!hrBatch.getEmployeeSet().isEmpty()) {
|
||||
String employeeIds =
|
||||
Joiner.on(',')
|
||||
.join(Iterables.transform(hrBatch.getEmployeeSet(), obj -> obj.getId().toString()));
|
||||
query.add("self.id IN (" + employeeIds + ")");
|
||||
}
|
||||
if (!hrBatch.getPlanningSet().isEmpty()) {
|
||||
String planningIds =
|
||||
Joiner.on(',')
|
||||
.join(Iterables.transform(hrBatch.getPlanningSet(), obj -> obj.getId().toString()));
|
||||
|
||||
query.add("self.weeklyPlanning.id IN (" + planningIds + ")");
|
||||
}
|
||||
|
||||
String liaison = query.isEmpty() ? "" : " AND";
|
||||
if (hrBatch.getCompany() != null) {
|
||||
return JPA.all(Employee.class)
|
||||
.filter(
|
||||
Joiner.on(" AND ").join(query)
|
||||
+ liaison
|
||||
+ " self.mainEmploymentContract.payCompany = :company")
|
||||
.bind("company", hrBatch.getCompany())
|
||||
.fetch();
|
||||
} else {
|
||||
return JPA.all(Employee.class).filter(Joiner.on(" AND ").join(query)).fetch();
|
||||
}
|
||||
}
|
||||
|
||||
public void generatePayrollPreparations(List<Employee> employeeList) {
|
||||
|
||||
for (Employee employee : employeeList) {
|
||||
try {
|
||||
employee = employeeRepository.find(employee.getId());
|
||||
if (employee.getMainEmploymentContract() != null
|
||||
&& employee.getMainEmploymentContract().getStatus()
|
||||
!= EmploymentContractRepository.STATUS_CLOSED) {
|
||||
createPayrollPreparation(employee);
|
||||
}
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(e, ExceptionOriginRepository.LEAVE_MANAGEMENT, batch.getId());
|
||||
incrementAnomaly();
|
||||
if (e.getCategory() == TraceBackRepository.CATEGORY_NO_UNIQUE_KEY) {
|
||||
duplicateAnomaly++;
|
||||
} else if (e.getCategory() == TraceBackRepository.CATEGORY_CONFIGURATION_ERROR) {
|
||||
configurationAnomaly++;
|
||||
}
|
||||
} finally {
|
||||
total++;
|
||||
JPA.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void createPayrollPreparation(Employee employee) throws AxelorException {
|
||||
String filter = "self.period = ?1 AND self.employee = ?2";
|
||||
String companyFilter = filter + " AND self.company = ?3";
|
||||
|
||||
List<PayrollPreparation> payrollPreparationList =
|
||||
payrollPreparationRepository
|
||||
.all()
|
||||
.filter(
|
||||
(company != null) ? companyFilter : filter, hrBatch.getPeriod(), employee, company)
|
||||
.fetch();
|
||||
log.debug("list : " + payrollPreparationList);
|
||||
if (!payrollPreparationList.isEmpty()) {
|
||||
throw new AxelorException(
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_NO_UNIQUE_KEY,
|
||||
I18n.get(IExceptionMessage.PAYROLL_PREPARATION_DUPLICATE),
|
||||
employee.getName(),
|
||||
(company != null) ? hrBatch.getCompany().getName() : null,
|
||||
hrBatch.getPeriod().getName());
|
||||
}
|
||||
PayrollPreparation payrollPreparation = new PayrollPreparation();
|
||||
if (company != null) {
|
||||
Company currentCompany = companyRepository.find(company.getId());
|
||||
payrollPreparation.setCompany(currentCompany);
|
||||
} else {
|
||||
payrollPreparation.setCompany(employee.getMainEmploymentContract().getPayCompany());
|
||||
}
|
||||
Period period = periodRepository.find(hrBatch.getPeriod().getId());
|
||||
payrollPreparation.setEmployee(employee);
|
||||
payrollPreparation.setEmploymentContract(employee.getMainEmploymentContract());
|
||||
payrollPreparation.setPeriod(period);
|
||||
|
||||
payrollPreparationService.fillInPayrollPreparation(payrollPreparation);
|
||||
payrollPreparationRepository.save(payrollPreparation);
|
||||
updateEmployee(employee);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
|
||||
String comment =
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_PAYROLL_PREPARATION_GENERATION_RECAP) + '\n', total);
|
||||
|
||||
comment +=
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_PAYROLL_PREPARATION_SUCCESS_RECAP) + '\n',
|
||||
batch.getDone());
|
||||
|
||||
if (duplicateAnomaly > 0) {
|
||||
comment +=
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_PAYROLL_PREPARATION_DUPLICATE_RECAP) + '\n',
|
||||
duplicateAnomaly);
|
||||
}
|
||||
|
||||
if (configurationAnomaly > 0) {
|
||||
comment +=
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_PAYROLL_PREPARATION_CONFIGURATION_RECAP) + '\n',
|
||||
configurationAnomaly);
|
||||
}
|
||||
|
||||
addComment(comment);
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* <p>Copyright (C) 2016 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* <p>This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU Affero General Public License, version 3, as published by the Free Software Foundation.
|
||||
*
|
||||
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* <p>You should have received a copy of the GNU Affero General Public License along with this
|
||||
* program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
import com.axelor.apps.hr.db.LeaveLine;
|
||||
import com.axelor.apps.hr.db.LeaveManagement;
|
||||
import com.axelor.apps.hr.db.LeaveManagementBatchRule;
|
||||
import com.axelor.apps.hr.db.repo.HRConfigRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveManagementRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.employee.EmployeeService;
|
||||
import com.axelor.apps.hr.service.leave.management.LeaveManagementService;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.ExceptionOriginRepository;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.tool.template.TemplateMaker;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import groovy.lang.Binding;
|
||||
import groovy.lang.GroovyShell;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
|
||||
public class BatchSeniorityLeaveManagement extends BatchStrategy {
|
||||
|
||||
int total;
|
||||
int noValueAnomaly;
|
||||
int confAnomaly;
|
||||
|
||||
private static final char TEMPLATE_DELIMITER = '$';
|
||||
protected TemplateMaker maker;
|
||||
protected HRConfig hrConfig;
|
||||
|
||||
protected LeaveLineRepository leaveLineRepository;
|
||||
protected LeaveManagementRepository leaveManagementRepository;
|
||||
|
||||
@Inject
|
||||
public BatchSeniorityLeaveManagement(
|
||||
LeaveManagementService leaveManagementService,
|
||||
LeaveLineRepository leaveLineRepository,
|
||||
LeaveManagementRepository leaveManagementRepository) {
|
||||
|
||||
super(leaveManagementService);
|
||||
this.leaveLineRepository = leaveLineRepository;
|
||||
this.leaveManagementRepository = leaveManagementRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start() throws IllegalAccessException {
|
||||
|
||||
super.start();
|
||||
|
||||
if (batch.getHrBatch().getDayNumber() == null
|
||||
|| batch.getHrBatch().getDayNumber() == BigDecimal.ZERO
|
||||
|| batch.getHrBatch().getLeaveReason() == null)
|
||||
TraceBackService.trace(
|
||||
new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.BATCH_MISSING_FIELD)),
|
||||
ExceptionOriginRepository.LEAVE_MANAGEMENT,
|
||||
batch.getId());
|
||||
total = 0;
|
||||
noValueAnomaly = 0;
|
||||
confAnomaly = 0;
|
||||
this.maker = new TemplateMaker(Locale.FRENCH, TEMPLATE_DELIMITER, TEMPLATE_DELIMITER);
|
||||
hrConfig =
|
||||
Beans.get(HRConfigRepository.class)
|
||||
.all()
|
||||
.filter("self.company.id = ?1 ", batch.getHrBatch().getCompany().getId())
|
||||
.fetchOne();
|
||||
checkPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
|
||||
List<Employee> employeeList = this.getEmployees(batch.getHrBatch());
|
||||
generateLeaveManagementLines(employeeList);
|
||||
}
|
||||
|
||||
public List<Employee> getEmployees(HrBatch hrBatch) {
|
||||
|
||||
List<Employee> employeeList;
|
||||
if (hrBatch.getCompany() != null) {
|
||||
employeeList =
|
||||
JPA.all(Employee.class)
|
||||
.filter("self.mainEmploymentContract.payCompany = :company")
|
||||
.bind("company", hrBatch.getCompany())
|
||||
.fetch();
|
||||
} else {
|
||||
employeeList = JPA.all(Employee.class).fetch();
|
||||
}
|
||||
return employeeList;
|
||||
}
|
||||
|
||||
public void generateLeaveManagementLines(List<Employee> employeeList) {
|
||||
|
||||
for (Employee employee : employeeList) {
|
||||
try {
|
||||
createLeaveManagement(employeeRepository.find(employee.getId()));
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(e, ExceptionOriginRepository.LEAVE_MANAGEMENT, batch.getId());
|
||||
incrementAnomaly();
|
||||
if (e.getCategory() == TraceBackRepository.CATEGORY_NO_VALUE) {
|
||||
noValueAnomaly++;
|
||||
}
|
||||
if (e.getCategory() == TraceBackRepository.CATEGORY_CONFIGURATION_ERROR) {
|
||||
confAnomaly++;
|
||||
}
|
||||
} finally {
|
||||
total++;
|
||||
JPA.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void createLeaveManagement(Employee employee) throws AxelorException {
|
||||
|
||||
batch = batchRepo.find(batch.getId());
|
||||
int count = 0;
|
||||
String eval = null;
|
||||
LeaveLine leaveLine = null;
|
||||
BigDecimal quantity = BigDecimal.ZERO;
|
||||
|
||||
if (!employee.getLeaveLineList().isEmpty()) {
|
||||
for (LeaveLine line : employee.getLeaveLineList()) {
|
||||
|
||||
if (line.getLeaveReason().equals(batch.getHrBatch().getLeaveReason())) {
|
||||
count++;
|
||||
leaveLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
throw new AxelorException(
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_NO_VALUE,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_NO_LEAVE_MANAGEMENT),
|
||||
employee.getName(),
|
||||
batch.getHrBatch().getLeaveReason().getLeaveReason());
|
||||
}
|
||||
if (count > 1) {
|
||||
throw new AxelorException(
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_DOUBLE_LEAVE_MANAGEMENT),
|
||||
employee.getName(),
|
||||
batch.getHrBatch().getLeaveReason().getLeaveReason());
|
||||
}
|
||||
if (count == 1) {
|
||||
|
||||
EmploymentContract contract = employee.getMainEmploymentContract();
|
||||
if (contract == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_NO_VALUE,
|
||||
IExceptionMessage.EMPLOYEE_CONTRACT_OF_EMPLOYMENT);
|
||||
}
|
||||
Integer executiveStatusSelect = contract.getExecutiveStatusSelect();
|
||||
|
||||
for (LeaveManagementBatchRule rule :
|
||||
Beans.get(HRConfigRepository.class)
|
||||
.all()
|
||||
.filter("self.company.id = ?1", batch.getHrBatch().getCompany().getId())
|
||||
.fetchOne()
|
||||
.getLeaveManagementBatchRuleList()) {
|
||||
|
||||
if (rule.getExecutiveStatusSelect().equals(executiveStatusSelect)) {
|
||||
maker.setContext(employee, "Employee");
|
||||
String formula = rule.getFormula();
|
||||
formula =
|
||||
formula.replace(
|
||||
hrConfig.getSeniorityVariableName(),
|
||||
String.valueOf(
|
||||
Beans.get(EmployeeService.class)
|
||||
.getLengthOfService(employee, batch.getHrBatch().getReferentialDate())));
|
||||
formula =
|
||||
formula.replace(
|
||||
hrConfig.getAgeVariableName(),
|
||||
String.valueOf(
|
||||
Beans.get(EmployeeService.class)
|
||||
.getAge(employee, batch.getHrBatch().getReferentialDate())));
|
||||
maker.setTemplate(formula);
|
||||
eval = maker.make();
|
||||
CompilerConfiguration conf = new CompilerConfiguration();
|
||||
ImportCustomizer customizer = new ImportCustomizer();
|
||||
customizer.addStaticStars("java.lang.Math");
|
||||
conf.addCompilationCustomizers(customizer);
|
||||
Binding binding = new Binding();
|
||||
GroovyShell shell = new GroovyShell(binding, conf);
|
||||
if (shell.evaluate(eval).toString().equals("true")) {
|
||||
quantity = rule.getLeaveDayNumber();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (quantity.signum() == 0) {
|
||||
// If the quantity equals 0, no need to create a leaveManagement and to update the employee,
|
||||
// since we won't give them any leaves
|
||||
incrementDone();
|
||||
return;
|
||||
}
|
||||
LeaveManagement leaveManagement =
|
||||
leaveManagementService.createLeaveManagement(
|
||||
leaveLine,
|
||||
AuthUtils.getUser(),
|
||||
batch.getHrBatch().getComments(),
|
||||
null,
|
||||
batch.getHrBatch().getStartDate(),
|
||||
batch.getHrBatch().getEndDate(),
|
||||
quantity);
|
||||
leaveLine.setQuantity(leaveLine.getQuantity().add(quantity));
|
||||
leaveLine.setTotalQuantity(leaveLine.getTotalQuantity().add(quantity));
|
||||
leaveManagementRepository.save(leaveManagement);
|
||||
leaveLineRepository.save(leaveLine);
|
||||
updateEmployee(employee);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
|
||||
String comment =
|
||||
String.format(I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_0) + '\n', total);
|
||||
|
||||
comment +=
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_1) + '\n', batch.getDone());
|
||||
|
||||
if (confAnomaly > 0) {
|
||||
comment +=
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_2) + '\n', confAnomaly);
|
||||
}
|
||||
if (noValueAnomaly > 0) {
|
||||
comment +=
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_LEAVE_MANAGEMENT_ENDING_3) + '\n', noValueAnomaly);
|
||||
}
|
||||
|
||||
addComment(comment);
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.base.service.administration.AbstractBatch;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.service.leave.management.LeaveManagementService;
|
||||
import com.axelor.apps.hr.service.publicHoliday.PublicHolidayHrService;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public abstract class BatchStrategy extends AbstractBatch {
|
||||
|
||||
protected LeaveManagementService leaveManagementService;
|
||||
|
||||
@Inject protected EmployeeRepository employeeRepository;
|
||||
|
||||
@Inject protected PublicHolidayHrService publicHolidayService;
|
||||
|
||||
public BatchStrategy(LeaveManagementService leaveManagementService) {
|
||||
super();
|
||||
this.leaveManagementService = leaveManagementService;
|
||||
}
|
||||
|
||||
public BatchStrategy() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected void updateEmployee(Employee employee) {
|
||||
|
||||
employee.addBatchSetItem(batchRepo.find(batch.getId()));
|
||||
|
||||
incrementDone();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.leave.management.LeaveManagementService;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.apps.message.db.repo.EmailAccountRepository;
|
||||
import com.axelor.apps.message.db.repo.MessageRepository;
|
||||
import com.axelor.apps.message.service.MessageService;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
public class BatchTimesheetReminder extends BatchStrategy {
|
||||
|
||||
protected TimesheetRepository timesheetRepo;
|
||||
protected MessageService messageService;
|
||||
|
||||
@Inject
|
||||
public BatchTimesheetReminder(
|
||||
LeaveManagementService leaveManagementService,
|
||||
TimesheetRepository timesheetRepo,
|
||||
MessageService messageService) {
|
||||
super(leaveManagementService);
|
||||
this.timesheetRepo = timesheetRepo;
|
||||
this.messageService = messageService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
for (Employee employee : getEmployeesWithoutRecentTimesheet()) {
|
||||
try {
|
||||
sendReminder(employee);
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e, Employee.class.getSimpleName(), batch.getId());
|
||||
incrementAnomaly();
|
||||
|
||||
} finally {
|
||||
incrementDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
String comment =
|
||||
String.format(I18n.get(IExceptionMessage.BATCH_TIMESHEET_REMINDER_DONE), batch.getDone())
|
||||
+ "<br/>"
|
||||
+ String.format(
|
||||
I18n.get(IExceptionMessage.BATCH_TIMESHEET_REMINDER_ANOMALY), batch.getAnomaly());
|
||||
|
||||
addComment(comment);
|
||||
super.stop();
|
||||
}
|
||||
|
||||
private List<Employee> getEmployeesWithoutRecentTimesheet() {
|
||||
LocalDate now = LocalDate.now();
|
||||
long daysBeforeReminder = batch.getHrBatch().getDaysBeforeReminder().longValue();
|
||||
|
||||
List<Employee> employees =
|
||||
employeeRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.timesheetReminder = 't' AND self.mainEmploymentContract.payCompany = :companyId")
|
||||
.bind("companyId", batch.getHrBatch().getCompany().getId())
|
||||
.fetch();
|
||||
employees.removeIf(employee -> hasRecentTimesheet(now, daysBeforeReminder, employee));
|
||||
return employees;
|
||||
}
|
||||
|
||||
private boolean hasRecentTimesheet(LocalDate now, long daysBeforeReminder, Employee employee) {
|
||||
Timesheet timesheet =
|
||||
timesheetRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.user.id = :userId AND self.statusSelect IN (:confirmed, :validated) AND self.company = :companyId")
|
||||
.bind("userId", employee.getUser().getId())
|
||||
.bind("confirmed", TimesheetRepository.STATUS_CONFIRMED)
|
||||
.bind("validated", TimesheetRepository.STATUS_VALIDATED)
|
||||
.bind("companyId", batch.getHrBatch().getCompany().getId())
|
||||
.order("-toDate")
|
||||
.fetchOne();
|
||||
return timesheet != null && timesheet.getToDate().plusDays(daysBeforeReminder).isAfter(now);
|
||||
}
|
||||
|
||||
private void sendReminder(Employee employee)
|
||||
throws AxelorException, MessagingException, IOException {
|
||||
Message message = new Message();
|
||||
message.setMediaTypeSelect(MessageRepository.MEDIA_TYPE_EMAIL);
|
||||
message.setReplyToEmailAddressSet(new HashSet<>());
|
||||
message.setCcEmailAddressSet(new HashSet<>());
|
||||
message.setBccEmailAddressSet(new HashSet<>());
|
||||
message.addToEmailAddressSetItem(employee.getContactPartner().getEmailAddress());
|
||||
message.setSenderUser(AuthUtils.getUser());
|
||||
message.setSubject(batch.getHrBatch().getTemplate().getSubject());
|
||||
message.setContent(batch.getHrBatch().getTemplate().getContent());
|
||||
message.setMailAccount(
|
||||
Beans.get(EmailAccountRepository.class).all().filter("self.isDefault = true").fetchOne());
|
||||
|
||||
messageService.sendByEmail(message);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||
import com.axelor.apps.base.db.repo.MailBatchRepository;
|
||||
import com.axelor.apps.base.service.administration.AbstractBatch;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetRepository;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.apps.message.db.Template;
|
||||
import com.axelor.apps.message.db.repo.EmailAccountRepository;
|
||||
import com.axelor.apps.message.db.repo.MessageRepository;
|
||||
import com.axelor.apps.message.service.MessageService;
|
||||
import com.axelor.apps.message.service.TemplateMessageService;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.ExceptionOriginRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
public class BatchTimesheetValidationReminder extends AbstractBatch {
|
||||
|
||||
protected TemplateMessageService templateMessageService;
|
||||
protected MessageService messageService;
|
||||
protected MessageRepository messageRepo;
|
||||
|
||||
@Inject
|
||||
public BatchTimesheetValidationReminder(
|
||||
TemplateMessageService templateMessageService,
|
||||
MessageService messageService,
|
||||
MessageRepository messageRepo) {
|
||||
|
||||
this.templateMessageService = templateMessageService;
|
||||
this.messageService = messageService;
|
||||
this.messageRepo = messageRepo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process() {
|
||||
Template template = batch.getMailBatch().getTemplate();
|
||||
switch (batch.getMailBatch().getCode()) {
|
||||
case MailBatchRepository.CODE_BATCH_EMAIL_TIME_SHEET:
|
||||
if (template != null) {
|
||||
generateEmailTemplate();
|
||||
} else {
|
||||
generateEmail();
|
||||
}
|
||||
break;
|
||||
case MailBatchRepository.CODE_BATCH_EMAIL_ALL_TIME_SHEET:
|
||||
if (template != null) {
|
||||
generateAllEmailTemplate();
|
||||
} else {
|
||||
generateAllEmail();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void generateEmailTemplate() {
|
||||
|
||||
Company company = batch.getMailBatch().getCompany();
|
||||
Template template = batch.getMailBatch().getTemplate();
|
||||
List<Timesheet> timesheetList = null;
|
||||
if (Beans.get(CompanyRepository.class).all().count() > 1) {
|
||||
timesheetList =
|
||||
Beans.get(TimesheetRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.company.id = ?1 AND self.statusSelect = 1 AND self.user.employee.timesheetReminder = true",
|
||||
company.getId())
|
||||
.fetch();
|
||||
} else {
|
||||
timesheetList =
|
||||
Beans.get(TimesheetRepository.class)
|
||||
.all()
|
||||
.filter("self.statusSelect = 1 AND self.user.employee.timesheetReminder = true")
|
||||
.fetch();
|
||||
}
|
||||
String model = template.getMetaModel().getFullName();
|
||||
String tag = template.getMetaModel().getName();
|
||||
for (Timesheet timesheet : timesheetList) {
|
||||
try {
|
||||
Message message =
|
||||
templateMessageService.generateMessage(
|
||||
timesheet.getUser().getEmployee().getId(), model, tag, template);
|
||||
messageService.sendByEmail(message);
|
||||
incrementDone();
|
||||
} catch (Exception e) {
|
||||
incrementAnomaly();
|
||||
TraceBackService.trace(new Exception(e), ExceptionOriginRepository.REMINDER, batch.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateEmail() {
|
||||
List<Timesheet> timesheetList =
|
||||
Beans.get(CompanyRepository.class).all().count() > 1
|
||||
? Beans.get(TimesheetRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.company.id = ?1 AND self.statusSelect = 1 AND self.user.employee.timesheetReminder = true",
|
||||
batch.getMailBatch().getCompany().getId())
|
||||
.fetch()
|
||||
: Beans.get(TimesheetRepository.class)
|
||||
.all()
|
||||
.filter("self.statusSelect = 1 AND self.user.employee.timesheetReminder = true")
|
||||
.fetch();
|
||||
|
||||
for (Timesheet timesheet : timesheetList) {
|
||||
try {
|
||||
generateAndSendMessage(timesheet.getUser().getEmployee());
|
||||
incrementDone();
|
||||
} catch (Exception e) {
|
||||
incrementAnomaly();
|
||||
TraceBackService.trace(
|
||||
new Exception(e), ExceptionOriginRepository.INVOICE_ORIGIN, batch.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateAllEmailTemplate() {
|
||||
Template template = batch.getMailBatch().getTemplate();
|
||||
String model = template.getMetaModel().getFullName();
|
||||
String tag = template.getMetaModel().getName();
|
||||
|
||||
List<Employee> employeeList =
|
||||
Beans.get(EmployeeRepository.class).all().filter("self.timesheetReminder = true").fetch();
|
||||
|
||||
for (Employee employee : employeeList) {
|
||||
try {
|
||||
Message message =
|
||||
templateMessageService.generateMessage(employee.getId(), model, tag, template);
|
||||
messageService.sendByEmail(message);
|
||||
incrementDone();
|
||||
} catch (Exception e) {
|
||||
incrementAnomaly();
|
||||
TraceBackService.trace(new Exception(e), ExceptionOriginRepository.REMINDER, batch.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateAllEmail() {
|
||||
List<Employee> employeeList =
|
||||
Beans.get(EmployeeRepository.class).all().filter("self.timesheetReminder = true").fetch();
|
||||
|
||||
for (Employee employee : employeeList) {
|
||||
try {
|
||||
generateAndSendMessage(employee);
|
||||
incrementDone();
|
||||
} catch (Exception e) {
|
||||
incrementAnomaly();
|
||||
TraceBackService.trace(
|
||||
new Exception(e), ExceptionOriginRepository.INVOICE_ORIGIN, batch.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {MessagingException.class, IOException.class, Exception.class})
|
||||
protected Message generateAndSendMessage(Employee employee)
|
||||
throws MessagingException, IOException, AxelorException {
|
||||
|
||||
Message message = new Message();
|
||||
message.setMediaTypeSelect(MessageRepository.MEDIA_TYPE_EMAIL);
|
||||
message.setReplyToEmailAddressSet(new HashSet<>());
|
||||
message.setCcEmailAddressSet(new HashSet<>());
|
||||
message.setBccEmailAddressSet(new HashSet<>());
|
||||
message.addToEmailAddressSetItem(employee.getContactPartner().getEmailAddress());
|
||||
message.setSenderUser(AuthUtils.getUser());
|
||||
message.setSubject(batch.getMailBatch().getSubject());
|
||||
message.setContent(batch.getMailBatch().getContent());
|
||||
message.setMailAccount(
|
||||
Beans.get(EmailAccountRepository.class).all().filter("self.isDefault = true").fetchOne());
|
||||
message = messageRepo.save(message);
|
||||
|
||||
return messageService.sendByEmail(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop() {
|
||||
|
||||
String comment = String.format("\t* %s Email(s) sent %n", batch.getDone());
|
||||
comment +=
|
||||
String.format(
|
||||
"\t" + I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
|
||||
batch.getAnomaly());
|
||||
|
||||
super.stop();
|
||||
addComment(comment);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.base.db.Batch;
|
||||
import com.axelor.apps.base.exceptions.IExceptionMessage;
|
||||
import com.axelor.apps.base.service.administration.AbstractBatchService;
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.db.Model;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
|
||||
public class HrBatchService extends AbstractBatchService {
|
||||
|
||||
@Override
|
||||
protected Class<? extends Model> getModelClass() {
|
||||
return HrBatch.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Batch run(Model batchModel) throws AxelorException {
|
||||
|
||||
HrBatch hrBatch = (HrBatch) batchModel;
|
||||
Batch batch = null;
|
||||
|
||||
switch (hrBatch.getActionSelect()) {
|
||||
case HrBatchRepository.ACTION_LEAVE_MANAGEMENT:
|
||||
batch = leaveManagement(hrBatch);
|
||||
break;
|
||||
case HrBatchRepository.ACTION_SENIORITY_LEAVE_MANAGEMENT:
|
||||
batch = seniorityLeaveManagement(hrBatch);
|
||||
break;
|
||||
case HrBatchRepository.ACTION_PAYROLL_PREPARATION_GENERATION:
|
||||
batch = payrollPreparationGeneration(hrBatch);
|
||||
break;
|
||||
case HrBatchRepository.ACTION_PAYROLL_PREPARATION_EXPORT:
|
||||
batch = payrollPreparationExport(hrBatch);
|
||||
break;
|
||||
case HrBatchRepository.ACTION_LEAVE_MANAGEMENT_RESET:
|
||||
batch = leaveManagementReset(hrBatch);
|
||||
break;
|
||||
case HrBatchRepository.ACTION_EMPLOYMENT_CONTRACT_EXPORT:
|
||||
batch = employmentContractExport(hrBatch);
|
||||
break;
|
||||
case HrBatchHRRepository.ACTION_TIMESHEET_REMINDER:
|
||||
batch = runTimesheetReminderBatch(hrBatch);
|
||||
break;
|
||||
default:
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BASE_BATCH_1),
|
||||
hrBatch.getActionSelect(),
|
||||
hrBatch.getCode());
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
public Batch leaveManagement(HrBatch hrBatch) {
|
||||
return Beans.get(BatchLeaveManagement.class).run(hrBatch);
|
||||
}
|
||||
|
||||
public Batch seniorityLeaveManagement(HrBatch hrBatch) {
|
||||
return Beans.get(BatchSeniorityLeaveManagement.class).run(hrBatch);
|
||||
}
|
||||
|
||||
public Batch payrollPreparationGeneration(HrBatch hrBatch) {
|
||||
return Beans.get(BatchPayrollPreparationGeneration.class).run(hrBatch);
|
||||
}
|
||||
|
||||
public Batch payrollPreparationExport(HrBatch hrBatch) {
|
||||
return Beans.get(BatchPayrollPreparationExport.class).run(hrBatch);
|
||||
}
|
||||
|
||||
public Batch leaveManagementReset(HrBatch hrBatch) {
|
||||
return Beans.get(BatchLeaveManagementReset.class).run(hrBatch);
|
||||
}
|
||||
|
||||
public Batch employmentContractExport(HrBatch hrBatch) {
|
||||
return Beans.get(BatchEmploymentContractExport.class).run(hrBatch);
|
||||
}
|
||||
|
||||
public Batch runTimesheetReminderBatch(HrBatch hrBatch) throws AxelorException {
|
||||
if (hrBatch.getTemplate() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_NO_VALUE,
|
||||
com.axelor.apps.hr.exception.IExceptionMessage.BATCH_TIMESHEET_MISSING_TEMPLATE);
|
||||
}
|
||||
|
||||
return Beans.get(BatchTimesheetReminder.class).run(hrBatch);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.batch;
|
||||
|
||||
import com.axelor.apps.base.db.Batch;
|
||||
import com.axelor.apps.base.db.MailBatch;
|
||||
import com.axelor.apps.base.db.repo.MailBatchRepository;
|
||||
import com.axelor.apps.base.service.batch.MailBatchService;
|
||||
import com.axelor.db.Model;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
|
||||
public class MailBatchServiceHR extends MailBatchService {
|
||||
|
||||
@Override
|
||||
public Batch run(Model batchModel) throws AxelorException {
|
||||
MailBatch mailBatch = (MailBatch) batchModel;
|
||||
|
||||
switch (mailBatch.getActionSelect()) {
|
||||
case MailBatchRepository.ACTION_TIMESHEET_VALIDATION_REMINDER:
|
||||
return runTimesheetValidationReminderBatch(mailBatch);
|
||||
|
||||
default:
|
||||
return super.run(batchModel);
|
||||
}
|
||||
}
|
||||
|
||||
public Batch runTimesheetValidationReminderBatch(MailBatch mailBatch) {
|
||||
return Beans.get(BatchTimesheetValidationReminder.class).run(mailBatch);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.config;
|
||||
|
||||
import com.axelor.apps.account.db.Account;
|
||||
import com.axelor.apps.account.db.AccountConfig;
|
||||
import com.axelor.apps.account.db.Journal;
|
||||
import com.axelor.apps.account.service.config.AccountConfigService;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
|
||||
public class AccountConfigHRService extends AccountConfigService {
|
||||
|
||||
public Journal getExpenseJournal(AccountConfig accountConfig) throws AxelorException {
|
||||
if (accountConfig.getExpenseJournal() == null) {
|
||||
throw new AxelorException(
|
||||
accountConfig,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EXPENSE_JOURNAL),
|
||||
accountConfig.getCompany().getName());
|
||||
}
|
||||
return accountConfig.getExpenseJournal();
|
||||
}
|
||||
|
||||
public Account getExpenseEmployeeAccount(AccountConfig accountConfig) throws AxelorException {
|
||||
if (accountConfig.getEmployeeAccount() == null) {
|
||||
throw new AxelorException(
|
||||
accountConfig,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EXPENSE_ACCOUNT),
|
||||
accountConfig.getCompany().getName());
|
||||
}
|
||||
return accountConfig.getEmployeeAccount();
|
||||
}
|
||||
|
||||
public Account getExpenseTaxAccount(AccountConfig accountConfig) throws AxelorException {
|
||||
if (accountConfig.getExpenseTaxAccount() == null) {
|
||||
throw new AxelorException(
|
||||
accountConfig,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EXPENSE_ACCOUNT_TAX),
|
||||
accountConfig.getCompany().getName());
|
||||
}
|
||||
return accountConfig.getExpenseTaxAccount();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.config;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.base.db.Sequence;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.LeaveReason;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.message.db.Template;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
|
||||
public class HRConfigService {
|
||||
|
||||
public HRConfig getHRConfig(Company company) throws AxelorException {
|
||||
HRConfig hrConfig = company.getHrConfig();
|
||||
if (hrConfig == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG),
|
||||
company.getName());
|
||||
}
|
||||
return hrConfig;
|
||||
}
|
||||
|
||||
public Sequence getExpenseSequence(HRConfig hrConfig) throws AxelorException {
|
||||
Sequence sequence = hrConfig.getExpenseSequence();
|
||||
if (sequence == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_NO_EXPENSE_SEQUENCE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public LeaveReason getLeaveReason(HRConfig hrConfig) throws AxelorException {
|
||||
LeaveReason leaveReason = hrConfig.getToJustifyLeaveReason();
|
||||
if (leaveReason == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_LEAVE_REASON),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return leaveReason;
|
||||
}
|
||||
|
||||
public Product getKilometricExpenseProduct(HRConfig hrConfig) throws AxelorException {
|
||||
Product kilometricExpenseProduct = hrConfig.getKilometricExpenseProduct();
|
||||
if (kilometricExpenseProduct == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_EXPENSE_TYPE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return kilometricExpenseProduct;
|
||||
}
|
||||
|
||||
// EXPENSE
|
||||
|
||||
public Template getSentExpenseTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template sentExpenseTemplate = hrConfig.getSentExpenseTemplate();
|
||||
if (sentExpenseTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_SENT_EXPENSE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return sentExpenseTemplate;
|
||||
}
|
||||
|
||||
public Template getValidatedExpenseTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template validatedExpenseTemplate = hrConfig.getValidatedExpenseTemplate();
|
||||
if (validatedExpenseTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_VALIDATED_EXPENSE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return validatedExpenseTemplate;
|
||||
}
|
||||
|
||||
public Template getRefusedExpenseTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedExpenseTemplate = hrConfig.getRefusedExpenseTemplate();
|
||||
if (refusedExpenseTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_REFUSED_EXPENSE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedExpenseTemplate;
|
||||
}
|
||||
|
||||
public Template getCanceledExpenseTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedExpenseTemplate = hrConfig.getCanceledExpenseTemplate();
|
||||
if (refusedExpenseTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_CANCELED_EXPENSE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedExpenseTemplate;
|
||||
}
|
||||
|
||||
// TIMESHEET
|
||||
|
||||
public Template getSentTimesheetTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template sentTimesheetTemplate = hrConfig.getSentTimesheetTemplate();
|
||||
if (sentTimesheetTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_SENT_TIMESHEET_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return sentTimesheetTemplate;
|
||||
}
|
||||
|
||||
public Template getValidatedTimesheetTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template validatedTimesheetTemplate = hrConfig.getValidatedTimesheetTemplate();
|
||||
if (validatedTimesheetTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_VALIDATED_TIMESHEET_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return validatedTimesheetTemplate;
|
||||
}
|
||||
|
||||
public Template getRefusedTimesheetTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedTimesheetTemplate = hrConfig.getRefusedTimesheetTemplate();
|
||||
if (refusedTimesheetTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_REFUSED_TIMESHEET_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedTimesheetTemplate;
|
||||
}
|
||||
|
||||
public Template getCanceledTimesheetTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedTimesheetTemplate = hrConfig.getCanceledTimesheetTemplate();
|
||||
if (refusedTimesheetTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_CANCELED_TIMESHEET_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedTimesheetTemplate;
|
||||
}
|
||||
|
||||
// LEAVE REQUEST
|
||||
|
||||
public Template getSentLeaveTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template sentLeaveTemplate = hrConfig.getSentLeaveTemplate();
|
||||
if (sentLeaveTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_SENT_LEAVE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return sentLeaveTemplate;
|
||||
}
|
||||
|
||||
public Template getValidatedLeaveTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template validatedLeaveTemplate = hrConfig.getValidatedLeaveTemplate();
|
||||
if (validatedLeaveTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_VALIDATED_LEAVE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return validatedLeaveTemplate;
|
||||
}
|
||||
|
||||
public Template getRefusedLeaveTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedLeaveTemplate = hrConfig.getRefusedLeaveTemplate();
|
||||
if (refusedLeaveTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_REFUSED_LEAVE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedLeaveTemplate;
|
||||
}
|
||||
|
||||
public Template getCanceledLeaveTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedLeaveTemplate = hrConfig.getCanceledLeaveTemplate();
|
||||
if (refusedLeaveTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_CANCELED_LEAVE_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedLeaveTemplate;
|
||||
}
|
||||
|
||||
// EXTRA HOURS
|
||||
|
||||
public Template getSentExtraHoursTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template sentExtraHoursTemplate = hrConfig.getSentExtraHoursTemplate();
|
||||
if (sentExtraHoursTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_SENT_EXTRA_HOURS_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return sentExtraHoursTemplate;
|
||||
}
|
||||
|
||||
public Template getValidatedExtraHoursTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template validatedExtraHoursTemplate = hrConfig.getValidatedExtraHoursTemplate();
|
||||
if (validatedExtraHoursTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_VALIDATED_EXTRA_HOURS_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return validatedExtraHoursTemplate;
|
||||
}
|
||||
|
||||
public Template getRefusedExtraHoursTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedExtraHoursTemplate = hrConfig.getRefusedExtraHoursTemplate();
|
||||
if (refusedExtraHoursTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_REFUSED_EXTRA_HOURS_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedExtraHoursTemplate;
|
||||
}
|
||||
|
||||
public Template getCanceledExtraHoursTemplate(HRConfig hrConfig) throws AxelorException {
|
||||
Template refusedExtraHoursTemplate = hrConfig.getCanceledExtraHoursTemplate();
|
||||
if (refusedExtraHoursTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.HR_CONFIG_CANCELED_EXTRA_HOURS_TEMPLATE),
|
||||
hrConfig.getCompany().getName());
|
||||
}
|
||||
return refusedExtraHoursTemplate;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.employee;
|
||||
|
||||
import com.axelor.apps.base.service.user.UserService;
|
||||
import com.axelor.apps.hr.db.DPAE;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
public interface EmployeeService extends UserService {
|
||||
|
||||
public int getLengthOfService(Employee employee, LocalDate refDate) throws AxelorException;
|
||||
|
||||
public int getAge(Employee employee, LocalDate refDate) throws AxelorException;
|
||||
|
||||
public BigDecimal getDaysWorksInPeriod(Employee employee, LocalDate fromDate, LocalDate toDate)
|
||||
throws AxelorException;
|
||||
|
||||
public BigDecimal getDaysWorkedInPeriod(Employee employee, LocalDate fromDate, LocalDate toDate)
|
||||
throws AxelorException;
|
||||
|
||||
public Map<String, String> getSocialNetworkUrl(String name, String firstName);
|
||||
|
||||
/** Generates a new {@link DPAE} for given {@link Employee} and returns its id. */
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
Long generateNewDPAE(Employee employee) throws AxelorException;
|
||||
|
||||
@Transactional
|
||||
public void setEmployeeEnrolled(Employee employee);
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void updateEmployeeConfig(Employee employee, Integer configSelect, Boolean status) throws AxelorException ;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void massUpdateEmployeeConfig(List<Long> employeesIds, Integer configSelect, Boolean status) throws AxelorException;
|
||||
|
||||
}
|
||||
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.employee;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.EventsPlanning;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.base.db.WeeklyPlanning;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.base.service.user.UserServiceImpl;
|
||||
import com.axelor.apps.base.service.weeklyplanning.WeeklyPlanningService;
|
||||
import com.axelor.apps.hr.db.DPAE;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.LeaveRequest;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.LeaveRequestRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.leave.LeaveService;
|
||||
import com.axelor.apps.hr.service.publicHoliday.PublicHolidayHrService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Period;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class EmployeeServiceImpl extends UserServiceImpl implements EmployeeService {
|
||||
|
||||
@Inject protected WeeklyPlanningService weeklyPlanningService;
|
||||
|
||||
public int getLengthOfService(Employee employee, LocalDate refDate) throws AxelorException {
|
||||
|
||||
try {
|
||||
Period period =
|
||||
Period.between(
|
||||
employee.getSeniorityDate(),
|
||||
refDate == null ? Beans.get(AppBaseService.class).getTodayDate() : refDate);
|
||||
return period.getYears();
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(),
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_NO_VALUE,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_NO_SENIORITY_DATE),
|
||||
employee.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public int getAge(Employee employee, LocalDate refDate) throws AxelorException {
|
||||
|
||||
try {
|
||||
Period period =
|
||||
Period.between(
|
||||
employee.getBirthDate(),
|
||||
refDate == null ? Beans.get(AppBaseService.class).getTodayDate() : refDate);
|
||||
return period.getYears();
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(),
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_NO_VALUE,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_NO_BIRTH_DATE),
|
||||
employee.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getDaysWorksInPeriod(Employee employee, LocalDate fromDate, LocalDate toDate)
|
||||
throws AxelorException {
|
||||
Company company = employee.getMainEmploymentContract().getPayCompany();
|
||||
BigDecimal duration = BigDecimal.ZERO;
|
||||
|
||||
WeeklyPlanning weeklyPlanning = employee.getWeeklyPlanning();
|
||||
if (weeklyPlanning == null) {
|
||||
HRConfig conf = company.getHrConfig();
|
||||
if (conf != null) {
|
||||
weeklyPlanning = conf.getWeeklyPlanning();
|
||||
}
|
||||
}
|
||||
|
||||
if (weeklyPlanning == null) {
|
||||
throw new AxelorException(
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_PLANNING),
|
||||
employee.getName());
|
||||
}
|
||||
|
||||
EventsPlanning publicHolidayPlanning = employee.getPublicHolidayEventsPlanning();
|
||||
if (publicHolidayPlanning == null) {
|
||||
HRConfig conf = company.getHrConfig();
|
||||
if (conf != null) {
|
||||
publicHolidayPlanning = conf.getPublicHolidayEventsPlanning();
|
||||
}
|
||||
}
|
||||
|
||||
if (publicHolidayPlanning == null) {
|
||||
throw new AxelorException(
|
||||
employee,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_PUBLIC_HOLIDAY),
|
||||
employee.getName());
|
||||
}
|
||||
|
||||
LocalDate date = fromDate;
|
||||
while (!date.isAfter(toDate)) {
|
||||
duration =
|
||||
duration.add(
|
||||
BigDecimal.valueOf(
|
||||
weeklyPlanningService.getWorkingDayValueInDays(weeklyPlanning, date)));
|
||||
date = date.plusDays(1);
|
||||
}
|
||||
|
||||
duration =
|
||||
duration.subtract(
|
||||
Beans.get(PublicHolidayHrService.class)
|
||||
.computePublicHolidayDays(fromDate, toDate, weeklyPlanning, publicHolidayPlanning));
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getDaysWorkedInPeriod(Employee employee, LocalDate fromDate, LocalDate toDate)
|
||||
throws AxelorException {
|
||||
BigDecimal daysWorks = getDaysWorksInPeriod(employee, fromDate, toDate);
|
||||
|
||||
BigDecimal daysLeave = BigDecimal.ZERO;
|
||||
List<LeaveRequest> leaveRequestList =
|
||||
Beans.get(LeaveRequestRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ?1 AND self.duration >= 1 AND self.statusSelect = ?2 AND (self.fromDateT BETWEEN ?3 AND ?4 OR self.toDateT BETWEEN ?3 AND ?4)",
|
||||
employee.getUser(),
|
||||
LeaveRequestRepository.STATUS_VALIDATED,
|
||||
fromDate,
|
||||
toDate)
|
||||
.fetch();
|
||||
|
||||
for (LeaveRequest leaveRequest : leaveRequestList) {
|
||||
daysLeave =
|
||||
daysLeave.add(
|
||||
Beans.get(LeaveService.class).computeDuration(leaveRequest, fromDate, toDate));
|
||||
}
|
||||
|
||||
return daysWorks.subtract(daysLeave);
|
||||
}
|
||||
|
||||
public Map<String, String> getSocialNetworkUrl(String name, String firstName) {
|
||||
|
||||
Map<String, String> urlMap = new HashMap<>();
|
||||
name =
|
||||
firstName != null && name != null
|
||||
? firstName + "+" + name
|
||||
: name == null ? firstName : name;
|
||||
name = name == null ? "" : name;
|
||||
urlMap.put(
|
||||
"facebook",
|
||||
"<a class='fa fa-facebook' href='https://www.facebook.com/search/more/?q="
|
||||
+ name
|
||||
+ "&init=public"
|
||||
+ "' target='_blank'/>");
|
||||
urlMap.put(
|
||||
"twitter",
|
||||
"<a class='fa fa-twitter' href='https://twitter.com/search?q="
|
||||
+ name
|
||||
+ "' target='_blank' />");
|
||||
urlMap.put(
|
||||
"linkedin",
|
||||
"<a class='fa fa-linkedin' href='http://www.linkedin.com/pub/dir/"
|
||||
+ name.replace("+", "/")
|
||||
+ "' target='_blank' />");
|
||||
urlMap.put(
|
||||
"youtube",
|
||||
"<a class='fa fa-youtube' href='https://www.youtube.com/results?search_query="
|
||||
+ name
|
||||
+ "' target='_blank' />");
|
||||
|
||||
return urlMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public Long generateNewDPAE(Employee employee) throws AxelorException {
|
||||
EmploymentContract mainEmploymentContract = employee.getMainEmploymentContract();
|
||||
if (mainEmploymentContract == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_CONTRACT_OF_EMPLOYMENT),
|
||||
employee.getName());
|
||||
}
|
||||
|
||||
Company payCompany = mainEmploymentContract.getPayCompany();
|
||||
Partner employer = payCompany.getPartner();
|
||||
|
||||
DPAE newDPAE = new DPAE();
|
||||
|
||||
// Employer
|
||||
newDPAE.setRegistrationCode(employer.getRegistrationCode());
|
||||
newDPAE.setMainActivityCode(employer.getMainActivityCode());
|
||||
newDPAE.setCompany(payCompany);
|
||||
newDPAE.setCompanyAddress(employer.getMainAddress());
|
||||
newDPAE.setCompanyFixedPhone(employer.getFixedPhone());
|
||||
if (payCompany.getHrConfig() != null) {
|
||||
newDPAE.setHealthService(payCompany.getHrConfig().getHealthService());
|
||||
newDPAE.setHealthServiceAddress(payCompany.getHrConfig().getHealthServiceAddress());
|
||||
}
|
||||
|
||||
// Employee
|
||||
newDPAE.setLastName(employee.getContactPartner().getName());
|
||||
newDPAE.setFirstName(employee.getContactPartner().getFirstName());
|
||||
newDPAE.setSocialSecurityNumber(employee.getSocialSecurityNumber());
|
||||
newDPAE.setSexSelect(employee.getSexSelect());
|
||||
newDPAE.setDateOfBirth(employee.getBirthDate());
|
||||
newDPAE.setDepartmentOfBirth(employee.getDepartmentOfBirth());
|
||||
newDPAE.setCityOfBirth(employee.getCityOfBirth());
|
||||
newDPAE.setCountryOfBirth(employee.getCountryOfBirth());
|
||||
|
||||
// Contract
|
||||
newDPAE.setDateOfHire(mainEmploymentContract.getStartDate());
|
||||
newDPAE.setTimeOfHire(mainEmploymentContract.getStartTime());
|
||||
newDPAE.setTrialPeriodDuration(mainEmploymentContract.getTrialPeriodDuration());
|
||||
newDPAE.setContractType(mainEmploymentContract.getContractType());
|
||||
newDPAE.setEndDateOfContract(mainEmploymentContract.getEndDate());
|
||||
|
||||
employee.addDpaeListItem(newDPAE);
|
||||
|
||||
Beans.get(EmployeeRepository.class).save(employee);
|
||||
return newDPAE.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void setEmployeeEnrolled(Employee employee) {
|
||||
employee.setIsEnrolled(true);
|
||||
Beans.get(EmployeeRepository.class).save(employee);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void updateEmployeeConfig(Employee employee, Integer configSelect, Boolean status)
|
||||
throws AxelorException {
|
||||
switch (configSelect) {
|
||||
case 1: // ITP
|
||||
employee.setHasItp(status);
|
||||
break;
|
||||
case 2: // Nuissance
|
||||
employee.setHasNuissance(status);
|
||||
break;
|
||||
case 3: // Transfaire
|
||||
employee.setIsTransfaire(status);
|
||||
break;
|
||||
default:
|
||||
return; // Invalid configSelect, stop processing
|
||||
}
|
||||
Beans.get(EmployeeRepository.class).save(employee);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void massUpdateEmployeeConfig(
|
||||
List<Long> employeesIds, Integer configSelect, Boolean status) throws AxelorException {
|
||||
List<Employee> employees =
|
||||
Beans.get(EmployeeRepository.class).all().filter("self.id in (?1)", employeesIds).fetch();
|
||||
|
||||
if (employeesIds != null || !employeesIds.isEmpty()) {
|
||||
for (Employee employee : employees) {
|
||||
this.updateEmployeeConfig(employee, configSelect, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.expense;
|
||||
|
||||
import com.axelor.apps.account.db.Invoice;
|
||||
import com.axelor.apps.account.db.InvoiceLine;
|
||||
import com.axelor.apps.account.db.Move;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.ExpenseLine;
|
||||
import com.axelor.apps.hr.db.KilometricAllowParam;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
public interface ExpenseService {
|
||||
|
||||
public ExpenseLine getAndComputeAnalyticDistribution(ExpenseLine expenseLine, Expense expense)
|
||||
throws AxelorException;
|
||||
|
||||
public ExpenseLine createAnalyticDistributionWithTemplate(ExpenseLine expenseLine)
|
||||
throws AxelorException;
|
||||
|
||||
public ExpenseLine computeAnalyticDistribution(ExpenseLine expenseLine) throws AxelorException;
|
||||
|
||||
public Expense compute(Expense expense);
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void confirm(Expense expense) throws AxelorException;
|
||||
|
||||
public Message sendConfirmationEmail(Expense expense)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(Expense expense) throws AxelorException;
|
||||
|
||||
public Message sendValidationEmail(Expense expense)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void refuse(Expense expense) throws AxelorException;
|
||||
|
||||
public Message sendRefusalEmail(Expense expense)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public Move ventilate(Expense expense) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancel(Expense expense) throws AxelorException;
|
||||
|
||||
public Message sendCancellationEmail(Expense expense)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void addPayment(Expense expense, BankDetails bankDetails) throws AxelorException;
|
||||
|
||||
public void addPayment(Expense expense) throws AxelorException;
|
||||
|
||||
/**
|
||||
* Cancel the payment in the expense in argument. Revert the payment status and clear all payment
|
||||
* fields.
|
||||
*
|
||||
* @param expense
|
||||
* @throws AxelorException
|
||||
*/
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancelPayment(Expense expense) throws AxelorException;
|
||||
|
||||
public List<InvoiceLine> createInvoiceLines(
|
||||
Invoice invoice, List<ExpenseLine> expenseLineList, int priority) throws AxelorException;
|
||||
|
||||
public List<InvoiceLine> createInvoiceLine(Invoice invoice, ExpenseLine expenseLine, int priority)
|
||||
throws AxelorException;
|
||||
|
||||
/**
|
||||
* Get the expense from user, if no expense is found create one.
|
||||
*
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
public Expense getOrCreateExpense(User user);
|
||||
|
||||
public BigDecimal computePersonalExpenseAmount(Expense expense);
|
||||
|
||||
public BigDecimal computeAdvanceAmount(Expense expense);
|
||||
|
||||
public Product getKilometricExpenseProduct(Expense expense) throws AxelorException;
|
||||
|
||||
public void setDraftSequence(Expense expense) throws AxelorException;
|
||||
|
||||
public List<KilometricAllowParam> getListOfKilometricAllowParamVehicleFilter(
|
||||
ExpenseLine expenseLine) throws AxelorException;
|
||||
|
||||
public List<ExpenseLine> getExpenseLineList(Expense expense);
|
||||
|
||||
/**
|
||||
* fill {@link ExpenseLine#expense} in {@link Expense#generalExpenseLineList} and {@link
|
||||
* Expense#kilometricExpenseLineList}
|
||||
*
|
||||
* @param expense
|
||||
*/
|
||||
void completeExpenseLines(Expense expense);
|
||||
|
||||
public List<KilometricAllowParam> getListOfKilometricAllowParamVehicleFilter(
|
||||
ExpenseLine expenseLine, Expense expense) throws AxelorException;
|
||||
|
||||
public Move createMoveForExpensePayment(Expense expense) throws AxelorException;
|
||||
|
||||
public Expense updateMoveDateAndPeriod(Expense expense);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.extra.hours;
|
||||
|
||||
import com.axelor.apps.hr.db.ExtraHours;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import javax.mail.MessagingException;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
public interface ExtraHoursService {
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancel(ExtraHours extraHours) throws AxelorException;
|
||||
|
||||
public Message sendCancellationEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void confirm(ExtraHours extraHours) throws AxelorException;
|
||||
|
||||
public Message sendConfirmationEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(ExtraHours extraHours) throws AxelorException;
|
||||
|
||||
public Message sendValidationEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void refuse(ExtraHours extraHours) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveExtraHours(JSONObject jsonObject) throws AxelorException;
|
||||
|
||||
public Message sendRefusalEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public void compute(ExtraHours extraHours);
|
||||
}
|
||||
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.extra.hours;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.ExtraHours;
|
||||
import com.axelor.apps.hr.db.ExtraHoursLine;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExtraHoursRepository;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.apps.message.service.TemplateMessageService;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.mail.MessagingException;
|
||||
import wslite.json.JSONException;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
public class ExtraHoursServiceImpl implements ExtraHoursService {
|
||||
|
||||
protected ExtraHoursRepository extraHoursRepo;
|
||||
protected AppBaseService appBaseService;
|
||||
protected HRConfigService hrConfigService;
|
||||
protected TemplateMessageService templateMessageService;
|
||||
protected CompanyRepository companyRepo;
|
||||
protected DailyReportRepository dailyReportRepo;
|
||||
protected EmployeeRepository employeeRepo;
|
||||
|
||||
@Inject
|
||||
public ExtraHoursServiceImpl(
|
||||
EmployeeRepository employeeRepo,
|
||||
CompanyRepository companyRepo,
|
||||
DailyReportRepository dailyReportRepo,
|
||||
ExtraHoursRepository extraHoursRepo,
|
||||
AppBaseService appBaseService,
|
||||
HRConfigService hrConfigService,
|
||||
TemplateMessageService templateMessageService) {
|
||||
|
||||
this.extraHoursRepo = extraHoursRepo;
|
||||
this.employeeRepo = employeeRepo;
|
||||
this.companyRepo = companyRepo;
|
||||
this.dailyReportRepo = dailyReportRepo;
|
||||
this.appBaseService = appBaseService;
|
||||
this.hrConfigService = hrConfigService;
|
||||
this.templateMessageService = templateMessageService;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancel(ExtraHours extraHours) throws AxelorException {
|
||||
|
||||
extraHours.setStatusSelect(ExtraHoursRepository.STATUS_CANCELED);
|
||||
extraHoursRepo.save(extraHours);
|
||||
}
|
||||
|
||||
public Message sendCancellationEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException {
|
||||
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(extraHours.getCompany());
|
||||
|
||||
if (hrConfig.getTimesheetMailNotification()) {
|
||||
|
||||
return templateMessageService.generateAndSendMessage(
|
||||
extraHours, hrConfigService.getCanceledExtraHoursTemplate(hrConfig));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void confirm(ExtraHours extraHours) throws AxelorException {
|
||||
|
||||
extraHours.setStatusSelect(ExtraHoursRepository.STATUS_CONFIRMED);
|
||||
extraHours.setSentDate(appBaseService.getTodayDate());
|
||||
|
||||
extraHoursRepo.save(extraHours);
|
||||
}
|
||||
|
||||
public Message sendConfirmationEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException {
|
||||
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(extraHours.getCompany());
|
||||
|
||||
if (hrConfig.getExtraHoursMailNotification()) {
|
||||
|
||||
return templateMessageService.generateAndSendMessage(
|
||||
extraHours, hrConfigService.getSentExtraHoursTemplate(hrConfig));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(ExtraHours extraHours) throws AxelorException {
|
||||
|
||||
extraHours.setStatusSelect(ExtraHoursRepository.STATUS_VALIDATED);
|
||||
extraHours.setValidatedBy(AuthUtils.getUser());
|
||||
extraHours.setValidationDate(appBaseService.getTodayDate());
|
||||
|
||||
extraHoursRepo.save(extraHours);
|
||||
}
|
||||
|
||||
public Message sendValidationEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException {
|
||||
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(extraHours.getCompany());
|
||||
|
||||
if (hrConfig.getExtraHoursMailNotification()) {
|
||||
|
||||
return templateMessageService.generateAndSendMessage(
|
||||
extraHours, hrConfigService.getValidatedExtraHoursTemplate(hrConfig));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void refuse(ExtraHours extraHours) throws AxelorException {
|
||||
|
||||
extraHours.setStatusSelect(ExtraHoursRepository.STATUS_REFUSED);
|
||||
extraHours.setRefusedBy(AuthUtils.getUser());
|
||||
extraHours.setRefusalDate(appBaseService.getTodayDate());
|
||||
|
||||
extraHoursRepo.save(extraHours);
|
||||
}
|
||||
|
||||
public Message sendRefusalEmail(ExtraHours extraHours)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException {
|
||||
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(extraHours.getCompany());
|
||||
|
||||
if (hrConfig.getExtraHoursMailNotification()) {
|
||||
|
||||
return templateMessageService.generateAndSendMessage(
|
||||
extraHours, hrConfigService.getRefusedExtraHoursTemplate(hrConfig));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compute(ExtraHours extraHours) {
|
||||
|
||||
BigDecimal totalQty = BigDecimal.ZERO;
|
||||
List<ExtraHoursLine> extraHoursLines = extraHours.getExtraHoursLineList();
|
||||
|
||||
for (ExtraHoursLine extraHoursLine : extraHoursLines) {
|
||||
totalQty = totalQty.add(extraHoursLine.getQty());
|
||||
}
|
||||
|
||||
extraHours.setTotalQty(totalQty);
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveExtraHours(JSONObject jsonObject) throws AxelorException {
|
||||
Company company = companyRepo.all().filter("self.id = 1").fetchOne();
|
||||
try {
|
||||
// Extract fields
|
||||
int idInt = jsonObject.getInt("id");
|
||||
String id = Integer.toString(idInt);
|
||||
String ticketLink = "https://dsi.sophal.dz/front/ticket.form.php?id=" + id;
|
||||
String matricule = jsonObject.getString("matricule");
|
||||
String dateRequisition = jsonObject.getString("date_requisition");
|
||||
String motifRequisition = jsonObject.getString("motif_requisition");
|
||||
String heureDebut = jsonObject.getString("heure_debut");
|
||||
String heureFin = jsonObject.getString("heure_fin");
|
||||
String lieuTravail = jsonObject.getString("lieu_travail");
|
||||
int validation_status = jsonObject.optInt("validation_status", 2);
|
||||
String validateByUser = jsonObject.optString("validate_by_user", null);
|
||||
String dateValidation = jsonObject.optString("validation_date", null);
|
||||
|
||||
// GET EMPLOYEES
|
||||
Employee employee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", matricule)
|
||||
.fetchOne();
|
||||
|
||||
if (employee == null) {
|
||||
System.err.println("Employee with matricule " + matricule + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
Employee validatedByEmployee = null;
|
||||
|
||||
if (validateByUser != null) {
|
||||
validatedByEmployee =
|
||||
employeeRepo
|
||||
.all()
|
||||
.filter("self.registrationNumber = :matricule")
|
||||
.bind("matricule", validateByUser)
|
||||
.fetchOne();
|
||||
|
||||
if (validatedByEmployee == null) {
|
||||
System.err.println("Validator employee with matricule " + validateByUser + " not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse validation date (handle null case)
|
||||
LocalDate validationDate = null;
|
||||
if (dateValidation != null && !dateValidation.isEmpty()) {
|
||||
try {
|
||||
OffsetDateTime offsetDateTime =
|
||||
OffsetDateTime.parse(dateValidation, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
validationDate = offsetDateTime.toLocalDate(); // Extract only the date part
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing dateValidation: " + dateValidation);
|
||||
validationDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse Requisition Date
|
||||
LocalDate requisitionDate;
|
||||
try {
|
||||
requisitionDate = LocalDate.parse(dateRequisition);
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("Error parsing dateRequisition: " + dateRequisition);
|
||||
requisitionDate = null;
|
||||
}
|
||||
|
||||
// Check if Authorization exists by ticketId
|
||||
ExtraHours extraHours =
|
||||
extraHoursRepo
|
||||
.all()
|
||||
.filter("self.ticketId = :ticketId")
|
||||
.bind("ticketId", idInt)
|
||||
.fetchOne();
|
||||
|
||||
if (extraHours != null) {
|
||||
// Authorization exists, compare previous and new status
|
||||
int previousStatus = extraHours.getStatusSelect(); // Previous status
|
||||
int newStatus = validation_status; // New status
|
||||
|
||||
if (previousStatus == 2 && newStatus == 3) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
// Update the fields of the existing Authorization
|
||||
extraHours.setValidatedByEmployee(validatedByEmployee);
|
||||
extraHours.setValidationDate(validationDate);
|
||||
extraHours.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
extraHoursRepo.save(extraHours);
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", requisitionDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
dailyReport.setIsValidSupHours(true);
|
||||
}
|
||||
} else if (previousStatus == 2 && newStatus == 4) {
|
||||
System.out.println(
|
||||
"Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||
extraHours.setRefusedByEmployee(validatedByEmployee);
|
||||
extraHours.setRefusalDate(validationDate);
|
||||
extraHours.setStatusSelect(newStatus);
|
||||
// Save the updated Authorization
|
||||
extraHoursRepo.save(extraHours);
|
||||
}
|
||||
} else {
|
||||
// Create an instance of ExtraHours
|
||||
extraHours = new ExtraHours();
|
||||
extraHours.setEmployee(employee);
|
||||
extraHours.setTicket(ticketLink);
|
||||
extraHours.setTicketId(idInt);
|
||||
extraHours.setRequisitionDate(requisitionDate);
|
||||
extraHours.setDescription(motifRequisition);
|
||||
extraHours.setStatusSelect(validation_status);
|
||||
extraHours.setCompany(company);
|
||||
|
||||
// Parse Start and End Hours
|
||||
try {
|
||||
extraHours.setStartHour(LocalTime.parse(heureDebut));
|
||||
} catch (DateTimeParseException e) {
|
||||
// Append the problematic heureDebut to the description
|
||||
String updatedDescription = extraHours.getDescription() + " - " + heureDebut;
|
||||
extraHours.setDescription(updatedDescription);
|
||||
extraHours.setStartHour(LocalTime.MIDNIGHT); // Optionally set a default value
|
||||
}
|
||||
|
||||
try {
|
||||
extraHours.setEndHour(LocalTime.parse(heureFin));
|
||||
} catch (DateTimeParseException e) {
|
||||
// Append the problematic heureFin to the description
|
||||
String updatedDescription = extraHours.getDescription() + " - " + heureFin;
|
||||
extraHours.setDescription(updatedDescription);
|
||||
extraHours.setEndHour(LocalTime.MIDNIGHT); // Optionally set a default value
|
||||
}
|
||||
|
||||
if (validation_status == 3) {
|
||||
extraHours.setValidatedByEmployee(validatedByEmployee);
|
||||
extraHours.setValidationDate(validationDate);
|
||||
} else if (validation_status == 4) {
|
||||
extraHours.setRefusedByEmployee(validatedByEmployee);
|
||||
extraHours.setRefusalDate(validationDate);
|
||||
}
|
||||
|
||||
// Save the ExtraHours entity
|
||||
extraHoursRepo.save(extraHours);
|
||||
|
||||
// Get Daily report
|
||||
DailyReport dailyReport =
|
||||
dailyReportRepo
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.reportDate = :reportDate")
|
||||
.bind("employee", employee)
|
||||
.bind("reportDate", requisitionDate)
|
||||
.fetchOne();
|
||||
|
||||
if (dailyReport != null) {
|
||||
// Get the existing list of ExtraHours
|
||||
List<ExtraHours> supHoursList = dailyReport.getSupHoursList();
|
||||
|
||||
// If the list is null, initialize it
|
||||
if (supHoursList == null) {
|
||||
supHoursList = new ArrayList<>();
|
||||
}
|
||||
|
||||
// Add the new ExtraHours to the list
|
||||
supHoursList.add(extraHours);
|
||||
if (validation_status == 3) dailyReport.setIsValidSupHours(true);
|
||||
// Set the updated list back to dailyReport
|
||||
dailyReport.setSupHoursList(supHoursList);
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
System.err.println("Failed to parse JSON: " + jsonObject.toString());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.leave;
|
||||
|
||||
import com.axelor.apps.base.db.WeeklyPlanning;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.LeaveLine;
|
||||
import com.axelor.apps.hr.db.LeaveReason;
|
||||
import com.axelor.apps.hr.db.LeaveRequest;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import javax.mail.MessagingException;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
public interface LeaveService {
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void saveCR(JSONObject jsonObject) throws AxelorException;
|
||||
|
||||
public BigDecimal computeDuration(LeaveRequest leave) throws AxelorException;
|
||||
|
||||
public BigDecimal computeDuration(LeaveRequest leave, LocalDate fromDate, LocalDate toDate)
|
||||
throws AxelorException;
|
||||
|
||||
public BigDecimal computeDuration(
|
||||
LeaveRequest leave, LocalDateTime from, LocalDateTime to, int startOn, int endOn)
|
||||
throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void manageSentLeaves(LeaveRequest leave) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void manageValidateLeaves(LeaveRequest leave) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void manageRefuseLeaves(LeaveRequest leave) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void manageCancelLeaves(LeaveRequest leave) throws AxelorException;
|
||||
|
||||
public double computeStartDateWithSelect(
|
||||
LocalDate date, int select, WeeklyPlanning weeklyPlanning);
|
||||
|
||||
public double computeEndDateWithSelect(LocalDate date, int select, WeeklyPlanning weeklyPlanning);
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public LeaveRequest createEvents(LeaveRequest leave) throws AxelorException;
|
||||
|
||||
public BigDecimal computeLeaveDaysByLeaveRequest(
|
||||
LocalDate fromDate, LocalDate toDate, LeaveRequest leaveRequest, Employee employee)
|
||||
throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancel(LeaveRequest leaveRequest) throws AxelorException;
|
||||
|
||||
public Message sendCancellationEmail(LeaveRequest leaveRequest)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void confirm(LeaveRequest leaveRequest) throws AxelorException;
|
||||
|
||||
public Message sendConfirmationEmail(LeaveRequest leaveRequest)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(LeaveRequest leaveRequest) throws AxelorException;
|
||||
|
||||
public Message sendValidationEmail(LeaveRequest leaveRequest)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void refuse(LeaveRequest leaveRequest) throws AxelorException;
|
||||
|
||||
public Message sendRefusalEmail(LeaveRequest leaveRequest)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public boolean willHaveEnoughDays(LeaveRequest leaveRequest);
|
||||
|
||||
@Transactional
|
||||
public LeaveLine createLeaveReasonToJustify(Employee employee, LeaveReason leaveReasonHrConfig)
|
||||
throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public LeaveLine addLeaveReasonOrCreateIt(Employee employee, LeaveReason leaveReason)
|
||||
throws AxelorException;
|
||||
|
||||
/**
|
||||
* Checks if the given day is a leave day.
|
||||
*
|
||||
* @param user
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public boolean isLeaveDay(User user, LocalDate date);
|
||||
|
||||
/**
|
||||
* Gets the leave for the given user for the given date.
|
||||
*
|
||||
* @param user
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public LeaveRequest getLeave(User user, LocalDate date);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.leave.management;
|
||||
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.LeaveLine;
|
||||
import com.axelor.apps.hr.db.LeaveManagement;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public class LeaveManagementService {
|
||||
|
||||
@Inject protected AppBaseService appBaseService;
|
||||
|
||||
public LeaveLine computeQuantityAvailable(LeaveLine leaveLine) {
|
||||
List<LeaveManagement> leaveManagementList = leaveLine.getLeaveManagementList();
|
||||
leaveLine.setTotalQuantity(BigDecimal.ZERO);
|
||||
if (leaveManagementList != null && !leaveManagementList.isEmpty()) {
|
||||
for (LeaveManagement leaveManagement : leaveManagementList) {
|
||||
leaveLine.setTotalQuantity(leaveLine.getTotalQuantity().add(leaveManagement.getValue()));
|
||||
}
|
||||
leaveLine.setQuantity(leaveLine.getTotalQuantity().subtract(leaveLine.getDaysValidated()));
|
||||
}
|
||||
return leaveLine;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public LeaveManagement createLeaveManagement(
|
||||
LeaveLine leaveLine,
|
||||
User user,
|
||||
String comments,
|
||||
LocalDate date,
|
||||
LocalDate fromDate,
|
||||
LocalDate toDate,
|
||||
BigDecimal value) {
|
||||
|
||||
LeaveManagement leaveManagement = new LeaveManagement();
|
||||
|
||||
leaveManagement.setLeaveLine(leaveLine);
|
||||
leaveManagement.setUser(user);
|
||||
leaveManagement.setComments(comments);
|
||||
if (date == null) {
|
||||
leaveManagement.setDate(appBaseService.getTodayDate());
|
||||
} else {
|
||||
leaveManagement.setDate(date);
|
||||
}
|
||||
leaveManagement.setFromDate(fromDate);
|
||||
leaveManagement.setToDate(toDate);
|
||||
leaveManagement.setValue(value.setScale(4, RoundingMode.HALF_EVEN));
|
||||
|
||||
return leaveManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset leave management list by adding a new leave management line with negative quantity.
|
||||
*
|
||||
* @param leaveLine
|
||||
* @param user
|
||||
* @param comments
|
||||
* @param date
|
||||
* @param fromDate
|
||||
* @param toDate
|
||||
*/
|
||||
@Transactional
|
||||
public void reset(
|
||||
LeaveLine leaveLine,
|
||||
User user,
|
||||
String comments,
|
||||
LocalDate date,
|
||||
LocalDate fromDate,
|
||||
LocalDate toDate) {
|
||||
LeaveManagement leaveManagement =
|
||||
createLeaveManagement(
|
||||
leaveLine, user, comments, date, fromDate, toDate, leaveLine.getQuantity().negate());
|
||||
leaveLine.addLeaveManagementListItem(leaveManagement);
|
||||
leaveLine.setQuantity(BigDecimal.ZERO);
|
||||
leaveLine.setTotalQuantity(BigDecimal.ZERO);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.lunch.voucher;
|
||||
|
||||
import com.axelor.apps.hr.db.LunchVoucherAdvance;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
|
||||
public interface LunchVoucherAdvanceService {
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void onNewAdvance(LunchVoucherAdvance lunchVoucherAdvance) throws AxelorException;
|
||||
|
||||
public int useAdvance(LunchVoucherAdvance lunchVoucherAdvance, int qty) throws AxelorException;
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.lunch.voucher;
|
||||
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.LunchVoucherAdvance;
|
||||
import com.axelor.apps.hr.db.repo.HRConfigRepository;
|
||||
import com.axelor.apps.hr.db.repo.LunchVoucherAdvanceRepository;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
|
||||
public class LunchVoucherAdvanceServiceImpl implements LunchVoucherAdvanceService {
|
||||
|
||||
protected HRConfigService hrConfigService;
|
||||
|
||||
@Inject
|
||||
public LunchVoucherAdvanceServiceImpl(HRConfigService hrConfigService) {
|
||||
this.hrConfigService = hrConfigService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void onNewAdvance(LunchVoucherAdvance lunchVoucherAdvance) throws AxelorException {
|
||||
|
||||
HRConfig config =
|
||||
hrConfigService.getHRConfig(
|
||||
lunchVoucherAdvance.getEmployee().getMainEmploymentContract().getPayCompany());
|
||||
config.setAvailableStockLunchVoucher(
|
||||
config.getAvailableStockLunchVoucher() - lunchVoucherAdvance.getNbrLunchVouchers());
|
||||
|
||||
Beans.get(LunchVoucherAdvanceRepository.class).save(lunchVoucherAdvance);
|
||||
Beans.get(HRConfigRepository.class).save(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int useAdvance(LunchVoucherAdvance lunchVoucherAdvance, int qty) throws AxelorException {
|
||||
int toUse =
|
||||
lunchVoucherAdvance.getNbrLunchVouchers() - lunchVoucherAdvance.getNbrLunchVouchersUsed();
|
||||
|
||||
if (qty > toUse) {
|
||||
lunchVoucherAdvance.setNbrLunchVouchersUsed(lunchVoucherAdvance.getNbrLunchVouchers());
|
||||
return qty - toUse;
|
||||
}
|
||||
|
||||
lunchVoucherAdvance.setNbrLunchVouchersUsed(
|
||||
lunchVoucherAdvance.getNbrLunchVouchersUsed() + qty);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.lunch.voucher;
|
||||
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.LunchVoucherMgt;
|
||||
import com.axelor.apps.hr.db.LunchVoucherMgtLine;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
public interface LunchVoucherMgtLineService {
|
||||
|
||||
public LunchVoucherMgtLine create(Employee employee, LunchVoucherMgt lunchVoucherMgt)
|
||||
throws AxelorException;
|
||||
|
||||
/**
|
||||
* Set the lunch voucher format in the line. If the format in employee is null, uses format from
|
||||
* HR configuration.
|
||||
*
|
||||
* @param employee
|
||||
* @param lunchVoucherMgt
|
||||
* @param lunchVoucherMgtLine @throws AxelorException
|
||||
*/
|
||||
void fillLunchVoucherFormat(
|
||||
Employee employee, LunchVoucherMgt lunchVoucherMgt, LunchVoucherMgtLine lunchVoucherMgtLine)
|
||||
throws AxelorException;
|
||||
|
||||
public void compute(LunchVoucherMgtLine lunchVoucherMgtLine) throws AxelorException;
|
||||
|
||||
public void computeAllAttrs(
|
||||
Employee employee, LunchVoucherMgt lunchVoucherMgt, LunchVoucherMgtLine lunchVoucherMgtLine);
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.lunch.voucher;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.LunchVoucherAdvance;
|
||||
import com.axelor.apps.hr.db.LunchVoucherMgt;
|
||||
import com.axelor.apps.hr.db.LunchVoucherMgtLine;
|
||||
import com.axelor.apps.hr.db.repo.LunchVoucherAdvanceRepository;
|
||||
import com.axelor.apps.hr.db.repo.LunchVoucherMgtLineRepository;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.apps.hr.service.employee.EmployeeService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
public class LunchVoucherMgtLineServiceImpl implements LunchVoucherMgtLineService {
|
||||
|
||||
@Inject protected EmployeeService employeeService;
|
||||
|
||||
/*
|
||||
* Create a new line from employee and lunchVoucherMgt
|
||||
*/
|
||||
@Override
|
||||
public LunchVoucherMgtLine create(Employee employee, LunchVoucherMgt lunchVoucherMgt)
|
||||
throws AxelorException {
|
||||
LunchVoucherMgtLine lunchVoucherMgtLine = new LunchVoucherMgtLine();
|
||||
lunchVoucherMgtLine.setEmployee(employee);
|
||||
computeAllAttrs(employee, lunchVoucherMgt, lunchVoucherMgtLine);
|
||||
return lunchVoucherMgtLine;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to set the line attributes: if an exception occurs, the line status
|
||||
* is anomaly.
|
||||
*/
|
||||
@Override
|
||||
public void computeAllAttrs(
|
||||
Employee employee, LunchVoucherMgt lunchVoucherMgt, LunchVoucherMgtLine lunchVoucherMgtLine) {
|
||||
Integer lineStatus = LunchVoucherMgtLineRepository.STATUS_CALCULATED;
|
||||
try {
|
||||
lunchVoucherMgtLine.setInAdvanceNbr(computeEmployeeLunchVoucherAdvance(employee));
|
||||
lunchVoucherMgtLine.setDaysWorkedNbr(
|
||||
employeeService
|
||||
.getDaysWorkedInPeriod(
|
||||
employee,
|
||||
lunchVoucherMgt.getLeavePeriod().getFromDate(),
|
||||
lunchVoucherMgt.getLeavePeriod().getToDate())
|
||||
.setScale(0, RoundingMode.HALF_UP)
|
||||
.intValue());
|
||||
compute(lunchVoucherMgtLine);
|
||||
fillLunchVoucherFormat(employee, lunchVoucherMgt, lunchVoucherMgtLine);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
lineStatus = LunchVoucherMgtLineRepository.STATUS_ANOMALY;
|
||||
}
|
||||
lunchVoucherMgtLine.setStatusSelect(lineStatus);
|
||||
}
|
||||
|
||||
private Integer computeEmployeeLunchVoucherAdvance(Employee employee) {
|
||||
int number = 0;
|
||||
List<LunchVoucherAdvance> list =
|
||||
Beans.get(LunchVoucherAdvanceRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee.id = ?1 AND self.nbrLunchVouchersUsed < self.nbrLunchVouchers",
|
||||
employee.getId())
|
||||
.fetch();
|
||||
|
||||
for (LunchVoucherAdvance item : list) {
|
||||
number += item.getNbrLunchVouchers() - item.getNbrLunchVouchersUsed();
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillLunchVoucherFormat(
|
||||
Employee employee, LunchVoucherMgt lunchVoucherMgt, LunchVoucherMgtLine lunchVoucherMgtLine)
|
||||
throws AxelorException {
|
||||
int employeeFormat = employee.getLunchVoucherFormatSelect();
|
||||
if (employeeFormat != 0) {
|
||||
lunchVoucherMgtLine.setLunchVoucherFormatSelect(employeeFormat);
|
||||
} else {
|
||||
Company company = lunchVoucherMgt.getCompany();
|
||||
HRConfig hrConfig = Beans.get(HRConfigService.class).getHRConfig(company);
|
||||
lunchVoucherMgtLine.setLunchVoucherFormatSelect(hrConfig.getLunchVoucherFormatSelect());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compute(LunchVoucherMgtLine lunchVoucherMgtLine) throws AxelorException {
|
||||
Integer lunchVoucherNumber =
|
||||
lunchVoucherMgtLine.getDaysWorkedNbr()
|
||||
- (lunchVoucherMgtLine.getCanteenEntries()
|
||||
+ lunchVoucherMgtLine.getDaysOverseas()
|
||||
+ lunchVoucherMgtLine.getInAdvanceNbr()
|
||||
+ lunchVoucherMgtLine.getInvitation());
|
||||
lunchVoucherMgtLine.setLunchVoucherNumber(Integer.max(lunchVoucherNumber, 0));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.lunch.voucher;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.hr.db.LunchVoucherMgt;
|
||||
import com.axelor.apps.hr.db.LunchVoucherMgtLine;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public interface LunchVoucherMgtService {
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void calculate(LunchVoucherMgt lunchVoucherMgt) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(LunchVoucherMgt lunchVoucherMgt) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public int updateStock(
|
||||
List<LunchVoucherMgtLine> newLunchVoucherMgtLines,
|
||||
List<LunchVoucherMgtLine> oldLunchVoucherMgtLines,
|
||||
Company company)
|
||||
throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void export(LunchVoucherMgt lunchVoucherMgt) throws IOException;
|
||||
|
||||
public int checkStock(Company company, int numberToUse) throws AxelorException;
|
||||
|
||||
public void calculateTotal(LunchVoucherMgt lunchVoucherMgt);
|
||||
}
|
||||
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.lunch.voucher;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.*;
|
||||
import com.axelor.apps.hr.db.repo.*;
|
||||
import com.axelor.apps.hr.service.config.HRConfigService;
|
||||
import com.axelor.common.ObjectUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LunchVoucherMgtServiceImpl implements LunchVoucherMgtService {
|
||||
|
||||
protected LunchVoucherMgtRepository lunchVoucherMgtRepository;
|
||||
|
||||
protected LunchVoucherMgtLineService lunchVoucherMgtLineService;
|
||||
|
||||
protected LunchVoucherAdvanceService lunchVoucherAdvanceService;
|
||||
|
||||
protected HRConfigService hrConfigService;
|
||||
|
||||
@Inject
|
||||
public LunchVoucherMgtServiceImpl(
|
||||
LunchVoucherMgtLineService lunchVoucherMgtLineService,
|
||||
LunchVoucherAdvanceService lunchVoucherAdvanceService,
|
||||
LunchVoucherMgtRepository lunchVoucherMgtRepository,
|
||||
HRConfigService hrConfigService) {
|
||||
|
||||
this.lunchVoucherMgtLineService = lunchVoucherMgtLineService;
|
||||
this.lunchVoucherMgtRepository = lunchVoucherMgtRepository;
|
||||
this.lunchVoucherAdvanceService = lunchVoucherAdvanceService;
|
||||
this.hrConfigService = hrConfigService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void calculate(LunchVoucherMgt lunchVoucherMgt) throws AxelorException {
|
||||
Company company = lunchVoucherMgt.getCompany();
|
||||
|
||||
if (company == null) {
|
||||
throw new AxelorException(
|
||||
lunchVoucherMgt,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get("Please fill a company."));
|
||||
}
|
||||
if (lunchVoucherMgt.getLeavePeriod() == null) {
|
||||
throw new AxelorException(
|
||||
lunchVoucherMgt,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get("Please fill a leave period."));
|
||||
}
|
||||
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(company);
|
||||
|
||||
List<Employee> employeeList =
|
||||
Beans.get(EmployeeRepository.class)
|
||||
.all()
|
||||
.filter("self.mainEmploymentContract.payCompany = ?1", company)
|
||||
.fetch();
|
||||
|
||||
for (Employee employee : employeeList) {
|
||||
if (employee != null) {
|
||||
LunchVoucherMgtLine lunchVoucherMgtLine = obtainLineFromEmployee(employee, lunchVoucherMgt);
|
||||
// the employee doesn't have a line, create it
|
||||
if (lunchVoucherMgtLine == null) {
|
||||
lunchVoucherMgtLine = lunchVoucherMgtLineService.create(employee, lunchVoucherMgt);
|
||||
lunchVoucherMgt.addLunchVoucherMgtLineListItem(lunchVoucherMgtLine);
|
||||
}
|
||||
// the line exist and is not already calculated, update it
|
||||
else {
|
||||
if (lunchVoucherMgtLine.getStatusSelect()
|
||||
!= LunchVoucherMgtLineRepository.STATUS_CALCULATED) {
|
||||
lunchVoucherMgtLineService.computeAllAttrs(
|
||||
employee, lunchVoucherMgt, lunchVoucherMgtLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lunchVoucherMgt.setStatusSelect(LunchVoucherMgtRepository.STATUS_CALCULATED);
|
||||
|
||||
lunchVoucherMgt.setStockQuantityStatus(hrConfig.getAvailableStockLunchVoucher());
|
||||
|
||||
calculateTotal(lunchVoucherMgt);
|
||||
|
||||
lunchVoucherMgtRepository.save(lunchVoucherMgt);
|
||||
}
|
||||
|
||||
protected LunchVoucherMgtLine obtainLineFromEmployee(
|
||||
Employee employee, LunchVoucherMgt lunchVoucherMgt) {
|
||||
for (LunchVoucherMgtLine line : lunchVoucherMgt.getLunchVoucherMgtLineList()) {
|
||||
if (line.getEmployee() == employee) {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateTotal(LunchVoucherMgt lunchVoucherMgt) {
|
||||
List<LunchVoucherMgtLine> lunchVoucherMgtLineList =
|
||||
lunchVoucherMgt.getLunchVoucherMgtLineList();
|
||||
int total = 0;
|
||||
int totalInAdvance = 0;
|
||||
|
||||
int totalGiven = 0;
|
||||
|
||||
if (!ObjectUtils.isEmpty(lunchVoucherMgtLineList)) {
|
||||
for (LunchVoucherMgtLine lunchVoucherMgtLine : lunchVoucherMgtLineList) {
|
||||
total += lunchVoucherMgtLine.getLunchVoucherNumber();
|
||||
totalInAdvance += lunchVoucherMgtLine.getInAdvanceNbr();
|
||||
totalGiven += lunchVoucherMgtLine.getGivenToEmployee();
|
||||
}
|
||||
}
|
||||
|
||||
lunchVoucherMgt.setTotalLunchVouchers(
|
||||
total + totalInAdvance + lunchVoucherMgt.getStockLineQuantity());
|
||||
lunchVoucherMgt.setRequestedLunchVouchers(total + lunchVoucherMgt.getStockLineQuantity());
|
||||
lunchVoucherMgt.setGivenLunchVouchers(totalGiven);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkStock(Company company, int numberToUse) throws AxelorException {
|
||||
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(company);
|
||||
int minStoclLV = hrConfig.getMinStockLunchVoucher();
|
||||
int availableStoclLV = hrConfig.getAvailableStockLunchVoucher();
|
||||
|
||||
return availableStoclLV - numberToUse - minStoclLV;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the stock in the config from lunch voucher management
|
||||
*
|
||||
* @param newLunchVoucherMgtLines the new mgt lines
|
||||
* @param oldLunchVoucherMgtLines the previous mgt lines
|
||||
* @param company the company of the HR config
|
||||
* @return the stock quantity status of the lunch voucher mgt
|
||||
* @throws AxelorException
|
||||
*/
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
@Override
|
||||
public int updateStock(
|
||||
List<LunchVoucherMgtLine> newLunchVoucherMgtLines,
|
||||
List<LunchVoucherMgtLine> oldLunchVoucherMgtLines,
|
||||
Company company)
|
||||
throws AxelorException {
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(company);
|
||||
|
||||
int newLunchVoucherQty = hrConfig.getAvailableStockLunchVoucher();
|
||||
int i = 0;
|
||||
for (LunchVoucherMgtLine line : newLunchVoucherMgtLines) {
|
||||
int oldQty = oldLunchVoucherMgtLines.get(i).getGivenToEmployee();
|
||||
int newQty = line.getGivenToEmployee();
|
||||
newLunchVoucherQty = newLunchVoucherQty - newQty + oldQty;
|
||||
i++;
|
||||
}
|
||||
hrConfig.setAvailableStockLunchVoucher(newLunchVoucherQty);
|
||||
Beans.get(HRConfigRepository.class).save(hrConfig);
|
||||
return hrConfig.getAvailableStockLunchVoucher();
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void export(LunchVoucherMgt lunchVoucherMgt) throws IOException {
|
||||
MetaFile metaFile = new MetaFile();
|
||||
metaFile.setFileName(
|
||||
I18n.get("LunchVoucherCommand")
|
||||
+ " - "
|
||||
+ LocalDate.now().format(DateTimeFormatter.ISO_DATE)
|
||||
+ ".csv");
|
||||
|
||||
Path tempFile = MetaFiles.createTempFile(null, ".csv");
|
||||
final OutputStream os = new FileOutputStream(tempFile.toFile());
|
||||
|
||||
try (final Writer writer = new OutputStreamWriter(os)) {
|
||||
|
||||
List<String> header = new ArrayList<>();
|
||||
header.add(escapeCsv(I18n.get("Company code")));
|
||||
header.add(escapeCsv(I18n.get("Lunch Voucher's number")));
|
||||
header.add(escapeCsv(I18n.get("Employee")));
|
||||
header.add(escapeCsv(I18n.get("Lunch Voucher format")));
|
||||
|
||||
writer.write(Joiner.on(";").join(header));
|
||||
|
||||
for (LunchVoucherMgtLine lunchVoucherMgtLine : lunchVoucherMgt.getLunchVoucherMgtLineList()) {
|
||||
|
||||
List<String> line = new ArrayList<>();
|
||||
line.add(escapeCsv(lunchVoucherMgt.getCompany().getCode()));
|
||||
line.add(escapeCsv(lunchVoucherMgtLine.getLunchVoucherNumber().toString()));
|
||||
line.add(escapeCsv(lunchVoucherMgtLine.getEmployee().getName()));
|
||||
line.add(
|
||||
escapeCsv(lunchVoucherMgtLine.getEmployee().getLunchVoucherFormatSelect().toString()));
|
||||
|
||||
writer.write("\n");
|
||||
writer.write(Joiner.on(";").join(line));
|
||||
}
|
||||
|
||||
Beans.get(MetaFiles.class).upload(tempFile.toFile(), metaFile);
|
||||
|
||||
} catch (Exception e) {
|
||||
Throwables.propagate(e);
|
||||
} finally {
|
||||
Files.deleteIfExists(tempFile);
|
||||
}
|
||||
/*
|
||||
*/
|
||||
// lunchVoucherMgt.setExported(true);
|
||||
lunchVoucherMgt.setCsvFile(metaFile);
|
||||
lunchVoucherMgt.setExportDate(Beans.get(AppBaseService.class).getTodayDate());
|
||||
|
||||
lunchVoucherMgtRepository.save(lunchVoucherMgt);
|
||||
}
|
||||
|
||||
protected String escapeCsv(String value) {
|
||||
if (value == null) return "";
|
||||
if (value.indexOf('"') > -1) value = value.replaceAll("\"", "\"\"");
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(LunchVoucherMgt lunchVoucherMgt) throws AxelorException {
|
||||
Company company = lunchVoucherMgt.getCompany();
|
||||
HRConfig hrConfig = hrConfigService.getHRConfig(company);
|
||||
|
||||
LunchVoucherAdvanceRepository advanceRepo = Beans.get(LunchVoucherAdvanceRepository.class);
|
||||
|
||||
for (LunchVoucherMgtLine item : lunchVoucherMgt.getLunchVoucherMgtLineList()) {
|
||||
if (item.getInAdvanceNbr() > 0) {
|
||||
|
||||
int qtyToUse = item.getInAdvanceNbr();
|
||||
List<LunchVoucherAdvance> list =
|
||||
advanceRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee.id = ?1 AND self.nbrLunchVouchersUsed < self.nbrLunchVouchers",
|
||||
item.getEmployee().getId())
|
||||
.order("distributionDate")
|
||||
.fetch();
|
||||
|
||||
for (LunchVoucherAdvance subItem : list) {
|
||||
qtyToUse = lunchVoucherAdvanceService.useAdvance(subItem, qtyToUse);
|
||||
advanceRepo.save(subItem);
|
||||
|
||||
if (qtyToUse <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hrConfig.setAvailableStockLunchVoucher(
|
||||
hrConfig.getAvailableStockLunchVoucher() + lunchVoucherMgt.getStockLineQuantity());
|
||||
lunchVoucherMgt.setStatusSelect(LunchVoucherMgtRepository.STATUS_VALIDATED);
|
||||
|
||||
Beans.get(HRConfigRepository.class).save(hrConfig);
|
||||
lunchVoucherMgtRepository.save(lunchVoucherMgt);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.project;
|
||||
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.team.db.TeamTask;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ProjectPlanningTimeService {
|
||||
|
||||
public BigDecimal getTaskPlannedHrs(TeamTask teamTask);
|
||||
|
||||
public BigDecimal getProjectPlannedHrs(Project project);
|
||||
|
||||
public void addMultipleProjectPlanningTime(Map<String, Object> dataMap) throws AxelorException;
|
||||
|
||||
public void removeProjectPlanningLines(List<Map<String, Object>> projectPlanningLines);
|
||||
}
|
||||
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.project;
|
||||
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.base.db.repo.ProductRepository;
|
||||
import com.axelor.apps.base.service.weeklyplanning.WeeklyPlanningService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.service.publicHoliday.PublicHolidayHrService;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.apps.project.db.ProjectPlanningTime;
|
||||
import com.axelor.apps.project.db.repo.ProjectPlanningTimeRepository;
|
||||
import com.axelor.apps.project.db.repo.ProjectRepository;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.auth.db.repo.UserRepository;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.team.db.TeamTask;
|
||||
import com.axelor.team.db.repo.TeamTaskRepository;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ProjectPlanningTimeServiceImpl implements ProjectPlanningTimeService {
|
||||
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(ProjectPlanningTimeService.class);
|
||||
|
||||
protected ProjectPlanningTimeRepository planningTimeRepo;
|
||||
protected ProjectRepository projectRepo;
|
||||
protected TeamTaskRepository teamTaskRepo;
|
||||
protected WeeklyPlanningService weeklyPlanningService;
|
||||
protected PublicHolidayHrService holidayService;
|
||||
protected ProductRepository productRepo;
|
||||
protected UserRepository userRepo;
|
||||
|
||||
@Inject
|
||||
public ProjectPlanningTimeServiceImpl(
|
||||
ProjectPlanningTimeRepository planningTimeRepo,
|
||||
ProjectRepository projectRepo,
|
||||
TeamTaskRepository teamTaskRepo,
|
||||
WeeklyPlanningService weeklyPlanningService,
|
||||
PublicHolidayHrService holidayService,
|
||||
ProductRepository productRepo,
|
||||
UserRepository userRepo) {
|
||||
super();
|
||||
this.planningTimeRepo = planningTimeRepo;
|
||||
this.projectRepo = projectRepo;
|
||||
this.teamTaskRepo = teamTaskRepo;
|
||||
this.weeklyPlanningService = weeklyPlanningService;
|
||||
this.holidayService = holidayService;
|
||||
this.productRepo = productRepo;
|
||||
this.userRepo = userRepo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getTaskPlannedHrs(TeamTask task) {
|
||||
|
||||
BigDecimal totalPlanned = BigDecimal.ZERO;
|
||||
if (task != null) {
|
||||
List<ProjectPlanningTime> plannings =
|
||||
planningTimeRepo.all().filter("self.task = ?1", task).fetch();
|
||||
if (plannings != null) {
|
||||
totalPlanned =
|
||||
plannings
|
||||
.stream()
|
||||
.map(ProjectPlanningTime::getPlannedHours)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
}
|
||||
|
||||
return totalPlanned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getProjectPlannedHrs(Project project) {
|
||||
|
||||
BigDecimal totalPlanned = BigDecimal.ZERO;
|
||||
if (project != null) {
|
||||
List<ProjectPlanningTime> plannings =
|
||||
planningTimeRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.project = ?1 OR (self.project.parentProject = ?1 AND self.project.parentProject.isShowPhasesElements = ?2)",
|
||||
project,
|
||||
true)
|
||||
.fetch();
|
||||
if (plannings != null) {
|
||||
totalPlanned =
|
||||
plannings
|
||||
.stream()
|
||||
.map(ProjectPlanningTime::getPlannedHours)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
}
|
||||
|
||||
return totalPlanned;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void addMultipleProjectPlanningTime(Map<String, Object> datas) throws AxelorException {
|
||||
|
||||
if (datas.get("project") == null
|
||||
|| datas.get("user") == null
|
||||
|| datas.get("fromDate") == null
|
||||
|| datas.get("toDate") == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
|
||||
|
||||
LocalDateTime fromDate = LocalDateTime.parse(datas.get("fromDate").toString(), formatter);
|
||||
LocalDateTime toDate = LocalDateTime.parse(datas.get("toDate").toString(), formatter);
|
||||
|
||||
TeamTask teamTask = null;
|
||||
|
||||
Map<String, Object> objMap = (Map) datas.get("project");
|
||||
Project project = projectRepo.find(Long.parseLong(objMap.get("id").toString()));
|
||||
Integer timePercent = 0;
|
||||
|
||||
if (datas.get("timepercent") != null) {
|
||||
timePercent = Integer.parseInt(datas.get("timepercent").toString());
|
||||
}
|
||||
|
||||
objMap = (Map) datas.get("user");
|
||||
User user = userRepo.find(Long.parseLong(objMap.get("id").toString()));
|
||||
|
||||
if (user.getEmployee() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (datas.get("task") != null) {
|
||||
objMap = (Map) datas.get("task");
|
||||
teamTask = teamTaskRepo.find(Long.valueOf(objMap.get("id").toString()));
|
||||
}
|
||||
|
||||
Product activity = null;
|
||||
if (datas.get("product") != null) {
|
||||
objMap = (Map) datas.get("product");
|
||||
activity = productRepo.find(Long.valueOf(objMap.get("id").toString()));
|
||||
}
|
||||
|
||||
Employee employee = user.getEmployee();
|
||||
BigDecimal dailyWorkHrs = employee.getDailyWorkHours();
|
||||
|
||||
while (fromDate.isBefore(toDate)) {
|
||||
|
||||
LocalDate date = fromDate.toLocalDate();
|
||||
|
||||
LOG.debug("Create Planning for the date: {}", date);
|
||||
|
||||
double dayHrs = 0;
|
||||
if (employee.getWeeklyPlanning() != null) {
|
||||
dayHrs = weeklyPlanningService.getWorkingDayValueInDays(employee.getWeeklyPlanning(), date);
|
||||
}
|
||||
|
||||
if (dayHrs > 0 && !holidayService.checkPublicHolidayDay(date, employee)) {
|
||||
|
||||
ProjectPlanningTime planningTime = new ProjectPlanningTime();
|
||||
|
||||
planningTime.setTask(teamTask);
|
||||
planningTime.setProduct(activity);
|
||||
planningTime.setTimepercent(timePercent);
|
||||
planningTime.setUser(user);
|
||||
planningTime.setDate(date);
|
||||
planningTime.setProject(project);
|
||||
planningTime.setIsIncludeInTurnoverForecast(
|
||||
(Boolean) datas.get("isIncludeInTurnoverForecast"));
|
||||
|
||||
BigDecimal totalHours = BigDecimal.ZERO;
|
||||
if (timePercent > 0) {
|
||||
totalHours =
|
||||
dailyWorkHrs.multiply(new BigDecimal(timePercent)).divide(new BigDecimal(100));
|
||||
}
|
||||
planningTime.setPlannedHours(totalHours);
|
||||
planningTimeRepo.save(planningTime);
|
||||
}
|
||||
|
||||
fromDate = fromDate.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeProjectPlanningLines(List<Map<String, Object>> projectPlanningLines) {
|
||||
|
||||
for (Map<String, Object> line : projectPlanningLines) {
|
||||
ProjectPlanningTime projectPlanningTime =
|
||||
planningTimeRepo.find(Long.parseLong(line.get("id").toString()));
|
||||
planningTimeRepo.remove(projectPlanningTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.publicHoliday;
|
||||
|
||||
import com.axelor.apps.base.db.EventsPlanning;
|
||||
import com.axelor.apps.base.db.EventsPlanningLine;
|
||||
import com.axelor.apps.base.db.repo.EventsPlanningLineRepository;
|
||||
import com.axelor.apps.base.service.publicHoliday.PublicHolidayService;
|
||||
import com.axelor.apps.base.service.weeklyplanning.WeeklyPlanningService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.google.inject.Inject;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public class PublicHolidayHrService extends PublicHolidayService {
|
||||
|
||||
@Inject
|
||||
public PublicHolidayHrService(
|
||||
WeeklyPlanningService weeklyPlanningService,
|
||||
EventsPlanningLineRepository eventsPlanningLineRepo) {
|
||||
super(weeklyPlanningService, eventsPlanningLineRepo);
|
||||
}
|
||||
|
||||
public boolean checkPublicHolidayDay(LocalDate date, Employee employee) {
|
||||
return super.checkPublicHolidayDay(date, employee.getPublicHolidayEventsPlanning());
|
||||
}
|
||||
|
||||
public int getImposedDayNumber(Employee employee, LocalDate startDate, LocalDate endDate) {
|
||||
|
||||
EventsPlanning imposedDays = employee.getImposedDayEventsPlanning();
|
||||
|
||||
if (imposedDays == null
|
||||
|| imposedDays.getEventsPlanningLineList() == null
|
||||
|| imposedDays.getEventsPlanningLineList().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<EventsPlanningLine> imposedDayList =
|
||||
eventsPlanningLineRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.eventsPlanning = ?1 AND self.date BETWEEN ?2 AND ?3",
|
||||
imposedDays,
|
||||
startDate,
|
||||
endDate)
|
||||
.fetch();
|
||||
|
||||
return imposedDayList.size();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.timesheet;
|
||||
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface TimesheetLineService {
|
||||
|
||||
/**
|
||||
* Compute duration from hours or to hours.
|
||||
*
|
||||
* @param timesheet a timesheet containing the time preference.
|
||||
* @param duration the duration to be converted.
|
||||
* @param toHours if we convert the duration to hours, or if we convert from hours.
|
||||
* @return the computed duration.
|
||||
* @throws AxelorException
|
||||
*/
|
||||
BigDecimal computeHoursDuration(Timesheet timesheet, BigDecimal duration, boolean toHours)
|
||||
throws AxelorException;
|
||||
|
||||
/**
|
||||
* Compute duration from hours or to hours.
|
||||
*
|
||||
* @param timePref a select containing the type of the duration. Can be minute, hours or days.
|
||||
* @param duration the duration to be converted
|
||||
* @param dailyWorkHrs The hours of work during a day.
|
||||
* @param toHours if we convert the duration to hours, or if we convert from hours.
|
||||
* @return the computed duration.
|
||||
* @throws AxelorException
|
||||
*/
|
||||
BigDecimal computeHoursDuration(
|
||||
String timePref, BigDecimal duration, BigDecimal dailyWorkHrs, boolean toHours)
|
||||
throws AxelorException;
|
||||
|
||||
/**
|
||||
* Creates a timesheet line.
|
||||
*
|
||||
* @param project
|
||||
* @param product
|
||||
* @param user
|
||||
* @param date
|
||||
* @param timesheet
|
||||
* @param hours
|
||||
* @param comments
|
||||
* @return the created timesheet line.
|
||||
*/
|
||||
TimesheetLine createTimesheetLine(
|
||||
Project project,
|
||||
Product product,
|
||||
User user,
|
||||
LocalDate date,
|
||||
Timesheet timesheet,
|
||||
BigDecimal hours,
|
||||
String comments);
|
||||
|
||||
/**
|
||||
* Creates a timesheet line without project and product. Used to generate timesheet lines for
|
||||
* holidays or day leaves.
|
||||
*
|
||||
* @param user
|
||||
* @param date
|
||||
* @param timesheet
|
||||
* @param hours
|
||||
* @param comments
|
||||
* @return the created timesheet line.
|
||||
*/
|
||||
TimesheetLine createTimesheetLine(
|
||||
User user, LocalDate date, Timesheet timesheet, BigDecimal hours, String comments);
|
||||
|
||||
TimesheetLine updateTimesheetLine(
|
||||
TimesheetLine timesheetLine,
|
||||
Project project,
|
||||
Product product,
|
||||
User user,
|
||||
LocalDate date,
|
||||
Timesheet timesheet,
|
||||
BigDecimal hours,
|
||||
String comments);
|
||||
|
||||
/**
|
||||
* Compute the total duration of timesheet lines. Add each duration only if the timesheet is
|
||||
* validated or confirmed.
|
||||
*
|
||||
* @param timesheetLineList a list of timesheet lines.
|
||||
* @return a {@link java.time.Duration}.
|
||||
*/
|
||||
Duration computeTotalDuration(List<TimesheetLine> timesheetLineList);
|
||||
|
||||
/**
|
||||
* Calculates time spent on the project base on timesheet lines for the validated {@link
|
||||
* Timesheet}.
|
||||
*
|
||||
* @param timesheetLineList
|
||||
* @return {@link Map}
|
||||
*/
|
||||
Map<Project, BigDecimal> getProjectTimeSpentMap(List<TimesheetLine> timesheetLineList);
|
||||
}
|
||||
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.timesheet;
|
||||
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetHRRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TimesheetLineServiceImpl implements TimesheetLineService {
|
||||
|
||||
@Inject private TimesheetService timesheetService;
|
||||
|
||||
@Inject private TimesheetHRRepository timesheetHRRepository;
|
||||
|
||||
@Inject private TimesheetRepository timesheetRepository;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Override
|
||||
public BigDecimal computeHoursDuration(Timesheet timesheet, BigDecimal duration, boolean toHours)
|
||||
throws AxelorException {
|
||||
if (duration == null) {
|
||||
return null;
|
||||
}
|
||||
AppBaseService appBaseService = Beans.get(AppBaseService.class);
|
||||
BigDecimal dailyWorkHrs;
|
||||
String timePref;
|
||||
|
||||
log.debug(
|
||||
"Get user duration for duration: {}, timesheet: {}",
|
||||
duration,
|
||||
timesheet == null ? "null" : timesheet.getFullName());
|
||||
|
||||
if (timesheet != null) {
|
||||
User user = timesheet.getUser();
|
||||
|
||||
Employee employee = user.getEmployee();
|
||||
|
||||
log.debug("Employee: {}", employee);
|
||||
|
||||
timePref = timesheet.getTimeLoggingPreferenceSelect();
|
||||
|
||||
if (employee != null) {
|
||||
dailyWorkHrs = employee.getDailyWorkHours();
|
||||
if (timePref == null) {
|
||||
timePref = employee.getTimeLoggingPreferenceSelect();
|
||||
}
|
||||
} else {
|
||||
dailyWorkHrs = appBaseService.getAppBase().getDailyWorkHours();
|
||||
}
|
||||
} else {
|
||||
timePref = appBaseService.getAppBase().getTimeLoggingPreferenceSelect();
|
||||
dailyWorkHrs = appBaseService.getAppBase().getDailyWorkHours();
|
||||
}
|
||||
|
||||
return computeHoursDuration(timePref, duration, dailyWorkHrs, toHours);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal computeHoursDuration(
|
||||
String timePref, BigDecimal duration, BigDecimal dailyWorkHrs, boolean toHours)
|
||||
throws AxelorException {
|
||||
log.debug("Timesheet time pref: {}, Daily Working hours: {}", timePref, dailyWorkHrs);
|
||||
if (timePref == null) {
|
||||
return duration;
|
||||
}
|
||||
if (toHours) {
|
||||
duration = computeDurationToHours(timePref, duration, dailyWorkHrs);
|
||||
} else {
|
||||
duration = computeDurationFromHours(timePref, duration, dailyWorkHrs);
|
||||
}
|
||||
log.debug("Calculated duration: {}", duration);
|
||||
return duration;
|
||||
}
|
||||
|
||||
protected BigDecimal computeDurationToHours(
|
||||
String timePref, BigDecimal duration, BigDecimal dailyWorkHrs) throws AxelorException {
|
||||
switch (timePref) {
|
||||
case EmployeeRepository.TIME_PREFERENCE_DAYS:
|
||||
if (dailyWorkHrs.compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.TIMESHEET_DAILY_WORK_HOURS));
|
||||
}
|
||||
return duration.multiply(dailyWorkHrs);
|
||||
case EmployeeRepository.TIME_PREFERENCE_MINUTES:
|
||||
return duration.divide(new BigDecimal(60), 2, RoundingMode.HALF_UP);
|
||||
default:
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
|
||||
protected BigDecimal computeDurationFromHours(
|
||||
String timePref, BigDecimal duration, BigDecimal dailyWorkHrs) throws AxelorException {
|
||||
switch (timePref) {
|
||||
case EmployeeRepository.TIME_PREFERENCE_DAYS:
|
||||
if (dailyWorkHrs.compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.TIMESHEET_DAILY_WORK_HOURS));
|
||||
}
|
||||
return duration.divide(dailyWorkHrs, 2, RoundingMode.HALF_UP);
|
||||
case EmployeeRepository.TIME_PREFERENCE_MINUTES:
|
||||
return duration.multiply(new BigDecimal(60));
|
||||
default:
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimesheetLine createTimesheetLine(
|
||||
Project project,
|
||||
Product product,
|
||||
User user,
|
||||
LocalDate date,
|
||||
Timesheet timesheet,
|
||||
BigDecimal hours,
|
||||
String comments) {
|
||||
|
||||
TimesheetLine timesheetLine = new TimesheetLine();
|
||||
|
||||
timesheetLine.setDate(date);
|
||||
timesheetLine.setComments(comments);
|
||||
timesheetLine.setProduct(product);
|
||||
timesheetLine.setProject(project);
|
||||
timesheetLine.setUser(user);
|
||||
timesheetLine.setHoursDuration(hours);
|
||||
try {
|
||||
timesheetLine.setDuration(computeHoursDuration(timesheet, hours, false));
|
||||
} catch (AxelorException e) {
|
||||
log.error(e.getLocalizedMessage());
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
timesheet.addTimesheetLineListItem(timesheetLine);
|
||||
|
||||
return timesheetLine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimesheetLine createTimesheetLine(
|
||||
User user, LocalDate date, Timesheet timesheet, BigDecimal hours, String comments) {
|
||||
return createTimesheetLine(null, null, user, date, timesheet, hours, comments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimesheetLine updateTimesheetLine(
|
||||
TimesheetLine timesheetLine,
|
||||
Project project,
|
||||
Product product,
|
||||
User user,
|
||||
LocalDate date,
|
||||
Timesheet timesheet,
|
||||
BigDecimal hours,
|
||||
String comments) {
|
||||
|
||||
timesheetLine.setDate(date);
|
||||
timesheetLine.setComments(comments);
|
||||
timesheetLine.setProduct(product);
|
||||
timesheetLine.setProject(project);
|
||||
timesheetLine.setUser(user);
|
||||
timesheetLine.setHoursDuration(hours);
|
||||
try {
|
||||
timesheetLine.setDuration(computeHoursDuration(timesheet, hours, false));
|
||||
} catch (AxelorException e) {
|
||||
log.error(e.getLocalizedMessage());
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
timesheet.addTimesheetLineListItem(timesheetLine);
|
||||
|
||||
return timesheetLine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration computeTotalDuration(List<TimesheetLine> timesheetLineList) {
|
||||
if (timesheetLineList == null || timesheetLineList.isEmpty()) {
|
||||
return Duration.ZERO;
|
||||
}
|
||||
long totalSecDuration = 0L;
|
||||
for (TimesheetLine timesheetLine : timesheetLineList) {
|
||||
// if null, that means the timesheet line is just created so the parent is not canceled.
|
||||
if (timesheetLine.getTimesheet() == null
|
||||
|| timesheetLine.getTimesheet().getStatusSelect()
|
||||
!= TimesheetRepository.STATUS_CANCELED) {
|
||||
totalSecDuration +=
|
||||
timesheetLine.getHoursDuration().multiply(new BigDecimal("3600")).longValue();
|
||||
}
|
||||
}
|
||||
return Duration.ofSeconds(totalSecDuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Project, BigDecimal> getProjectTimeSpentMap(List<TimesheetLine> timesheetLineList) {
|
||||
Map<Project, BigDecimal> projectTimeSpentMap = new HashMap<>();
|
||||
|
||||
if (timesheetLineList != null) {
|
||||
|
||||
for (TimesheetLine timesheetLine : timesheetLineList) {
|
||||
Project project = timesheetLine.getProject();
|
||||
BigDecimal hoursDuration = timesheetLine.getHoursDuration();
|
||||
|
||||
if (project != null) {
|
||||
if (projectTimeSpentMap.containsKey(project)) {
|
||||
hoursDuration = hoursDuration.add(projectTimeSpentMap.get(project));
|
||||
}
|
||||
projectTimeSpentMap.put(project, hoursDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return projectTimeSpentMap;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public TimesheetLine setTimesheet(TimesheetLine timesheetLine) {
|
||||
Timesheet timesheet =
|
||||
timesheetRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ?1 AND self.company = ?2 AND (self.statusSelect = 1 OR self.statusSelect = 2) AND ((?3 BETWEEN self.fromDate AND self.toDate) OR (self.toDate = null)) ORDER BY self.id ASC",
|
||||
timesheetLine.getUser(),
|
||||
timesheetLine.getProject().getCompany(),
|
||||
timesheetLine.getDate())
|
||||
.fetchOne();
|
||||
if (timesheet == null) {
|
||||
Timesheet lastTimesheet =
|
||||
timesheetRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ?1 AND self.statusSelect != ?2 ORDER BY self.toDate DESC",
|
||||
timesheetLine.getUser(),
|
||||
TimesheetRepository.STATUS_CANCELED)
|
||||
.fetchOne();
|
||||
timesheet =
|
||||
timesheetService.createTimesheet(
|
||||
timesheetLine.getUser(),
|
||||
lastTimesheet != null && lastTimesheet.getToDate() != null
|
||||
? lastTimesheet.getToDate().plusDays(1)
|
||||
: timesheetLine.getDate(),
|
||||
null);
|
||||
timesheet = timesheetHRRepository.save(timesheet);
|
||||
}
|
||||
timesheetLine.setTimesheet(timesheet);
|
||||
return timesheetLine;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.timesheet;
|
||||
|
||||
import com.axelor.apps.hr.db.TimesheetReport;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface TimesheetReportService {
|
||||
|
||||
static TimesheetReportService getInstance() {
|
||||
return Beans.get(TimesheetReportService.class);
|
||||
}
|
||||
|
||||
Set<User> getUserToBeReminded(TimesheetReport timesheetReport);
|
||||
|
||||
List<Message> sendReminders(TimesheetReport timesheetReport) throws AxelorException;
|
||||
|
||||
List<Map<String, Object>> getTimesheetReportList(String TimesheetReportId);
|
||||
}
|
||||
@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.timesheet;
|
||||
|
||||
import com.axelor.apps.base.db.DayPlanning;
|
||||
import com.axelor.apps.base.db.WeeklyPlanning;
|
||||
import com.axelor.apps.base.service.publicHoliday.PublicHolidayService;
|
||||
import com.axelor.apps.base.service.weeklyplanning.WeeklyPlanningService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.LeaveRequest;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.hr.db.TimesheetReminder;
|
||||
import com.axelor.apps.hr.db.TimesheetReminderLine;
|
||||
import com.axelor.apps.hr.db.TimesheetReport;
|
||||
import com.axelor.apps.hr.db.repo.ExtraHoursLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExtraHoursRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetReminderRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetReportRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.app.AppHumanResourceService;
|
||||
import com.axelor.apps.hr.service.employee.EmployeeService;
|
||||
import com.axelor.apps.hr.service.leave.LeaveService;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.apps.message.db.Template;
|
||||
import com.axelor.apps.message.service.MessageService;
|
||||
import com.axelor.apps.message.service.TemplateMessageService;
|
||||
import com.axelor.apps.tool.QueryBuilder;
|
||||
import com.axelor.apps.tool.date.DateTool;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
public class TimesheetReportServiceImpl implements TimesheetReportService {
|
||||
|
||||
protected TimesheetReminderRepository timesheetReminderRepo;
|
||||
protected TimesheetReportRepository timesheetReportRepository;
|
||||
protected ExtraHoursLineRepository extraHoursLineRepository;
|
||||
protected TimesheetLineRepository timesheetLineRepository;
|
||||
|
||||
protected MessageService messageService;
|
||||
protected TemplateMessageService templateMessageService;
|
||||
protected PublicHolidayService publicHolidayService;
|
||||
protected WeeklyPlanningService weeklyPlanningService;
|
||||
protected EmployeeService employeeService;
|
||||
protected TimesheetLineService timesheetLineService;
|
||||
protected LeaveService leaveService;
|
||||
|
||||
@Inject
|
||||
public TimesheetReportServiceImpl(
|
||||
TimesheetReminderRepository timesheetReminderRepo,
|
||||
TimesheetReportRepository timesheetReportRepository,
|
||||
ExtraHoursLineRepository extraHoursLineRepository,
|
||||
TimesheetLineRepository timesheetLineRepository,
|
||||
MessageService messageService,
|
||||
TemplateMessageService templateMessageService,
|
||||
PublicHolidayService publicHolidayService,
|
||||
WeeklyPlanningService weeklyPlanningService,
|
||||
EmployeeService employeeService,
|
||||
TimesheetLineService timesheetLineService,
|
||||
LeaveService leaveService) {
|
||||
this.timesheetReminderRepo = timesheetReminderRepo;
|
||||
this.timesheetReportRepository = timesheetReportRepository;
|
||||
this.extraHoursLineRepository = extraHoursLineRepository;
|
||||
this.timesheetLineRepository = timesheetLineRepository;
|
||||
|
||||
this.messageService = messageService;
|
||||
this.templateMessageService = templateMessageService;
|
||||
this.publicHolidayService = publicHolidayService;
|
||||
this.weeklyPlanningService = weeklyPlanningService;
|
||||
this.employeeService = employeeService;
|
||||
this.timesheetLineService = timesheetLineService;
|
||||
this.leaveService = leaveService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<User> getUserToBeReminded(TimesheetReport timesheetReport) {
|
||||
Set<User> userSet = new HashSet<>();
|
||||
BigDecimal worksHour = BigDecimal.ZERO, workedHour = BigDecimal.ZERO;
|
||||
|
||||
List<User> users = getUsers(timesheetReport);
|
||||
LocalDate fromDate = timesheetReport.getFromDate();
|
||||
LocalDate toDate = timesheetReport.getToDate();
|
||||
|
||||
for (User user : users) {
|
||||
Employee employee = user.getEmployee();
|
||||
try {
|
||||
worksHour = workedHour = BigDecimal.ZERO;
|
||||
BigDecimal publicHolidays =
|
||||
publicHolidayService.computePublicHolidayDays(
|
||||
fromDate,
|
||||
toDate,
|
||||
employee.getWeeklyPlanning(),
|
||||
employee.getPublicHolidayEventsPlanning());
|
||||
worksHour = getTotalWeekWorksHours(user, fromDate, toDate, publicHolidays);
|
||||
workedHour = getTotalWeekWorkedHours(user, fromDate, toDate, publicHolidays);
|
||||
if (worksHour.compareTo(workedHour) != 0) {
|
||||
userSet.add(user);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
}
|
||||
return userSet;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Message> sendReminders(TimesheetReport timesheetReport) throws AxelorException {
|
||||
|
||||
Template reminderTemplate =
|
||||
Beans.get(AppHumanResourceService.class).getAppTimesheet().getTimesheetReminderTemplate();
|
||||
if (reminderTemplate == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_NO_VALUE,
|
||||
I18n.get(IExceptionMessage.EMPLOYEE_TIMESHEET_REMINDER_TEMPLATE));
|
||||
}
|
||||
List<TimesheetReminder> timesheetReminders = getTimesheetReminderList(timesheetReport);
|
||||
return sendEmailMessage(timesheetReminders, reminderTemplate);
|
||||
}
|
||||
|
||||
private List<TimesheetReminder> getTimesheetReminderList(TimesheetReport timesheetReport) {
|
||||
List<TimesheetReminder> timesheetReminders = new ArrayList<>();
|
||||
|
||||
List<User> users = new ArrayList<>(timesheetReport.getReminderUserSet());
|
||||
try {
|
||||
addTimesheetReminder(timesheetReport, users, timesheetReminders);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
return timesheetReminders;
|
||||
}
|
||||
|
||||
private void addTimesheetReminder(
|
||||
TimesheetReport timesheetReport, List<User> users, List<TimesheetReminder> timesheetReminders)
|
||||
throws AxelorException {
|
||||
BigDecimal worksHour = BigDecimal.ZERO,
|
||||
workedHour = BigDecimal.ZERO,
|
||||
missingHour = BigDecimal.ZERO,
|
||||
extraHour = BigDecimal.ZERO;
|
||||
LocalDate fromDate = timesheetReport.getFromDate();
|
||||
LocalDate toDate = null;
|
||||
do {
|
||||
toDate = fromDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
|
||||
if (toDate.until(timesheetReport.getToDate()).getDays() < 0) {
|
||||
toDate = timesheetReport.getToDate();
|
||||
}
|
||||
|
||||
for (User user : users) {
|
||||
Employee employee = user.getEmployee();
|
||||
missingHour = BigDecimal.ZERO;
|
||||
extraHour = BigDecimal.ZERO;
|
||||
|
||||
BigDecimal publicHolidays =
|
||||
publicHolidayService.computePublicHolidayDays(
|
||||
fromDate,
|
||||
toDate,
|
||||
employee.getWeeklyPlanning(),
|
||||
employee.getPublicHolidayEventsPlanning());
|
||||
|
||||
worksHour = getTotalWeekWorksHours(user, fromDate, toDate, publicHolidays);
|
||||
|
||||
workedHour = getTotalWeekWorkedHours(user, fromDate, toDate, publicHolidays);
|
||||
if (worksHour.compareTo(workedHour) == 1) {
|
||||
missingHour = worksHour.subtract(workedHour);
|
||||
} else if (worksHour.compareTo(workedHour) == -1) {
|
||||
extraHour = workedHour.subtract(worksHour);
|
||||
}
|
||||
|
||||
if (missingHour.compareTo(BigDecimal.ZERO) == 0
|
||||
&& extraHour.compareTo(BigDecimal.ZERO) == 0) {
|
||||
continue;
|
||||
}
|
||||
Optional<TimesheetReminder> optReminder =
|
||||
timesheetReminders
|
||||
.stream()
|
||||
.filter(reminder -> reminder.getEmployee().getId().compareTo(employee.getId()) == 0)
|
||||
.findFirst();
|
||||
|
||||
TimesheetReminder timesheetReminder = null;
|
||||
if (optReminder.isPresent()) {
|
||||
timesheetReminder = optReminder.get();
|
||||
timesheetReminder.addTimesheetReminderLineListItem(
|
||||
createTimesheetReminderLine(fromDate, toDate, worksHour, missingHour, extraHour));
|
||||
} else {
|
||||
List<TimesheetReminderLine> timesheetReminderLines = new ArrayList<>();
|
||||
timesheetReminder = new TimesheetReminder();
|
||||
timesheetReminder.setEmployee(employee);
|
||||
timesheetReminder.setTimesheetReminderLineList(timesheetReminderLines);
|
||||
timesheetReminder.addTimesheetReminderLineListItem(
|
||||
createTimesheetReminderLine(fromDate, toDate, worksHour, missingHour, extraHour));
|
||||
timesheetReminders.add(timesheetReminder);
|
||||
}
|
||||
timesheetReminderRepo.save(timesheetReminder);
|
||||
}
|
||||
fromDate = fromDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
|
||||
} while (toDate.until(timesheetReport.getToDate()).getDays() > 0);
|
||||
}
|
||||
|
||||
private List<Message> sendEmailMessage(
|
||||
List<TimesheetReminder> timesheetReminders, Template reminderTemplate) {
|
||||
|
||||
List<Message> messages = new ArrayList<>();
|
||||
for (TimesheetReminder timesheetReminder : timesheetReminders) {
|
||||
try {
|
||||
Message message =
|
||||
templateMessageService.generateMessage(timesheetReminder, reminderTemplate);
|
||||
message = messageService.sendMessage(message);
|
||||
timesheetReminder.setEmailSentDateT(LocalDateTime.now());
|
||||
messages.add(message);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
private TimesheetReminderLine createTimesheetReminderLine(
|
||||
LocalDate fromDate,
|
||||
LocalDate toDate,
|
||||
BigDecimal worksHour,
|
||||
BigDecimal missingHour,
|
||||
BigDecimal extraHour) {
|
||||
TimesheetReminderLine line = new TimesheetReminderLine();
|
||||
line.setFromDate(fromDate);
|
||||
line.setToDate(toDate);
|
||||
line.setRequiredHours(worksHour);
|
||||
line.setExtraHours(extraHour);
|
||||
line.setMissingHours(missingHour);
|
||||
line.setWorkHour(worksHour.subtract(missingHour).add(extraHour));
|
||||
return line;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getTimesheetReportList(String TimesheetReportId) {
|
||||
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 5);
|
||||
|
||||
TimesheetReport timesheetReport =
|
||||
timesheetReportRepository.find(Long.parseLong(TimesheetReportId.toString()));
|
||||
int numOfDays = timesheetReport.getFromDate().until(timesheetReport.getToDate()).getDays();
|
||||
List<LocalDate> daysRange =
|
||||
Stream.iterate(timesheetReport.getFromDate(), date -> date.plusDays(1))
|
||||
.limit(numOfDays + 1)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<User> users = getUsers(timesheetReport);
|
||||
|
||||
for (User user : users) {
|
||||
Employee employee = user.getEmployee();
|
||||
BigDecimal dailyWorkingHours = employee.getDailyWorkHours();
|
||||
WeeklyPlanning planning = employee.getWeeklyPlanning();
|
||||
|
||||
Integer weekNumber = 1;
|
||||
int lastDayNumber = -1;
|
||||
try {
|
||||
for (LocalDate date : daysRange) {
|
||||
DayPlanning dayPlanning =
|
||||
Beans.get(WeeklyPlanningService.class).findDayPlanning(planning, date);
|
||||
if (dayPlanning == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int dayIndex = date.get(weekFields.dayOfWeek()) - 1;
|
||||
if (lastDayNumber < dayIndex) {
|
||||
lastDayNumber = dayIndex;
|
||||
} else {
|
||||
lastDayNumber = -1;
|
||||
weekNumber++;
|
||||
}
|
||||
BigDecimal weeklyWorkHours =
|
||||
employee
|
||||
.getWeeklyWorkHours()
|
||||
.multiply(BigDecimal.valueOf((dayIndex) / 6.0))
|
||||
.setScale(2, RoundingMode.HALF_EVEN);
|
||||
Map<String, Object> map = getTimesheetMap(user, date, dailyWorkingHours);
|
||||
map.put("weeklyWorkHours", weeklyWorkHours);
|
||||
map.put("weekNumber", weekNumber.toString());
|
||||
list.add(map);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private Map<String, Object> getTimesheetMap(
|
||||
User user, LocalDate date, BigDecimal dailyWorkingHours) throws AxelorException {
|
||||
Employee employee = user.getEmployee();
|
||||
BigDecimal worksHour = BigDecimal.ZERO, workedHour = BigDecimal.ZERO;
|
||||
|
||||
boolean isPublicHoliday =
|
||||
publicHolidayService.checkPublicHolidayDay(date, employee.getPublicHolidayEventsPlanning());
|
||||
worksHour = getTotalWorksHours(user, date, isPublicHoliday, dailyWorkingHours);
|
||||
|
||||
try {
|
||||
workedHour = getTotalWorkedHours(user, date, isPublicHoliday, dailyWorkingHours);
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("userName", user.getFullName());
|
||||
map.put("date", DateTool.toDate(date));
|
||||
map.put("workedHour", workedHour);
|
||||
map.put("workingHour", worksHour);
|
||||
return map;
|
||||
}
|
||||
|
||||
private BigDecimal getTotalWorksHours(
|
||||
User user, LocalDate date, boolean isPublicHoliday, BigDecimal dailyWorkingHours)
|
||||
throws AxelorException {
|
||||
Employee employee = user.getEmployee();
|
||||
BigDecimal worksHour =
|
||||
employeeService
|
||||
.getDaysWorksInPeriod(employee, date, date)
|
||||
.multiply(employee.getDailyWorkHours());
|
||||
if (isPublicHoliday) {
|
||||
worksHour = worksHour.add(dailyWorkingHours);
|
||||
}
|
||||
double extraHours =
|
||||
extraHoursLineRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ? AND self.date = ? AND (self.extraHours.statusSelect = ? OR self.extraHours.statusSelect = ?)",
|
||||
user,
|
||||
date,
|
||||
ExtraHoursRepository.STATUS_VALIDATED,
|
||||
ExtraHoursRepository.STATUS_CONFIRMED)
|
||||
.fetchStream()
|
||||
.mapToDouble(ehl -> Double.parseDouble(ehl.getQty().toString()))
|
||||
.sum();
|
||||
worksHour = worksHour.add(new BigDecimal(extraHours));
|
||||
return worksHour;
|
||||
}
|
||||
|
||||
private BigDecimal getTotalWeekWorksHours(
|
||||
User user, LocalDate fromDate, LocalDate toDate, BigDecimal publicHolidays)
|
||||
throws AxelorException {
|
||||
Employee employee = user.getEmployee();
|
||||
BigDecimal worksHour =
|
||||
employeeService
|
||||
.getDaysWorksInPeriod(employee, fromDate, toDate)
|
||||
.multiply(employee.getDailyWorkHours());
|
||||
worksHour = worksHour.add(publicHolidays.multiply(employee.getDailyWorkHours()));
|
||||
double extraHours =
|
||||
extraHoursLineRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ? AND (self.date BETWEEN ? AND ?) AND (self.extraHours.statusSelect = ? OR self.extraHours.statusSelect = ?)",
|
||||
user,
|
||||
fromDate,
|
||||
toDate,
|
||||
ExtraHoursRepository.STATUS_VALIDATED,
|
||||
ExtraHoursRepository.STATUS_CONFIRMED)
|
||||
.fetchStream()
|
||||
.mapToDouble(ehl -> Double.parseDouble(ehl.getQty().toString()))
|
||||
.sum();
|
||||
worksHour = worksHour.add(new BigDecimal(extraHours));
|
||||
return worksHour;
|
||||
}
|
||||
|
||||
private BigDecimal getTotalWorkedHours(
|
||||
User user, LocalDate date, boolean isPublicHoliday, BigDecimal dailyWorkingHours)
|
||||
throws AxelorException {
|
||||
BigDecimal totalHours = BigDecimal.ZERO;
|
||||
|
||||
List<TimesheetLine> timesheetLineList =
|
||||
timesheetLineRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ? AND self.date = ? AND (self.timesheet.statusSelect = ? OR self.timesheet.statusSelect = ?)",
|
||||
user,
|
||||
date,
|
||||
TimesheetRepository.STATUS_CONFIRMED,
|
||||
TimesheetRepository.STATUS_VALIDATED)
|
||||
.fetch();
|
||||
|
||||
Duration totalDuration = timesheetLineService.computeTotalDuration(timesheetLineList);
|
||||
totalHours = new BigDecimal(totalDuration.getSeconds()).divide(BigDecimal.valueOf(3600));
|
||||
|
||||
if (isPublicHoliday) {
|
||||
totalHours = totalHours.add(dailyWorkingHours);
|
||||
} else {
|
||||
totalHours = totalHours.add(getLeaveHours(user, date, dailyWorkingHours));
|
||||
}
|
||||
|
||||
return totalHours;
|
||||
}
|
||||
|
||||
private BigDecimal getTotalWeekWorkedHours(
|
||||
User user, LocalDate fromDate, LocalDate toDate, BigDecimal publicHolidays)
|
||||
throws AxelorException {
|
||||
BigDecimal totalHours = BigDecimal.ZERO;
|
||||
Employee employee = user.getEmployee();
|
||||
|
||||
List<TimesheetLine> timesheetLineList =
|
||||
timesheetLineRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ? AND (self.date BETWEEN ? AND ?) AND (self.timesheet.statusSelect = ? OR self.timesheet.statusSelect = ?)",
|
||||
user,
|
||||
fromDate,
|
||||
toDate,
|
||||
TimesheetRepository.STATUS_VALIDATED,
|
||||
TimesheetRepository.STATUS_CONFIRMED)
|
||||
.fetch();
|
||||
|
||||
Duration totalDuration = timesheetLineService.computeTotalDuration(timesheetLineList);
|
||||
totalHours = new BigDecimal(totalDuration.toHours());
|
||||
totalHours = totalHours.add(publicHolidays.multiply(employee.getDailyWorkHours()));
|
||||
totalHours =
|
||||
totalHours.add(getWeekLeaveHours(user, fromDate, toDate, employee.getDailyWorkHours()));
|
||||
|
||||
return totalHours;
|
||||
}
|
||||
|
||||
private BigDecimal getLeaveHours(User user, LocalDate date, BigDecimal dailyWorkingHours)
|
||||
throws AxelorException {
|
||||
LeaveRequest leave = leaveService.getLeave(user, date);
|
||||
if (leave != null) {
|
||||
return leaveService.computeDuration(leave, date, date).multiply(dailyWorkingHours);
|
||||
}
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
private BigDecimal getWeekLeaveHours(
|
||||
User user, LocalDate fromDate, LocalDate toDate, BigDecimal dailyWorkingHours)
|
||||
throws AxelorException {
|
||||
BigDecimal leaveHours = BigDecimal.ZERO;
|
||||
do {
|
||||
LeaveRequest leave = leaveService.getLeave(user, fromDate);
|
||||
if (leave != null) {
|
||||
|
||||
boolean isPublicHoliday =
|
||||
publicHolidayService.checkPublicHolidayDay(
|
||||
fromDate, user.getEmployee().getPublicHolidayEventsPlanning());
|
||||
if (!isPublicHoliday) {
|
||||
leaveHours =
|
||||
leaveHours.add(
|
||||
leaveService
|
||||
.computeDuration(leave, fromDate, fromDate)
|
||||
.multiply(dailyWorkingHours));
|
||||
}
|
||||
}
|
||||
fromDate = fromDate.plusDays(1);
|
||||
} while (fromDate.until(toDate).getDays() > -1);
|
||||
return leaveHours;
|
||||
}
|
||||
|
||||
protected List<User> getUsers(TimesheetReport timesheetReport) {
|
||||
QueryBuilder<User> userQuery = QueryBuilder.of(User.class);
|
||||
userQuery.add(
|
||||
"self.employee IS NOT NULL AND self.employee.weeklyPlanning IS NOT NULL AND self.employee.publicHolidayEventsPlanning IS NOT NULL AND self.employee.mainEmploymentContract IS NOT NULL");
|
||||
if (!CollectionUtils.isEmpty(timesheetReport.getUserSet())) {
|
||||
userQuery.add("self IN :users");
|
||||
userQuery.bind("users", timesheetReport.getUserSet());
|
||||
}
|
||||
return userQuery.build().fetch();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.timesheet;
|
||||
|
||||
import com.axelor.apps.account.db.Invoice;
|
||||
import com.axelor.apps.account.db.InvoiceLine;
|
||||
import com.axelor.apps.base.db.PriceList;
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.apps.project.db.Project;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
public interface TimesheetService {
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void confirm(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
public Message sendConfirmationEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public Message confirmAndSendConfirmationEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
/**
|
||||
* Checks that there is a line for each working day of the timesheet.
|
||||
*
|
||||
* @param timesheet
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public void checkEmptyPeriod(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
public Message sendValidationEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public Message validateAndSendValidationEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void refuse(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
public Message sendRefusalEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public Message refuseAndSendRefusalEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public void cancel(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
/**
|
||||
* Set the timesheet to draft status.
|
||||
*
|
||||
* @param timesheet a timesheet
|
||||
*/
|
||||
void draft(Timesheet timesheet);
|
||||
|
||||
public Message sendCancellationEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public Message cancelAndSendCancellationEmail(Timesheet timesheet)
|
||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||
IllegalAccessException, MessagingException, IOException;
|
||||
|
||||
public Timesheet generateLines(
|
||||
Timesheet timesheet,
|
||||
LocalDate fromGenerationDate,
|
||||
LocalDate toGenerationDate,
|
||||
BigDecimal logTime,
|
||||
Project project,
|
||||
Product product)
|
||||
throws AxelorException;
|
||||
|
||||
public LocalDate getFromPeriodDate();
|
||||
|
||||
public Timesheet getCurrentTimesheet();
|
||||
|
||||
public Timesheet getCurrentOrCreateTimesheet();
|
||||
|
||||
public Timesheet createTimesheet(User user, LocalDate fromDate, LocalDate toDate);
|
||||
|
||||
public List<InvoiceLine> createInvoiceLines(
|
||||
Invoice invoice, List<TimesheetLine> timesheetLineList, int priority) throws AxelorException;
|
||||
|
||||
public List<InvoiceLine> createInvoiceLine(
|
||||
Invoice invoice,
|
||||
Product product,
|
||||
User user,
|
||||
String date,
|
||||
BigDecimal hoursDuration,
|
||||
int priority,
|
||||
PriceList priceList)
|
||||
throws AxelorException;
|
||||
|
||||
@Transactional
|
||||
public void computeTimeSpent(Timesheet timesheet);
|
||||
|
||||
public BigDecimal computeSubTimeSpent(Project project);
|
||||
|
||||
public void computeParentTimeSpent(Project project);
|
||||
|
||||
public BigDecimal computeTimeSpent(Project project);
|
||||
|
||||
public String computeFullName(Timesheet timesheet);
|
||||
|
||||
public List<Map<String, Object>> createDefaultLines(Timesheet timesheet);
|
||||
|
||||
public BigDecimal computePeriodTotal(Timesheet timesheet);
|
||||
|
||||
public String getPeriodTotalConvertTitle(Timesheet timesheet);
|
||||
|
||||
public void createDomainAllTimesheetLine(
|
||||
User user, Employee employee, ActionView.ActionViewBuilder actionView);
|
||||
|
||||
public void createValidateDomainTimesheetLine(
|
||||
User user, Employee employee, ActionView.ActionViewBuilder actionView);
|
||||
|
||||
/**
|
||||
* Update {@link Timesheet#timeLoggingPreferenceSelect} and recompute all durations.
|
||||
*
|
||||
* @param timesheet a context timesheet
|
||||
* @return the updated timesheet
|
||||
*/
|
||||
void updateTimeLoggingPreference(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void generateLinesFromExpectedProjectPlanning(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
public void prefillLines(Timesheet timesheet) throws AxelorException;
|
||||
|
||||
public void setTeamTaskTotalRealHrs(List<TimesheetLine> timesheetLines, boolean isAdd);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.timesheet.timer;
|
||||
|
||||
import com.axelor.apps.hr.db.TSTimer;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public interface TimesheetTimerService {
|
||||
|
||||
public void pause(TSTimer timer);
|
||||
|
||||
public void stop(TSTimer timer) throws AxelorException;
|
||||
|
||||
public void calculateDuration(TSTimer timer);
|
||||
|
||||
public TimesheetLine generateTimesheetLine(TSTimer timer);
|
||||
|
||||
public TSTimer getCurrentTSTimer();
|
||||
|
||||
public BigDecimal convertSecondDurationInHours(long durationInSeconds);
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.timesheet.timer;
|
||||
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.hr.db.TSTimer;
|
||||
import com.axelor.apps.hr.db.Timesheet;
|
||||
import com.axelor.apps.hr.db.TimesheetLine;
|
||||
import com.axelor.apps.hr.db.repo.TSTimerRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
|
||||
import com.axelor.apps.hr.db.repo.TimesheetRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetLineService;
|
||||
import com.axelor.apps.hr.service.timesheet.TimesheetService;
|
||||
import com.axelor.apps.tool.date.DurationTool;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TimesheetTimerServiceImpl implements TimesheetTimerService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Transactional
|
||||
public void pause(TSTimer timer) {
|
||||
timer.setStatusSelect(TSTimerRepository.STATUS_PAUSE);
|
||||
calculateDuration(timer);
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void stop(TSTimer timer) throws AxelorException {
|
||||
timer.setStatusSelect(TSTimerRepository.STATUS_STOP);
|
||||
calculateDuration(timer);
|
||||
if (timer.getDuration() > 59) {
|
||||
generateTimesheetLine(timer);
|
||||
} else {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.TYPE_FUNCTIONNAL,
|
||||
I18n.get(IExceptionMessage.NO_TIMESHEET_CREATED),
|
||||
timer);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void calculateDuration(TSTimer timer) {
|
||||
long currentDuration = timer.getDuration();
|
||||
Duration duration =
|
||||
DurationTool.computeDuration(
|
||||
timer.getTimerStartDateT(),
|
||||
Beans.get(AppBaseService.class).getTodayDateTime().toLocalDateTime());
|
||||
long secondes = DurationTool.getSecondsDuration(duration) + currentDuration;
|
||||
timer.setDuration(secondes);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public TimesheetLine generateTimesheetLine(TSTimer timer) {
|
||||
|
||||
BigDecimal durationHours = this.convertSecondDurationInHours(timer.getDuration());
|
||||
Timesheet timesheet = Beans.get(TimesheetService.class).getCurrentOrCreateTimesheet();
|
||||
LocalDate startDateTime =
|
||||
(timer.getStartDateTime() == null)
|
||||
? Beans.get(AppBaseService.class).getTodayDateTime().toLocalDate()
|
||||
: timer.getStartDateTime().toLocalDate();
|
||||
TimesheetLine timesheetLine =
|
||||
Beans.get(TimesheetLineService.class)
|
||||
.createTimesheetLine(
|
||||
timer.getProject(),
|
||||
timer.getProduct(),
|
||||
timer.getUser(),
|
||||
startDateTime,
|
||||
timesheet,
|
||||
durationHours,
|
||||
timer.getComments());
|
||||
|
||||
Beans.get(TimesheetRepository.class).save(timesheet);
|
||||
Beans.get(TimesheetLineRepository.class).save(timesheetLine);
|
||||
timer.setTimesheetLine(timesheetLine);
|
||||
|
||||
return timesheetLine;
|
||||
}
|
||||
|
||||
public BigDecimal convertSecondDurationInHours(long durationInSeconds) {
|
||||
logger.debug("Duration in seconds : {}", durationInSeconds);
|
||||
|
||||
BigDecimal durationHours =
|
||||
new BigDecimal(durationInSeconds).divide(new BigDecimal(3600), 4, RoundingMode.HALF_EVEN);
|
||||
logger.debug("Duration in hours : {}", durationHours);
|
||||
|
||||
return durationHours;
|
||||
}
|
||||
|
||||
public TSTimer getCurrentTSTimer() {
|
||||
return Beans.get(TSTimerRepository.class)
|
||||
.all()
|
||||
.filter("self.user = ?1", AuthUtils.getUser())
|
||||
.fetchOne();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.user;
|
||||
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.meta.CallMethod;
|
||||
import com.google.inject.persist.Transactional;
|
||||
|
||||
public interface UserHrService {
|
||||
|
||||
@Transactional
|
||||
public void createEmployee(User user);
|
||||
|
||||
@Transactional
|
||||
public Company getPayCompany(User user);
|
||||
|
||||
@CallMethod
|
||||
public Product getTimesheetProduct(User user);
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.service.user;
|
||||
|
||||
import com.axelor.apps.base.db.AppBase;
|
||||
import com.axelor.apps.base.db.AppLeave;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.EventsPlanning;
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.base.service.user.UserService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.HRConfig;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.service.app.AppHumanResourceService;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.auth.db.repo.UserRepository;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
|
||||
public class UserHrServiceImpl implements UserHrService {
|
||||
|
||||
@Inject UserRepository userRepo;
|
||||
|
||||
@Inject private AppHumanResourceService appHumanResourceService;
|
||||
|
||||
@Transactional
|
||||
public void createEmployee(User user) {
|
||||
if (user.getPartner() == null) {
|
||||
Beans.get(UserService.class).createPartner(user);
|
||||
}
|
||||
|
||||
AppBase appBase = appHumanResourceService.getAppBase();
|
||||
AppLeave appLeave = appHumanResourceService.getAppLeave();
|
||||
|
||||
Employee employee = new Employee();
|
||||
employee.setContactPartner(user.getPartner());
|
||||
employee.setTimeLoggingPreferenceSelect(appBase.getTimeLoggingPreferenceSelect());
|
||||
employee.setDailyWorkHours(appBase.getDailyWorkHours());
|
||||
employee.setNegativeValueLeave(appLeave.getAllowNegativeLeaveEmployees());
|
||||
|
||||
EventsPlanning planning = null;
|
||||
Company company = user.getActiveCompany();
|
||||
if (company != null) {
|
||||
HRConfig hrConfig = company.getHrConfig();
|
||||
if (hrConfig != null) {
|
||||
planning = hrConfig.getPublicHolidayEventsPlanning();
|
||||
}
|
||||
}
|
||||
employee.setPublicHolidayEventsPlanning(planning);
|
||||
|
||||
employee.setUser(user);
|
||||
Beans.get(EmployeeRepository.class).save(employee);
|
||||
|
||||
user.setEmployee(employee);
|
||||
userRepo.save(user);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Company getPayCompany(User user) {
|
||||
Company payCompany = null;
|
||||
if (user.getEmployee() != null
|
||||
&& user.getEmployee().getMainEmploymentContract() != null
|
||||
&& user.getEmployee().getMainEmploymentContract().getPayCompany() != null) {
|
||||
payCompany = user.getEmployee().getMainEmploymentContract().getPayCompany();
|
||||
} else if (user.getActiveCompany() != null) {
|
||||
payCompany = user.getActiveCompany();
|
||||
}
|
||||
return payCompany;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Product getTimesheetProduct(User user) {
|
||||
|
||||
if (user == null || user.getId() == null || user.getActiveCompany() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
user = userRepo.find(user.getId());
|
||||
|
||||
Product product = null;
|
||||
HRConfig hrConfig = user.getActiveCompany().getHrConfig();
|
||||
if (hrConfig != null && hrConfig.getUseUniqueProductForTimesheet()) {
|
||||
product = hrConfig.getUniqueTimesheetProduct();
|
||||
}
|
||||
|
||||
if (product == null && user.getEmployee() != null) {
|
||||
product = user.getEmployee().getProduct();
|
||||
}
|
||||
|
||||
return product;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.translation;
|
||||
|
||||
public interface ITranslation {
|
||||
|
||||
public static final String EMPLOYEES_MANAGEMENT_APP_NAME = /*$$(*/
|
||||
"value:Employees Managment"; /*)*/
|
||||
public static final String EXTRA_HOURS_APP_NAME = /*$$(*/ "value:Extra hours"; /*)*/
|
||||
public static final String EXPENSE_MANAGEMENT_APP_NAME = /*$$(*/ "value:Expense Management"; /*)*/
|
||||
public static final String TIMESHEET_MANAGEMENT_APP_NAME = /*$$(*/
|
||||
"value:Timesheet Management"; /*)*/
|
||||
public static final String LEAVE_MANAGEMENT_APP_NAME = /*$$(*/ "value:Leave Management"; /*)*/
|
||||
|
||||
public static final String PUBLIC_HOLIDAY_TITLE = /*$$(*/ "Public holidays"; /*)*/
|
||||
public static final String WEEKLY_PLANNING_TITLE = /*$$(*/ "6 days week"; /*)*/
|
||||
|
||||
public static final String TS_REPORT_FILL_NO_USER = /*$$(*/ "No user found"; /*)*/
|
||||
public static final String TS_REPORT_TITLE = /*$$(*/ "TimesheetReport"; /*)*/
|
||||
|
||||
public static final String REQUEST_OVERFLOW = /*$$(*/ "Too many requests"; /*)*/
|
||||
public static final String NO_SUCH_PLACE = /*$$(*/ "No such place exists"; /*)*/
|
||||
public static final String NO_ROUTE = /*$$(*/ "No Route Found"; /*)*/
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.hr.db.Absence;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.service.AbsenceServiceImpl;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AbsenceController {
|
||||
|
||||
public void attachTheAbsenceWithDailyReport(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Long absenceId = (Long) request.getContext().asType(Absence.class).getId();
|
||||
Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);
|
||||
|
||||
LocalDate absenceStartDate = absence.getStartDate().toLocalDate();
|
||||
LocalDate absenceEndDate = absence.getEndDate().toLocalDate();
|
||||
Employee employee = absence.getEmployee();
|
||||
|
||||
// Fetch all existing daily reports associated with this absence
|
||||
List<DailyReport> existingReports =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.absenceSet = :absence")
|
||||
.bind("absence", absence)
|
||||
.fetch();
|
||||
|
||||
if (existingReports != null && !existingReports.isEmpty()) {
|
||||
// Detach absence only from reports that are outside the new date range
|
||||
List<DailyReport> reportsToDetach =
|
||||
existingReports
|
||||
.stream()
|
||||
.filter(
|
||||
report ->
|
||||
report.getReportDate().isBefore(absenceStartDate)
|
||||
|| report.getReportDate().isAfter(absenceEndDate))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Detach absence from these specific reports
|
||||
if (!reportsToDetach.isEmpty()) {
|
||||
Beans.get(AbsenceServiceImpl.class)
|
||||
.deAttachTheAbsenceWithDailyReport(absence, reportsToDetach, false);
|
||||
}
|
||||
}
|
||||
|
||||
List<DailyReport> newReports =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee = :employee and self.reportDate between :absenceStartDate and :absenceEndDate")
|
||||
.bind("employee", employee)
|
||||
.bind("absenceStartDate", absenceStartDate)
|
||||
.bind("absenceEndDate", absenceEndDate)
|
||||
.fetch();
|
||||
|
||||
// Check if there are any reports
|
||||
if (newReports.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Beans.get(AbsenceServiceImpl.class).attachTheAbsenceWithDailyReport(absence, newReports);
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void chooseAbsenceType(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
// Get the selected absence type from the request parameters
|
||||
Integer selectedType = (Integer) request.getContext().get("selectedType");
|
||||
|
||||
// Get the list of selected absence IDs
|
||||
List<Long> absenceIds = (List<Long>) request.getContext().get("_ids");
|
||||
|
||||
// Iterate over the selected absence IDs
|
||||
for (Long absenceId : absenceIds) {
|
||||
// Find the absence entity by ID
|
||||
Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);
|
||||
|
||||
if (absence != null) {
|
||||
// Call the chooseAbsenceType method of the service with both absence and selectedType
|
||||
Beans.get(AbsenceServiceImpl.class).chooseAbsenceType(absence, selectedType);
|
||||
} else {
|
||||
// Log a warning or handle the absence being null appropriately
|
||||
System.err.println("Absence entity with ID " + absenceId + " not found.");
|
||||
}
|
||||
}
|
||||
|
||||
// Set reload to true to refresh the view
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void archiveAbsence(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Long absenceId = (Long) request.getContext().asType(Absence.class).getId();
|
||||
Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);
|
||||
|
||||
List<DailyReport> dailyreports =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.absence = :absence")
|
||||
.bind("absence", absenceId)
|
||||
.fetch();
|
||||
|
||||
Beans.get(AbsenceServiceImpl.class)
|
||||
.deAttachTheAbsenceWithDailyReport(absence, dailyreports, true);
|
||||
ActionViewBuilder actionView =
|
||||
ActionView.define(I18n.get("Absences"))
|
||||
.model(Absence.class.getName())
|
||||
.add("grid", "absence-grid")
|
||||
.add("form", "absence-form");
|
||||
|
||||
response.setView(actionView.map());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void calculateTotalAbsenceHours(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Absence absence = request.getContext().asType(Absence.class);
|
||||
// Absence absence = Beans.get(AbsenceRepository.class).find(absenceId);
|
||||
|
||||
LocalDateTime absenceStartDate = absence.getStartDate();
|
||||
LocalDateTime absenceEndDate = absence.getEndDate();
|
||||
if (absenceStartDate.isAfter(absenceEndDate)) {
|
||||
response.setAlert("Start date cannot be after end date.");
|
||||
} else {
|
||||
BigDecimal totalAbsenceHours =
|
||||
Beans.get(AbsenceServiceImpl.class)
|
||||
.calculateTotalAbsenceHours(absenceStartDate, absenceEndDate);
|
||||
response.setValue("totalAbsenceHours", totalAbsenceHours);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.hr.service.app.AppHumanResourceService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class AppHumanResourceController {
|
||||
|
||||
public void generateHrConfigurations(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Beans.get(AppHumanResourceService.class).generateHrConfigurations();
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,373 @@
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.base.web.AppBaseController;
|
||||
import com.axelor.apps.hr.service.AuthorizationService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import wslite.json.JSONArray;
|
||||
import wslite.json.JSONException;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
@Singleton
|
||||
public class AuthorizationController {
|
||||
|
||||
private final AppSettings appSettings = AppSettings.get();
|
||||
private final String BASE_URL = appSettings.get("portail.api.baseurl");
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
public void fetchAuthorization(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
|
||||
String accessToken = AppBaseController.getAccessToken();
|
||||
if (accessToken == null) {
|
||||
logger.error("Access token is null, unable to proceed.");
|
||||
return;
|
||||
}
|
||||
|
||||
String jsonResponse = fetchAA(accessToken);
|
||||
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveAA(jsonObject);
|
||||
}
|
||||
|
||||
// Reload the response after successfully saving extra hours
|
||||
response.setReload(true);
|
||||
|
||||
} catch (JSONException e) {
|
||||
// Log the specific JSON parsing error
|
||||
System.err.println("Failed to parse JSON: " + jsonResponse);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
System.err.println("No response received from fetchAA.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// General catch for unexpected exceptions
|
||||
System.err.println(
|
||||
"An error occurred while fetching Authorization Absence: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void fetchEntryAuthorization(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
String accessToken = AppBaseController.getAccessToken();
|
||||
if (accessToken == null) {
|
||||
logger.error("Access token is null, unable to proceed.");
|
||||
return;
|
||||
}
|
||||
String jsonResponse = fetchAE(accessToken);
|
||||
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveAE(jsonObject);
|
||||
}
|
||||
|
||||
// Reload the response after successfully saving extra hours
|
||||
response.setReload(true);
|
||||
|
||||
} catch (JSONException e) {
|
||||
// Log the specific JSON parsing error
|
||||
System.err.println("Failed to parse JSON: " + jsonResponse);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
System.err.println("No response received from fetchAE.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// General catch for unexpected exceptions
|
||||
System.err.println("An error occurred while fetching Entry Authorization: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void fetchExitAuthorization(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
String accessToken = AppBaseController.getAccessToken();
|
||||
if (accessToken == null) {
|
||||
logger.error("Access token is null, unable to proceed.");
|
||||
return;
|
||||
}
|
||||
String jsonResponse = fetchBS(accessToken);
|
||||
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveBS(jsonObject);
|
||||
}
|
||||
|
||||
// Reload the response after successfully saving extra hours
|
||||
response.setReload(true);
|
||||
|
||||
} catch (JSONException e) {
|
||||
// Log the specific JSON parsing error
|
||||
System.err.println("Failed to parse JSON: " + jsonResponse);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
System.err.println("No response received from fetchBS.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// General catch for unexpected exceptions
|
||||
System.err.println("An error occurred while fetching Entry Authorization: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void fetchSalaryAuthorization(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
String accessToken = AppBaseController.getAccessToken();
|
||||
if (accessToken == null) {
|
||||
logger.error("Access token is null, unable to proceed.");
|
||||
return;
|
||||
}
|
||||
String jsonResponse = fetchAP(accessToken);
|
||||
|
||||
if (jsonResponse != null) {
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResponse);
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
Beans.get(AuthorizationService.class).saveAP(jsonObject);
|
||||
}
|
||||
|
||||
// Reload the response after successfully saving extra hours
|
||||
response.setReload(true);
|
||||
|
||||
} catch (JSONException e) {
|
||||
// Log the specific JSON parsing error
|
||||
System.err.println("Failed to parse JSON: " + jsonResponse);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
System.err.println("No response received from fetchAP.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// General catch for unexpected exceptions
|
||||
System.err.println(
|
||||
"An error occurred while fetching Salary Authorization: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String fetchAA(String accessToken) {
|
||||
String endpoint = BASE_URL + "tickets/aa/";
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(endpoint);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
// Include the access token in the Authorization header
|
||||
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
// Process the response as needed
|
||||
return response.toString();
|
||||
}
|
||||
} else {
|
||||
// Read the error stream for more details
|
||||
StringBuilder errorResponse = new StringBuilder();
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"))) {
|
||||
String errorLine;
|
||||
while ((errorLine = br.readLine()) != null) {
|
||||
errorResponse.append(errorLine.trim());
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(
|
||||
"Failed: HTTP error code: " + responseCode + ", Error: " + errorResponse.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Return null in case of failure
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect(); // Ensure connection is closed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String fetchAE(String accessToken) {
|
||||
String endpoint = BASE_URL + "tickets/ae/";
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(endpoint);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
// Include the access token in the Authorization header
|
||||
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
// Process the response as needed
|
||||
return response.toString();
|
||||
}
|
||||
} else {
|
||||
// Read the error stream for more details
|
||||
StringBuilder errorResponse = new StringBuilder();
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"))) {
|
||||
String errorLine;
|
||||
while ((errorLine = br.readLine()) != null) {
|
||||
errorResponse.append(errorLine.trim());
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(
|
||||
"Failed: HTTP error code: " + responseCode + ", Error: " + errorResponse.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Return null in case of failure
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect(); // Ensure connection is closed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String fetchBS(String accessToken) {
|
||||
String endpoint = BASE_URL + "tickets/bs/";
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(endpoint);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
// Include the access token in the Authorization header
|
||||
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
// Process the response as needed
|
||||
return response.toString();
|
||||
}
|
||||
} else {
|
||||
// Read the error stream for more details
|
||||
StringBuilder errorResponse = new StringBuilder();
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"))) {
|
||||
String errorLine;
|
||||
while ((errorLine = br.readLine()) != null) {
|
||||
errorResponse.append(errorLine.trim());
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(
|
||||
"Failed: HTTP error code: " + responseCode + ", Error: " + errorResponse.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Return null in case of failure
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect(); // Ensure connection is closed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Authorisation de paye
|
||||
public String fetchAP(String accessToken) {
|
||||
String endpoint = BASE_URL + "tickets/ap/";
|
||||
HttpURLConnection conn = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(endpoint);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
// Include the access token in the Authorization header
|
||||
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String responseLine;
|
||||
while ((responseLine = br.readLine()) != null) {
|
||||
response.append(responseLine.trim());
|
||||
}
|
||||
// Process the response as needed
|
||||
return response.toString();
|
||||
}
|
||||
} else {
|
||||
// Read the error stream for more details
|
||||
StringBuilder errorResponse = new StringBuilder();
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"))) {
|
||||
String errorLine;
|
||||
while ((errorLine = br.readLine()) != null) {
|
||||
errorResponse.append(errorLine.trim());
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(
|
||||
"Failed: HTTP error code: " + responseCode + ", Error: " + errorResponse.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Return null in case of failure
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect(); // Ensure connection is closed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,233 @@
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.service.DailyReportService;
|
||||
import com.axelor.apps.hr.service.DailyReportServiceImpl;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class DailyReportController {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
public void workingHours(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Long dailyReportId = (Long) request.getContext().asType(DailyReport.class).getId();
|
||||
DailyReport DailyReport = Beans.get(DailyReportRepository.class).find(dailyReportId);
|
||||
if (DailyReport == null) {
|
||||
throw new IllegalArgumentException("DailyReport with ID " + dailyReportId + " not found.");
|
||||
}
|
||||
Beans.get(DailyReportServiceImpl.class).determineShift(DailyReport);
|
||||
Beans.get(DailyReportServiceImpl.class).workingHours(DailyReport);
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n\n\n\n\n\n\n\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void workingHours1(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Long dailyReportId = (Long) request.getContext().asType(DailyReport.class).getId();
|
||||
DailyReport DailyReport = Beans.get(DailyReportRepository.class).find(dailyReportId);
|
||||
if (DailyReport == null) {
|
||||
throw new IllegalArgumentException("DailyReport with ID " + dailyReportId + " not found.");
|
||||
}
|
||||
Beans.get(DailyReportServiceImpl.class).workingHours(DailyReport);
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n\n\n\n\n\n\n\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void workingHoursForAll(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
List<DailyReport> dailyReportList =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.isCalculated = ?", false)
|
||||
.fetch();
|
||||
|
||||
if (!dailyReportList.isEmpty()) {
|
||||
Beans.get(DailyReportServiceImpl.class).workingHoursForAll(dailyReportList);
|
||||
response.setFlash("Working hours calculated successfully.");
|
||||
} else {
|
||||
response.setFlash("No new records to process.");
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
log.error("An error occurred while calculating working hours.", e);
|
||||
response.setError("An error occurred while calculating working hours.");
|
||||
}
|
||||
}
|
||||
|
||||
public void workingHoursForSelectedInstances(ActionRequest request, ActionResponse response) {
|
||||
List<Long> dailyReportIds = (List<Long>) request.getContext().get("_ids");
|
||||
if (dailyReportIds != null && !dailyReportIds.isEmpty()) {
|
||||
|
||||
List<DailyReport> dailyReportList =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.id in ?1 ", dailyReportIds)
|
||||
.fetch();
|
||||
|
||||
for (DailyReport dailyReport : dailyReportList) {
|
||||
Beans.get(DailyReportServiceImpl.class).determineShift(dailyReport);
|
||||
}
|
||||
Beans.get(DailyReportServiceImpl.class).workingHoursForAll(dailyReportList);
|
||||
response.setFlash("Working hours calculated successfully.");
|
||||
} else {
|
||||
response.setFlash("No Daily report selected");
|
||||
}
|
||||
}
|
||||
|
||||
public void workingHoursForChangedInstances(ActionRequest request, ActionResponse response) {
|
||||
List<DailyReport> dailyReportList =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.isCalculated = ? and self.isChanged = ?", false, true)
|
||||
.fetch();
|
||||
|
||||
for (DailyReport dailyReport : dailyReportList) {
|
||||
Beans.get(DailyReportServiceImpl.class).determineShift(dailyReport);
|
||||
}
|
||||
|
||||
Beans.get(DailyReportServiceImpl.class).workingHoursForAll(dailyReportList);
|
||||
response.setReload(true);
|
||||
response.setFlash("Working hours calculated successfully.");
|
||||
}
|
||||
|
||||
public void massDeducePrime(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Integer primeSelection = (Integer) request.getContext().get("primesSelect");
|
||||
String startDateStr = (String) request.getContext().get("startDate");
|
||||
String endDateStr = (String) request.getContext().get("endDate");
|
||||
|
||||
LocalDate startDate = null;
|
||||
LocalDate endDate = null;
|
||||
|
||||
try {
|
||||
if (startDateStr != null) {
|
||||
startDate = LocalDate.parse(startDateStr);
|
||||
}
|
||||
if (endDateStr != null) {
|
||||
endDate = LocalDate.parse(endDateStr);
|
||||
}
|
||||
|
||||
// Validate the dates
|
||||
if (startDate == null || endDate == null) {
|
||||
response.setFlash("Start date or end date is missing or invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (startDate.isAfter(endDate)) {
|
||||
response.setFlash("Start date cannot be after end date.");
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (DateTimeParseException e) {
|
||||
response.setFlash(
|
||||
"Invalid date format for startDate or endDate. Expected format: yyyy-MM-dd.");
|
||||
return;
|
||||
}
|
||||
|
||||
Object valueToDeduceObj = request.getContext().get("valueToDeduce");
|
||||
|
||||
BigDecimal valueToDeduce = null;
|
||||
if (valueToDeduceObj instanceof Integer) {
|
||||
valueToDeduce = BigDecimal.valueOf((Integer) valueToDeduceObj);
|
||||
} else if (valueToDeduceObj instanceof BigDecimal) {
|
||||
valueToDeduce = (BigDecimal) valueToDeduceObj;
|
||||
} else if (valueToDeduceObj instanceof String) {
|
||||
try {
|
||||
valueToDeduce = new BigDecimal((String) valueToDeduceObj);
|
||||
} catch (NumberFormatException e) {
|
||||
response.setFlash("Value to deduce must be a valid number.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
response.setFlash(
|
||||
"Invalid value to deduce: unsupported type "
|
||||
+ (valueToDeduceObj != null ? valueToDeduceObj.getClass().getName() : "null"));
|
||||
return;
|
||||
}
|
||||
|
||||
Object employeesObject = request.getContext().get("employees");
|
||||
|
||||
// Initialize the employees list
|
||||
List<Employee> employees = new ArrayList<>();
|
||||
|
||||
if (employeesObject instanceof List) {
|
||||
List<LinkedHashMap<String, Object>> employeesList =
|
||||
(List<LinkedHashMap<String, Object>>) employeesObject;
|
||||
|
||||
for (LinkedHashMap<String, Object> employeeMap : employeesList) {
|
||||
Integer employeeIdInt = (Integer) employeeMap.get("id");
|
||||
|
||||
if (employeeIdInt != null) {
|
||||
Long employeeId = employeeIdInt.longValue();
|
||||
Employee employee = Beans.get(EmployeeRepository.class).find(employeeId);
|
||||
|
||||
if (employee != null) {
|
||||
employees.add(employee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (employees.isEmpty()) {
|
||||
response.setFlash("No employees selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Integer> employeeIds = new ArrayList<>();
|
||||
for (Employee employee : employees) {
|
||||
employeeIds.add(employee.getId().intValue());
|
||||
}
|
||||
|
||||
// Fetch all rapport journaliers within the date range for all employees
|
||||
List<DailyReport> dailyReportList =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee.id in :employeeIds and self.reportDate >= :startDate and self.reportDate <= :endDate")
|
||||
.bind("startDate", startDate)
|
||||
.bind("endDate", endDate)
|
||||
.bind("employeeIds", employeeIds)
|
||||
.fetch();
|
||||
|
||||
try {
|
||||
if (!dailyReportList.isEmpty()) {
|
||||
Beans.get(DailyReportService.class)
|
||||
.massDeducePrimes(dailyReportList, primeSelection, valueToDeduce);
|
||||
response.setReload(true);
|
||||
response.setFlash("Prime deductions processed successfully.");
|
||||
} else {
|
||||
response.setFlash("No reports found for the selected date range.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
response.setFlash("An error occurred while processing the request.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.ReportFactory;
|
||||
import com.axelor.apps.base.service.PeriodService;
|
||||
import com.axelor.apps.hr.db.EmployeeBonusMgt;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeBonusMgtRepository;
|
||||
import com.axelor.apps.hr.report.IReport;
|
||||
import com.axelor.apps.hr.service.EmployeeBonusService;
|
||||
import com.axelor.apps.report.engine.ReportSettings;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class EmployeeBonusController {
|
||||
|
||||
public void compute(ActionRequest request, ActionResponse response) {
|
||||
EmployeeBonusMgt employeeBonusMgt = request.getContext().asType(EmployeeBonusMgt.class);
|
||||
PeriodService periodService = Beans.get(PeriodService.class);
|
||||
try {
|
||||
employeeBonusMgt = Beans.get(EmployeeBonusMgtRepository.class).find(employeeBonusMgt.getId());
|
||||
Beans.get(EmployeeBonusService.class).compute(employeeBonusMgt);
|
||||
response.setReload(true);
|
||||
periodService.checkPeriod(employeeBonusMgt.getPayPeriod());
|
||||
periodService.checkPeriod(employeeBonusMgt.getLeavePeriod());
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void print(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
|
||||
EmployeeBonusMgt bonus =
|
||||
Beans.get(EmployeeBonusMgtRepository.class)
|
||||
.find(request.getContext().asType(EmployeeBonusMgt.class).getId());
|
||||
|
||||
String name =
|
||||
I18n.get("Employee bonus management") + " : " + bonus.getEmployeeBonusType().getLabel();
|
||||
|
||||
String fileLink =
|
||||
ReportFactory.createReport(IReport.EMPLOYEE_BONUS_MANAGEMENT, name)
|
||||
.addParam("EmployeeBonusMgtId", bonus.getId())
|
||||
.addParam("Locale", ReportSettings.getPrintingLocale(null))
|
||||
.toAttach(bonus)
|
||||
.generate()
|
||||
.getFileLink();
|
||||
|
||||
response.setView(ActionView.define(name).add("html", fileLink).map());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.ReportFactory;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.hr.db.DPAE;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.Granding;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.GrandingRepository;
|
||||
import com.axelor.apps.hr.report.IReport;
|
||||
import com.axelor.apps.hr.service.employee.EmployeeService;
|
||||
import com.axelor.apps.report.engine.ReportSettings;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import wslite.json.JSONException;
|
||||
import wslite.json.JSONObject;
|
||||
|
||||
@Singleton
|
||||
public class EmployeeController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private final String pythonScriptDir = AppSettings.get().get("services.dir");
|
||||
|
||||
public void showAnnualReport(ActionRequest request, ActionResponse response)
|
||||
throws JSONException, NumberFormatException, AxelorException {
|
||||
|
||||
String employeeId = request.getContext().get("_id").toString();
|
||||
String year = request.getContext().get("year").toString();
|
||||
int yearId = new JSONObject(year).getInt("id");
|
||||
String yearName = new JSONObject(year).getString("name");
|
||||
User user = AuthUtils.getUser();
|
||||
|
||||
String name =
|
||||
I18n.get("Annual expenses report") + " : " + user.getFullName() + " (" + yearName + ")";
|
||||
|
||||
String fileLink =
|
||||
ReportFactory.createReport(IReport.EMPLOYEE_ANNUAL_REPORT, name)
|
||||
.addParam("EmployeeId", Long.valueOf(employeeId))
|
||||
.addParam("YearId", Long.valueOf(yearId))
|
||||
.addParam("Locale", ReportSettings.getPrintingLocale(null))
|
||||
.toAttach(Beans.get(EmployeeRepository.class).find(Long.valueOf(employeeId)))
|
||||
.generate()
|
||||
.getFileLink();
|
||||
|
||||
response.setView(ActionView.define(name).add("html", fileLink).map());
|
||||
|
||||
response.setCanClose(true);
|
||||
}
|
||||
|
||||
public void setEmployeeSocialNetworkUrl(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Employee employee = request.getContext().asType(Employee.class);
|
||||
if (employee.getContactPartner() != null) {
|
||||
Map<String, String> urlMap =
|
||||
Beans.get(EmployeeService.class)
|
||||
.getSocialNetworkUrl(
|
||||
employee.getContactPartner().getName(),
|
||||
employee.getContactPartner().getFirstName());
|
||||
response.setAttr("contactPartner.facebookLabel", "title", urlMap.get("facebook"));
|
||||
response.setAttr("contactPartner.twitterLabel", "title", urlMap.get("twitter"));
|
||||
response.setAttr("contactPartner.linkedinLabel", "title", urlMap.get("linkedin"));
|
||||
response.setAttr("contactPartner.youtubeLabel", "title", urlMap.get("youtube"));
|
||||
}
|
||||
}
|
||||
|
||||
public void setContactSocialNetworkUrl(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Partner partnerContact = request.getContext().asType(Partner.class);
|
||||
Map<String, String> urlMap =
|
||||
Beans.get(EmployeeService.class)
|
||||
.getSocialNetworkUrl(partnerContact.getName(), partnerContact.getFirstName());
|
||||
response.setAttr("facebookLabel", "title", urlMap.get("facebook"));
|
||||
response.setAttr("twitterLabel", "title", urlMap.get("twitter"));
|
||||
response.setAttr("linkedinLabel", "title", urlMap.get("linkedin"));
|
||||
response.setAttr("youtubeLabel", "title", urlMap.get("youtube"));
|
||||
}
|
||||
|
||||
public void printEmployeePhonebook(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
User user = AuthUtils.getUser();
|
||||
|
||||
String name = I18n.get("Employee PhoneBook");
|
||||
|
||||
String fileLink =
|
||||
ReportFactory.createReport(IReport.EMPLOYEE_PHONEBOOK, name + "-${date}")
|
||||
.addParam("Locale", ReportSettings.getPrintingLocale(null))
|
||||
.addParam("UserId", user.getId())
|
||||
.generate()
|
||||
.getFileLink();
|
||||
|
||||
LOG.debug("Printing " + name);
|
||||
|
||||
response.setView(ActionView.define(name).add("html", fileLink).map());
|
||||
}
|
||||
|
||||
public void generateNewDPAE(ActionRequest request, ActionResponse response) {
|
||||
Employee employee = request.getContext().asType(Employee.class);
|
||||
employee = Beans.get(EmployeeRepository.class).find(employee.getId());
|
||||
|
||||
try {
|
||||
Long dpaeId = Beans.get(EmployeeService.class).generateNewDPAE(employee);
|
||||
|
||||
ActionViewBuilder builder =
|
||||
ActionView.define(I18n.get("DPAE"))
|
||||
.model(DPAE.class.getName())
|
||||
.add("grid", "dpae-grid")
|
||||
.add("form", "dpae-form")
|
||||
.context("_showRecord", dpaeId);
|
||||
response.setView(builder.map());
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void enrollEmployee(ActionRequest request, ActionResponse response) {
|
||||
Long employeeId = (Long) request.getContext().asType(Employee.class).getId();
|
||||
Employee employee = Beans.get(EmployeeRepository.class).find(employeeId);
|
||||
|
||||
Granding granding =
|
||||
Beans.get(GrandingRepository.class).all().filter("self.name = 'POINTEUSE-RDC'").fetchOne();
|
||||
|
||||
String ipAdress = granding.getIpAdress();
|
||||
String code = granding.getCode().toString();
|
||||
|
||||
if (employee.getIsEnrolled()) {
|
||||
response.setFlash("Employee is already enrolled.");
|
||||
} else {
|
||||
if (employee.getContactPartner() != null) {
|
||||
String employeeRegistrationNumber = employee.getRegistrationNumber();
|
||||
String employeeName = employee.getContactPartner().getName();
|
||||
|
||||
if (pythonScriptDir == null || pythonScriptDir.isEmpty()) {
|
||||
LOG.error("Pythons script path is not configured in AppSettings.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
String[] args = {
|
||||
"python",
|
||||
pythonScriptDir + "\\Attendance\\main.py",
|
||||
"--commande",
|
||||
"create",
|
||||
"--ip_address",
|
||||
ipAdress,
|
||||
"--code",
|
||||
code,
|
||||
"--user_id",
|
||||
employeeRegistrationNumber,
|
||||
"--name",
|
||||
employeeName
|
||||
};
|
||||
|
||||
Process p = Runtime.getRuntime().exec(args);
|
||||
|
||||
// Capture the output stream (standard output)
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
LOG.info("Python script (Employee Enrolling) output: " + line);
|
||||
}
|
||||
|
||||
// Capture the error stream (standard error)
|
||||
BufferedReader errorReader =
|
||||
new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
while ((line = errorReader.readLine()) != null) {
|
||||
LOG.error("Python script (Employee Enrolling) error: " + line);
|
||||
}
|
||||
|
||||
// Wait for the process to complete and check the exit value
|
||||
int exitCode = p.waitFor();
|
||||
|
||||
// Check if the process ran successfully
|
||||
if (exitCode == 0) {
|
||||
LOG.info("Python script executed successfully (Employee Enrolling).");
|
||||
Beans.get(EmployeeService.class).setEmployeeEnrolled(employee);
|
||||
response.setFlash("Employee enrolled successfully.");
|
||||
} else {
|
||||
LOG.error(
|
||||
"Python script execution (Employee Enrolling) failed with exit code: " + exitCode);
|
||||
response.setFlash("Failed to enroll the Employee.");
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
// Check if the file is not found based on the message or error code
|
||||
if (e.getMessage().contains("The system cannot find the file specified")) {
|
||||
LOG.error("Python script file (Employee Enrolling) not found: " + e.getMessage());
|
||||
} else {
|
||||
LOG.error(
|
||||
"An error occurred while executing the Python script (Employee Enrolling).", e);
|
||||
}
|
||||
response.setFlash("Failed to enroll the Employee.");
|
||||
TraceBackService.trace(e);
|
||||
} catch (InterruptedException e) {
|
||||
// Handle any interruption errors
|
||||
response.setFlash("Failed to enroll the Employee.");
|
||||
LOG.error("Python script (Employee Enrolling) execution interrupted.", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setEmployeeConfig(ActionRequest request, ActionResponse response) {
|
||||
|
||||
List<Long> employeeIds = (List<Long>) request.getContext().get("_ids");
|
||||
System.out.println("****************");
|
||||
System.out.println(employeeIds);
|
||||
System.out.println("****************");
|
||||
Integer configSelect = (Integer) request.getContext().get("configSelect");
|
||||
|
||||
if (employeeIds == null || employeeIds.isEmpty()) {
|
||||
response.setFlash("You haven't selected any Employee.");
|
||||
}
|
||||
try {
|
||||
if (!employeeIds.isEmpty()) {
|
||||
Beans.get(EmployeeService.class).massUpdateEmployeeConfig(employeeIds, configSelect, true);
|
||||
response.setReload(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void unSetEmployeeConfig(ActionRequest request, ActionResponse response) {
|
||||
|
||||
List<Long> employeeIds = (List<Long>) request.getContext().get("_ids");
|
||||
System.out.println("****************");
|
||||
System.out.println(employeeIds);
|
||||
System.out.println("****************");
|
||||
Integer configSelect = (Integer) request.getContext().get("configSelect");
|
||||
|
||||
if (employeeIds == null || employeeIds.isEmpty()) {
|
||||
response.setFlash("You haven't selected any Employee.");
|
||||
}
|
||||
try {
|
||||
if (!employeeIds.isEmpty()) {
|
||||
Beans.get(EmployeeService.class).massUpdateEmployeeConfig(employeeIds, configSelect, false);
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.repo.EmploymentContractRepository;
|
||||
import com.axelor.apps.hr.service.EmploymentContractService;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
|
||||
@Singleton
|
||||
public class EmploymentContractController {
|
||||
|
||||
public void addAmendment(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EmploymentContract employmentContract = request.getContext().asType(EmploymentContract.class);
|
||||
|
||||
try {
|
||||
|
||||
Beans.get(EmploymentContractService.class)
|
||||
.addAmendment(
|
||||
Beans.get(EmploymentContractRepository.class).find(employmentContract.getId()));
|
||||
response.setFlash(
|
||||
String.format(
|
||||
"Contrat %s - avenant %s",
|
||||
employmentContract.getFullName(), employmentContract.getEmploymentContractVersion()));
|
||||
response.setReload(true);
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void exportEmploymentContract(ActionRequest request, ActionResponse response)
|
||||
throws IOException {
|
||||
EmploymentContract employmentContract =
|
||||
Beans.get(EmploymentContractRepository.class)
|
||||
.find(request.getContext().asType(EmploymentContract.class).getId());
|
||||
|
||||
Beans.get(EmploymentContractService.class).exportEmploymentContract(employmentContract);
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.hr.db.Granding;
|
||||
import com.axelor.apps.hr.db.repo.GrandingRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class GrandingController {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
public void testGrandingConnection(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Long grandingId = (Long) request.getContext().asType(Granding.class).getId();
|
||||
Granding granding = Beans.get(GrandingRepository.class).find(grandingId);
|
||||
|
||||
String ipAdress = granding.getIpAdress();
|
||||
String code = granding.getCode().toString();
|
||||
|
||||
try {
|
||||
|
||||
String[] args = {
|
||||
"python",
|
||||
"C:\\Users\\administrator\\Desktop\\attendance\\main.py",
|
||||
"--commande",
|
||||
"ping",
|
||||
"--ip_address",
|
||||
ipAdress,
|
||||
"--code",
|
||||
code
|
||||
};
|
||||
|
||||
Process p = Runtime.getRuntime().exec(args);
|
||||
|
||||
// Capture the output stream (standard output)
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.info("Python script (Granding ping) output: " + line);
|
||||
}
|
||||
|
||||
// Capture the error stream (standard error)
|
||||
BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
while ((line = errorReader.readLine()) != null) {
|
||||
log.error("Python script (Granding ping) error: " + line);
|
||||
}
|
||||
|
||||
// Wait for the process to complete and check the exit value
|
||||
int exitCode = p.waitFor();
|
||||
|
||||
// Check if the process ran successfully
|
||||
if (exitCode == 0) {
|
||||
log.info("Python script executed successfully (Granding ping).");
|
||||
response.setFlash("Connection successful.");
|
||||
} else {
|
||||
log.error("Python script execution (Granding ping) failed with exit code: " + exitCode);
|
||||
response.setFlash("Connection failed.");
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
// Check if the file is not found based on the message or error code
|
||||
if (e.getMessage().contains("The system cannot find the file specified")) {
|
||||
log.error("Python script file (Granding ping) not found: " + e.getMessage());
|
||||
} else {
|
||||
log.error("An error occurred while executing the Python script (Granding ping).", e);
|
||||
}
|
||||
response.setFlash("Connection failed.");
|
||||
TraceBackService.trace(e);
|
||||
} catch (InterruptedException e) {
|
||||
// Handle any interruption errors
|
||||
response.setFlash("Connection failed.");
|
||||
log.error("Python script (Granding ping) execution interrupted.", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.base.db.Batch;
|
||||
import com.axelor.apps.hr.db.HrBatch;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.apps.hr.service.batch.HrBatchService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class HrBatchController {
|
||||
|
||||
/**
|
||||
* Launch any type of HR batch
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public void launchHrBatch(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
|
||||
HrBatch hrBatch = request.getContext().asType(HrBatch.class);
|
||||
|
||||
Batch batch =
|
||||
Beans.get(HrBatchService.class)
|
||||
.run(Beans.get(HrBatchRepository.class).find(hrBatch.getId()));
|
||||
|
||||
if (batch != null) {
|
||||
response.setFlash(batch.getComments());
|
||||
}
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,281 @@
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.base.db.Period;
|
||||
import com.axelor.apps.base.db.repo.PeriodRepository;
|
||||
import com.axelor.apps.hr.db.Absence;
|
||||
import com.axelor.apps.hr.db.DailyReport;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.MonthlyReport;
|
||||
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.MonthlyReportRepository;
|
||||
import com.axelor.apps.hr.service.MonthlyReportServiceImpl;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class MonthlyReportController {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
public void createMensuelReport(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
|
||||
Object object = request.getContext().get("period");
|
||||
LinkedHashMap<String, Object> periodMap = (LinkedHashMap<String, Object>) object;
|
||||
Integer periodIdInt = (Integer) periodMap.get("id");
|
||||
Long periodId = periodIdInt.longValue();
|
||||
Period period = Beans.get(PeriodRepository.class).find(periodId);
|
||||
LocalDate startDate = period.getFromDate();
|
||||
LocalDate endDate = period.getToDate();
|
||||
|
||||
// int remainingDateToLastOfMonth = calculateDaysExcludingFridaysAndThursdays(endDate);
|
||||
|
||||
// Get active employees in this period
|
||||
List<Employee> employees =
|
||||
Beans.get(EmployeeRepository.class)
|
||||
.all()
|
||||
.filter("self.quitDate is null or self.quitDate >= :startDate")
|
||||
.bind("startDate", startDate)
|
||||
.fetch();
|
||||
|
||||
// Fetch all rapport journaliers within the date range for all employees
|
||||
List<DailyReport> allDailyReports =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.reportDate >= :startDate and self.reportDate <= :endDate")
|
||||
.bind("startDate", startDate)
|
||||
.bind("endDate", endDate)
|
||||
.fetch();
|
||||
|
||||
// Fetch all absences within the date range for all employees
|
||||
List<Absence> allAbsences =
|
||||
Beans.get(AbsenceRepository.class)
|
||||
.all()
|
||||
.filter("DATE(self.startDate) >= :startDate and DATE(self.startDate) <= :endDate")
|
||||
.bind("startDate", startDate)
|
||||
.bind("endDate", endDate)
|
||||
.fetch();
|
||||
|
||||
// Iterate over employees and calculate/update MonthlyReport instances
|
||||
for (Employee employee : employees) {
|
||||
// Filter rapport journaliers for the current employee
|
||||
List<DailyReport> employeeDailyReports =
|
||||
allDailyReports
|
||||
.stream()
|
||||
.filter(r -> r.getEmployee().equals(employee))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Filter absences for the current employee
|
||||
List<Absence> employeeAbsences =
|
||||
allAbsences
|
||||
.stream()
|
||||
.filter(a -> a.getEmployee().equals(employee))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!employeeDailyReports.isEmpty() || !employeeAbsences.isEmpty()) {
|
||||
System.out.println(
|
||||
"Create monthly report for employee: " + employee.getRegistrationNumber());
|
||||
// Process the employee's monthly report using filtered rapport and absences
|
||||
Beans.get(MonthlyReportServiceImpl.class)
|
||||
.createMensuelReport(
|
||||
employee, period, startDate, endDate, employeeDailyReports, employeeAbsences);
|
||||
} else {
|
||||
log.error("No Daily Reports exist for employee: " + employee.getRegistrationNumber());
|
||||
}
|
||||
}
|
||||
// Indicate that the action was successful and a reload is needed
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
// Handle any exceptions
|
||||
e.printStackTrace();
|
||||
response.setError("An error occurred: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateMensuelReport(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
|
||||
Object periodObject = request.getContext().get("period");
|
||||
LinkedHashMap<String, Object> periodMap = (LinkedHashMap<String, Object>) periodObject;
|
||||
Integer periodIdInt = (Integer) periodMap.get("id");
|
||||
Long periodId = periodIdInt.longValue();
|
||||
Period period = Beans.get(PeriodRepository.class).find(periodId);
|
||||
LocalDate startDate = period.getFromDate();
|
||||
LocalDate endDate = period.getToDate();
|
||||
|
||||
//
|
||||
Object employeesObject = request.getContext().get("employees");
|
||||
System.out.println("Employees" + employeesObject);
|
||||
|
||||
// Initialize the employees list
|
||||
List<Employee> employees = new ArrayList<>();
|
||||
|
||||
// Check if employeesObject is not null and cast it to a list
|
||||
if (employeesObject instanceof List) {
|
||||
List<LinkedHashMap<String, Object>> employeesList =
|
||||
(List<LinkedHashMap<String, Object>>) employeesObject;
|
||||
|
||||
// Loop through each employee in the list
|
||||
for (LinkedHashMap<String, Object> employeeMap : employeesList) {
|
||||
Integer employeeIdInt = (Integer) employeeMap.get("id");
|
||||
|
||||
// Check for null ID to avoid potential NullPointerException
|
||||
if (employeeIdInt != null) {
|
||||
Long employeeId = employeeIdInt.longValue();
|
||||
|
||||
// Retrieve the employee from the repository
|
||||
Employee employee = Beans.get(EmployeeRepository.class).find(employeeId);
|
||||
|
||||
if (employee != null) {
|
||||
employees.add(employee); // Use add() instead of append()
|
||||
} else {
|
||||
System.out.println("Employee with ID " + employeeId + " not found.");
|
||||
}
|
||||
} else {
|
||||
System.out.println("Employee ID is missing in the employeeMap.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
response.setFlash("No employees Selected.");
|
||||
}
|
||||
|
||||
// int remainingDateToLastOfMonth = calculateDaysExcludingFridaysAndThursdays(endDate);
|
||||
List<Integer> employeesIds = new ArrayList<>();
|
||||
for (Employee e : employees) {
|
||||
employeesIds.add(e.getId().intValue());
|
||||
}
|
||||
|
||||
// Fetch all rapport journaliers within the date range for all employees
|
||||
List<DailyReport> allDailyReports =
|
||||
Beans.get(DailyReportRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee in :employeesIds and self.reportDate >= :startDate and self.reportDate <= :endDate")
|
||||
.bind("startDate", startDate)
|
||||
.bind("endDate", endDate)
|
||||
.bind("employeesIds", employeesIds)
|
||||
.fetch();
|
||||
|
||||
// Fetch all absences within the date range for all employees
|
||||
List<Absence> allAbsences =
|
||||
Beans.get(AbsenceRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.employee in :employeesIds and DATE(self.startDate) >= :startDate and DATE(self.startDate) <= :endDate")
|
||||
.bind("startDate", startDate)
|
||||
.bind("endDate", endDate)
|
||||
.bind("employeesIds", employeesIds)
|
||||
.fetch();
|
||||
|
||||
for (Employee employee : employees) {
|
||||
// Check if a MonthlyReport exists for this employee in the specified period
|
||||
MonthlyReport monthlyReport =
|
||||
Beans.get(MonthlyReportRepository.class)
|
||||
.all()
|
||||
.filter("self.employee = :employee and self.period = :period")
|
||||
.bind("employee", employee)
|
||||
.bind("period", period)
|
||||
.fetchOne();
|
||||
|
||||
Optional<MonthlyReport> monthlyReportOpt = Optional.ofNullable(monthlyReport);
|
||||
|
||||
// Filter daily reports for the current employee
|
||||
List<DailyReport> employeeDailyReports =
|
||||
allDailyReports
|
||||
.stream()
|
||||
.filter(r -> r.getEmployee().equals(employee))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Filter absences for the current employee
|
||||
List<Absence> employeeAbsences =
|
||||
allAbsences
|
||||
.stream()
|
||||
.filter(a -> a.getEmployee().equals(employee))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!employeeDailyReports.isEmpty() || !employeeAbsences.isEmpty()) {
|
||||
if (monthlyReportOpt.isPresent()) {
|
||||
MonthlyReport existingReport = monthlyReportOpt.get();
|
||||
System.out.println(
|
||||
"Update monthly report for employee: " + employee.getRegistrationNumber());
|
||||
// Update the existing monthly report
|
||||
Beans.get(MonthlyReportServiceImpl.class)
|
||||
.updateMensuelReport(
|
||||
existingReport,
|
||||
employee,
|
||||
period,
|
||||
startDate,
|
||||
endDate,
|
||||
employeeDailyReports,
|
||||
employeeAbsences);
|
||||
} else {
|
||||
System.out.println(
|
||||
"Create monthly report for employee: " + employee.getRegistrationNumber());
|
||||
// Create a new monthly report
|
||||
Beans.get(MonthlyReportServiceImpl.class)
|
||||
.createMensuelReport(
|
||||
employee, period, startDate, endDate, employeeDailyReports, employeeAbsences);
|
||||
}
|
||||
} else {
|
||||
System.err.println(
|
||||
"No Daily Reports exist for employee: " + employee.getRegistrationNumber());
|
||||
}
|
||||
}
|
||||
|
||||
// Indicate that the action was successful and a reload is needed
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
// Handle any exceptions
|
||||
e.printStackTrace();
|
||||
response.setError("An error occurred: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*public void calculePrimeAssiduite(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
Long monthlyReportId = (Long) request.getContext().asType(MonthlyReport.class).getId();
|
||||
MonthlyReport monthlyReport = Beans.get(MonthlyReportRepository.class).find(monthlyReportId);
|
||||
|
||||
Beans.get(MonthlyReportServiceImpl.class).calculePrimeAssiduite(monthlyReport);
|
||||
|
||||
// Indicate that the action was successful and a reload is needed
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
// Handle any exceptions
|
||||
e.printStackTrace();
|
||||
response.setError("An error occurred: " + e.getMessage());
|
||||
}
|
||||
}*/
|
||||
|
||||
private int calculateDaysExcludingFridaysAndThursdays(LocalDate endDate) {
|
||||
// Get the last day of the month for endDate
|
||||
LocalDate lastDayOfMonth = endDate.with(TemporalAdjusters.lastDayOfMonth());
|
||||
|
||||
// Calculate the number of days from endDate to lastDayOfMonth excluding Fridays and Thursdays
|
||||
int daysToLastDateExcludingFridaysAndThursdays = 0;
|
||||
LocalDate currentDate = endDate.plusDays(1); // Start from the day after endDate
|
||||
|
||||
while (!currentDate.isAfter(lastDayOfMonth)) {
|
||||
DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
|
||||
if (dayOfWeek != DayOfWeek.FRIDAY && dayOfWeek != DayOfWeek.THURSDAY) {
|
||||
daysToLastDateExcludingFridaysAndThursdays++;
|
||||
}
|
||||
currentDate = currentDate.plusDays(1); // Move to the next day
|
||||
}
|
||||
|
||||
return daysToLastDateExcludingFridaysAndThursdays;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.PayrollLeave;
|
||||
import com.axelor.apps.hr.db.PayrollPreparation;
|
||||
import com.axelor.apps.hr.db.repo.EmploymentContractRepository;
|
||||
import com.axelor.apps.hr.db.repo.HrBatchRepository;
|
||||
import com.axelor.apps.hr.db.repo.PayrollPreparationRepository;
|
||||
import com.axelor.apps.hr.service.PayrollPreparationService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@Singleton
|
||||
public class PayrollPreparationController {
|
||||
|
||||
public void generateFromEmploymentContract(ActionRequest request, ActionResponse response) {
|
||||
|
||||
PayrollPreparation payrollPreparation = request.getContext().asType(PayrollPreparation.class);
|
||||
EmploymentContract employmentContract =
|
||||
Beans.get(EmploymentContractRepository.class)
|
||||
.find(new Long(request.getContext().get("_idEmploymentContract").toString()));
|
||||
|
||||
response.setValues(
|
||||
Beans.get(PayrollPreparationService.class)
|
||||
.generateFromEmploymentContract(payrollPreparation, employmentContract));
|
||||
}
|
||||
|
||||
public void fillInPayrollPreparation(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
PayrollPreparation payrollPreparation = request.getContext().asType(PayrollPreparation.class);
|
||||
|
||||
List<PayrollLeave> payrollLeaveList =
|
||||
Beans.get(PayrollPreparationService.class).fillInPayrollPreparation(payrollPreparation);
|
||||
|
||||
response.setValue("extraHoursLineList", payrollPreparation.getExtraHoursLineList());
|
||||
response.setValue("$payrollLeavesList", payrollLeaveList);
|
||||
response.setValue("duration", payrollPreparation.getDuration());
|
||||
response.setValue("leaveDuration", payrollPreparation.getLeaveDuration());
|
||||
response.setValue("expenseAmount", payrollPreparation.getExpenseAmount());
|
||||
response.setValue("expenseList", payrollPreparation.getExpenseList());
|
||||
response.setValue(
|
||||
"otherCostsEmployeeSet",
|
||||
payrollPreparation.getEmploymentContract().getOtherCostsEmployeeSet());
|
||||
response.setValue(
|
||||
"annualGrossSalary", payrollPreparation.getEmploymentContract().getAnnualGrossSalary());
|
||||
response.setValue("employeeBonusMgtLineList", payrollPreparation.getEmployeeBonusMgtLineList());
|
||||
response.setValue("lunchVoucherNumber", payrollPreparation.getLunchVoucherNumber());
|
||||
response.setValue("lunchVoucherMgtLineList", payrollPreparation.getLunchVoucherMgtLineList());
|
||||
}
|
||||
|
||||
public void fillInPayrollPreparationLeaves(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
PayrollPreparation payrollPreparation = request.getContext().asType(PayrollPreparation.class);
|
||||
|
||||
List<PayrollLeave> payrollLeaveList =
|
||||
Beans.get(PayrollPreparationService.class).fillInLeaves(payrollPreparation);
|
||||
|
||||
response.setValue("$payrollLeavesList", payrollLeaveList);
|
||||
}
|
||||
|
||||
public void exportPayrollPreparation(ActionRequest request, ActionResponse response)
|
||||
throws IOException, AxelorException {
|
||||
|
||||
PayrollPreparationService payrollPreparationService =
|
||||
Beans.get(PayrollPreparationService.class);
|
||||
PayrollPreparation payrollPreparation =
|
||||
Beans.get(PayrollPreparationRepository.class)
|
||||
.find(request.getContext().asType(PayrollPreparation.class).getId());
|
||||
|
||||
if (payrollPreparation.getExportTypeSelect() == HrBatchRepository.EXPORT_TYPE_STANDARD) {
|
||||
response.setExportFile(
|
||||
payrollPreparationService.exportSinglePayrollPreparation(payrollPreparation));
|
||||
} else if (payrollPreparation.getExportTypeSelect() == HrBatchRepository.EXPORT_TYPE_NIBELIS) {
|
||||
response.setExportFile(
|
||||
payrollPreparationService.exportNibelisPayrollPreparation(payrollPreparation));
|
||||
}
|
||||
payrollPreparationService.closePayPeriodIfExported(payrollPreparation);
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web;
|
||||
|
||||
import com.axelor.apps.base.service.user.UserService;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.EmploymentContract;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.service.user.UserHrService;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.auth.db.repo.UserRepository;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.rpc.Context;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
@Singleton
|
||||
public class UserHrController {
|
||||
|
||||
@Transactional
|
||||
public void createEmployee(ActionRequest request, ActionResponse response) {
|
||||
User user =
|
||||
Beans.get(UserRepository.class).find(request.getContext().asType(User.class).getId());
|
||||
Beans.get(UserHrService.class).createEmployee(user);
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void createUser(ActionRequest request, ActionResponse response) {
|
||||
Context context = request.getContext();
|
||||
User user = context.asType(User.class);
|
||||
EmployeeRepository employeeRepository = Beans.get(EmployeeRepository.class);
|
||||
|
||||
User employeeUser = new User();
|
||||
employeeUser.setActivateOn(user.getActivateOn());
|
||||
employeeUser.setExpiresOn(user.getExpiresOn());
|
||||
employeeUser.setCode(user.getCode());
|
||||
employeeUser.setGroup(user.getGroup());
|
||||
|
||||
if (context.containsKey("_id")) {
|
||||
Object employeeId = context.get("_id");
|
||||
if (employeeId != null) {
|
||||
Employee employee = employeeRepository.find(Long.parseLong(employeeId.toString()));
|
||||
employeeUser.setEmployee(employeeRepository.find(employee.getId()));
|
||||
|
||||
if (employee.getContactPartner() != null) {
|
||||
String employeeName = employee.getContactPartner().getName();
|
||||
if (employee.getContactPartner().getFirstName() != null) {
|
||||
employeeName += " " + employee.getContactPartner().getFirstName();
|
||||
}
|
||||
employeeUser.setName(employeeName);
|
||||
if (employee.getContactPartner().getEmailAddress() != null) {
|
||||
employeeUser.setEmail(employee.getContactPartner().getEmailAddress().getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
if (employee.getMainEmploymentContract() != null) {
|
||||
employeeUser.setActiveCompany(employee.getMainEmploymentContract().getPayCompany());
|
||||
}
|
||||
|
||||
List<EmploymentContract> contractList = employee.getEmploymentContractList();
|
||||
if (contractList != null && !contractList.isEmpty()) {
|
||||
for (EmploymentContract employmentContract : contractList) {
|
||||
employeeUser.addCompanySetItem(employmentContract.getPayCompany());
|
||||
}
|
||||
}
|
||||
CharSequence password = Beans.get(UserService.class).generateRandomPassword();
|
||||
employeeUser.setPassword(password.toString());
|
||||
employee.setUser(employeeUser);
|
||||
}
|
||||
}
|
||||
|
||||
Beans.get(UserRepository.class).save(employeeUser);
|
||||
response.setCanClose(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,694 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
< * Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.hr.web.expense;
|
||||
|
||||
import com.axelor.apps.ReportFactory;
|
||||
import com.axelor.apps.account.db.Move;
|
||||
import com.axelor.apps.account.service.app.AppAccountService;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Product;
|
||||
import com.axelor.apps.base.db.Wizard;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.base.service.message.MessageServiceBaseImpl;
|
||||
import com.axelor.apps.hr.db.Employee;
|
||||
import com.axelor.apps.hr.db.Expense;
|
||||
import com.axelor.apps.hr.db.ExpenseLine;
|
||||
import com.axelor.apps.hr.db.ExtraHours;
|
||||
import com.axelor.apps.hr.db.KilometricAllowParam;
|
||||
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||
import com.axelor.apps.hr.db.repo.ExpenseRepository;
|
||||
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||
import com.axelor.apps.hr.report.IReport;
|
||||
import com.axelor.apps.hr.service.HRMenuTagService;
|
||||
import com.axelor.apps.hr.service.HRMenuValidateService;
|
||||
import com.axelor.apps.hr.service.KilometricService;
|
||||
import com.axelor.apps.hr.service.app.AppHumanResourceService;
|
||||
import com.axelor.apps.hr.service.expense.ExpenseService;
|
||||
import com.axelor.apps.hr.service.user.UserHrService;
|
||||
import com.axelor.apps.message.db.Message;
|
||||
import com.axelor.apps.message.db.repo.MessageRepository;
|
||||
import com.axelor.apps.report.engine.ReportSettings;
|
||||
import com.axelor.apps.tool.StringTool;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.db.JPA;
|
||||
import com.axelor.db.Query;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.ResponseMessageType;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.rpc.Context;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Singleton;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** @author axelor */
|
||||
@Singleton
|
||||
public class ExpenseController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
public void createAnalyticDistributionWithTemplate(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class);
|
||||
|
||||
expenseLine =
|
||||
Beans.get(ExpenseService.class).createAnalyticDistributionWithTemplate(expenseLine);
|
||||
response.setValue("analyticMoveLineList", expenseLine.getAnalyticMoveLineList());
|
||||
}
|
||||
|
||||
public void computeAnalyticDistribution(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class);
|
||||
Expense expense = expenseLine.getExpense();
|
||||
if (expense == null) {
|
||||
setExpense(request, expenseLine);
|
||||
}
|
||||
if (Beans.get(AppAccountService.class).getAppAccount().getManageAnalyticAccounting()) {
|
||||
expenseLine = Beans.get(ExpenseService.class).computeAnalyticDistribution(expenseLine);
|
||||
response.setValue("analyticMoveLineList", expenseLine.getAnalyticMoveLineList());
|
||||
}
|
||||
}
|
||||
|
||||
public void editExpense(ActionRequest request, ActionResponse response) {
|
||||
|
||||
User user = AuthUtils.getUser();
|
||||
Company activeCompany = user.getActiveCompany();
|
||||
|
||||
List<Expense> expenseList =
|
||||
Beans.get(ExpenseRepository.class)
|
||||
.all()
|
||||
.filter(
|
||||
"self.user = ?1 AND self.company = ?2 AND self.statusSelect = 1 AND (self.multipleUsers is false OR self.multipleUsers is null)",
|
||||
user,
|
||||
activeCompany)
|
||||
.fetch();
|
||||
if (expenseList.isEmpty()) {
|
||||
response.setView(
|
||||
ActionView.define(I18n.get("Expense"))
|
||||
.model(Expense.class.getName())
|
||||
.add("form", "expense-form")
|
||||
.context("_payCompany", Beans.get(UserHrService.class).getPayCompany(user))
|
||||
.map());
|
||||
} else if (expenseList.size() == 1) {
|
||||
response.setView(
|
||||
ActionView.define(I18n.get("Expense"))
|
||||
.model(Expense.class.getName())
|
||||
.add("form", "expense-form")
|
||||
.param("forceEdit", "true")
|
||||
.context("_showRecord", String.valueOf(expenseList.get(0).getId()))
|
||||
.map());
|
||||
} else {
|
||||
response.setView(
|
||||
ActionView.define(I18n.get("Expense"))
|
||||
.model(Wizard.class.getName())
|
||||
.add("form", "popup-expense-form")
|
||||
.param("forceEdit", "true")
|
||||
.param("popup", "true")
|
||||
.param("show-toolbar", "false")
|
||||
.param("show-confirm", "false")
|
||||
.param("forceEdit", "true")
|
||||
.param("popup-save", "false")
|
||||
.map());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void editExpenseSelected(ActionRequest request, ActionResponse response) {
|
||||
Map<String, Object> expenseMap =
|
||||
(Map<String, Object>) request.getContext().get("expenseSelect");
|
||||
|
||||
if (expenseMap == null) {
|
||||
response.setError(I18n.get(IExceptionMessage.EXPENSE_NOT_SELECTED));
|
||||
return;
|
||||
}
|
||||
Long expenseId = Long.valueOf((Integer) expenseMap.get("id"));
|
||||
response.setCanClose(true);
|
||||
response.setView(
|
||||
ActionView.define(I18n.get("Expense"))
|
||||
.model(Expense.class.getName())
|
||||
.add("form", "expense-form")
|
||||
.param("forceEdit", "true")
|
||||
.domain("self.id = " + expenseId)
|
||||
.context("_showRecord", expenseId)
|
||||
.map());
|
||||
}
|
||||
|
||||
public void validateExpense(ActionRequest request, ActionResponse response) {
|
||||
|
||||
User user = AuthUtils.getUser();
|
||||
Employee employee = user.getEmployee();
|
||||
|
||||
ActionViewBuilder actionView =
|
||||
ActionView.define(I18n.get("Expenses to Validate"))
|
||||
.model(Expense.class.getName())
|
||||
.add("grid", "expense-validate-grid")
|
||||
.add("form", "expense-form");
|
||||
|
||||
Beans.get(HRMenuValidateService.class).createValidateDomain(user, employee, actionView);
|
||||
|
||||
response.setView(actionView.map());
|
||||
}
|
||||
|
||||
public void historicExpense(ActionRequest request, ActionResponse response) {
|
||||
|
||||
User user = AuthUtils.getUser();
|
||||
Employee employee = user.getEmployee();
|
||||
|
||||
ActionViewBuilder actionView =
|
||||
ActionView.define(I18n.get("Historic colleague Expenses"))
|
||||
.model(Expense.class.getName())
|
||||
.add("grid", "expense-grid")
|
||||
.add("form", "expense-form");
|
||||
|
||||
actionView
|
||||
.domain(
|
||||
"self.company = :_activeCompany AND (self.statusSelect = 3 OR self.statusSelect = 4)")
|
||||
.context("_activeCompany", user.getActiveCompany());
|
||||
|
||||
if (employee == null || !employee.getHrManager()) {
|
||||
actionView
|
||||
.domain(actionView.get().getDomain() + " AND self.user.employee.managerUser = :_user")
|
||||
.context("_user", user);
|
||||
}
|
||||
|
||||
response.setView(actionView.map());
|
||||
}
|
||||
|
||||
public void showSubordinateExpenses(ActionRequest request, ActionResponse response) {
|
||||
|
||||
User user = AuthUtils.getUser();
|
||||
Company activeCompany = user.getActiveCompany();
|
||||
|
||||
ActionViewBuilder actionView =
|
||||
ActionView.define(I18n.get("Expenses to be Validated by your subordinates"))
|
||||
.model(Expense.class.getName())
|
||||
.add("grid", "expense-grid")
|
||||
.add("form", "expense-form");
|
||||
|
||||
String domain =
|
||||
"self.user.employee.managerUser.employee.managerUser = :_user AND self.company = :_activeCompany AND self.statusSelect = 2";
|
||||
|
||||
long nbExpenses =
|
||||
Query.of(ExtraHours.class)
|
||||
.filter(domain)
|
||||
.bind("_user", user)
|
||||
.bind("_activeCompany", activeCompany)
|
||||
.count();
|
||||
|
||||
if (nbExpenses == 0) {
|
||||
response.setNotify(I18n.get("No expense to be validated by your subordinates"));
|
||||
} else {
|
||||
response.setView(
|
||||
actionView
|
||||
.domain(domain)
|
||||
.context("_user", user)
|
||||
.context("_activeCompany", activeCompany)
|
||||
.map());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from expense form, on expense lines change. Call {@link ExpenseService#compute(Expense)}
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
public void compute(ActionRequest request, ActionResponse response) {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseService.class).compute(expense);
|
||||
response.setValues(expense);
|
||||
}
|
||||
|
||||
public void updateMoveDateAndPeriod(ActionRequest request, ActionResponse response) {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseService.class).updateMoveDateAndPeriod(expense);
|
||||
response.setValue("moveDate", expense.getMoveDate());
|
||||
response.setValue("period", expense.getPeriod());
|
||||
}
|
||||
|
||||
public void ventilate(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
try {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseRepository.class).find(expense.getId());
|
||||
Move move = Beans.get(ExpenseService.class).ventilate(expense);
|
||||
response.setReload(true);
|
||||
if (move != null) {
|
||||
response.setView(
|
||||
ActionView.define(I18n.get("Move"))
|
||||
.model(Move.class.getName())
|
||||
.add("grid", "move-grid")
|
||||
.add("form", "move-form")
|
||||
.context("_showRecord", String.valueOf(move.getId()))
|
||||
.map());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void printExpense(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
|
||||
String name = I18n.get("Expense") + " " + expense.getFullName().replace("/", "-");
|
||||
|
||||
String fileLink =
|
||||
ReportFactory.createReport(IReport.EXPENSE, name)
|
||||
.addParam("ExpenseId", expense.getId())
|
||||
.addParam("Locale", ReportSettings.getPrintingLocale(null))
|
||||
.toAttach(expense)
|
||||
.generate()
|
||||
.getFileLink();
|
||||
|
||||
logger.debug("Printing {}", name);
|
||||
|
||||
response.setView(ActionView.define(name).add("html", fileLink).map());
|
||||
}
|
||||
|
||||
/* Count Tags displayed on the menu items */
|
||||
|
||||
public String expenseValidateMenuTag() {
|
||||
|
||||
return Beans.get(HRMenuTagService.class)
|
||||
.countRecordsTag(Expense.class, ExpenseRepository.STATUS_CONFIRMED);
|
||||
}
|
||||
|
||||
public String expenseVentilateMenuTag() {
|
||||
Long total =
|
||||
JPA.all(Expense.class).filter("self.statusSelect = 3 AND self.ventilated = false").count();
|
||||
|
||||
return String.format("%s", total);
|
||||
}
|
||||
|
||||
public void cancel(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
try {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseRepository.class).find(expense.getId());
|
||||
ExpenseService expenseService = Beans.get(ExpenseService.class);
|
||||
|
||||
expenseService.cancel(expense);
|
||||
|
||||
Message message = expenseService.sendCancellationEmail(expense);
|
||||
if (message != null && message.getStatusSelect() == MessageRepository.STATUS_SENT) {
|
||||
response.setFlash(
|
||||
String.format(
|
||||
I18n.get("Email sent to %s"),
|
||||
Beans.get(MessageServiceBaseImpl.class).getToRecipients(message)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
} finally {
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPayment(ActionRequest request, ActionResponse response) {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseRepository.class).find(expense.getId());
|
||||
try {
|
||||
Beans.get(ExpenseService.class).addPayment(expense);
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on clicking cancelPaymentButton, call {@link ExpenseService#cancelPayment(Expense)}.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
public void cancelPayment(ActionRequest request, ActionResponse response) {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseRepository.class).find(expense.getId());
|
||||
try {
|
||||
Beans.get(ExpenseService.class).cancelPayment(expense);
|
||||
response.setReload(true);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
// sending expense and sending mail to manager
|
||||
public void send(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
|
||||
try {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseRepository.class).find(expense.getId());
|
||||
ExpenseService expenseService = Beans.get(ExpenseService.class);
|
||||
|
||||
expenseService.confirm(expense);
|
||||
|
||||
Message message = expenseService.sendConfirmationEmail(expense);
|
||||
if (message != null && message.getStatusSelect() == MessageRepository.STATUS_SENT) {
|
||||
response.setFlash(
|
||||
String.format(
|
||||
I18n.get("Email sent to %s"),
|
||||
Beans.get(MessageServiceBaseImpl.class).getToRecipients(message)));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
} finally {
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void newExpense(ActionResponse response) {
|
||||
|
||||
response.setView(
|
||||
ActionView.define(I18n.get("Expense"))
|
||||
.model(Expense.class.getName())
|
||||
.add("form", "expense-form")
|
||||
.context(
|
||||
"_payCompany", Beans.get(UserHrService.class).getPayCompany(AuthUtils.getUser()))
|
||||
.map());
|
||||
}
|
||||
|
||||
// validating expense and sending mail to applicant
|
||||
public void valid(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
|
||||
try {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseRepository.class).find(expense.getId());
|
||||
ExpenseService expenseService = Beans.get(ExpenseService.class);
|
||||
|
||||
expenseService.validate(expense);
|
||||
|
||||
Message message = expenseService.sendValidationEmail(expense);
|
||||
if (message != null && message.getStatusSelect() == MessageRepository.STATUS_SENT) {
|
||||
response.setFlash(
|
||||
String.format(
|
||||
I18n.get("Email sent to %s"),
|
||||
Beans.get(MessageServiceBaseImpl.class).getToRecipients(message)));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
} finally {
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
|
||||
// refusing expense and sending mail to applicant
|
||||
public void refuse(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||
|
||||
try {
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
expense = Beans.get(ExpenseRepository.class).find(expense.getId());
|
||||
ExpenseService expenseService = Beans.get(ExpenseService.class);
|
||||
|
||||
expenseService.refuse(expense);
|
||||
|
||||
Message message = expenseService.sendRefusalEmail(expense);
|
||||
if (message != null && message.getStatusSelect() == MessageRepository.STATUS_SENT) {
|
||||
response.setFlash(
|
||||
String.format(
|
||||
I18n.get("Email sent to %s"),
|
||||
Beans.get(MessageServiceBaseImpl.class).getToRecipients(message)));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
} finally {
|
||||
response.setReload(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void fillKilometricExpenseProduct(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
try {
|
||||
Expense expense = request.getContext().getParent().asType(Expense.class);
|
||||
Product expenseProduct = Beans.get(ExpenseService.class).getKilometricExpenseProduct(expense);
|
||||
logger.debug("Get Kilometric expense product : {}", expenseProduct);
|
||||
response.setValue("expenseProduct", expenseProduct);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateAndCompute(ActionRequest request, ActionResponse response) {
|
||||
|
||||
Expense expense = request.getContext().asType(Expense.class);
|
||||
ExpenseService expenseService = Beans.get(ExpenseService.class);
|
||||
|
||||
List<Integer> expenseLineListId = new ArrayList<>();
|
||||
int compt = 0;
|
||||
for (ExpenseLine expenseLine : expenseService.getExpenseLineList(expense)) {
|
||||
compt++;
|
||||
if (expenseLine.getExpenseDate().isAfter(Beans.get(AppBaseService.class).getTodayDate())) {
|
||||
expenseLineListId.add(compt);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!expenseLineListId.isEmpty()) {
|
||||
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get("Date can't be in the future for line(s) : %s"),
|
||||
expenseLineListId.stream().map(id -> id.toString()).collect(Collectors.joining(",")));
|
||||
}
|
||||
|
||||
} catch (AxelorException e) {
|
||||
|
||||
TraceBackService.trace(response, e, ResponseMessageType.ERROR);
|
||||
}
|
||||
|
||||
response.setValue(
|
||||
"personalExpenseAmount", expenseService.computePersonalExpenseAmount(expense));
|
||||
response.setValue("advanceAmount", expenseService.computeAdvanceAmount(expense));
|
||||
|
||||
if (expense.getKilometricExpenseLineList() != null
|
||||
&& !expense.getKilometricExpenseLineList().isEmpty()) {
|
||||
response.setValue("kilometricExpenseLineList", expense.getKilometricExpenseLineList());
|
||||
}
|
||||
|
||||
compute(request, response);
|
||||
}
|
||||
|
||||
public void computeKilometricExpense(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class);
|
||||
if (expenseLine.getKilometricAllowParam() == null
|
||||
|| expenseLine.getDistance().compareTo(BigDecimal.ZERO) == 0
|
||||
|| expenseLine.getExpenseDate() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String userId;
|
||||
String userName;
|
||||
if (expenseLine.getExpense() != null) {
|
||||
setExpense(request, expenseLine);
|
||||
}
|
||||
Expense expense = expenseLine.getExpense();
|
||||
|
||||
if (expense != null && expenseLine.getUser() != null) {
|
||||
userId = expense.getUser().getId().toString();
|
||||
userName = expense.getUser().getFullName();
|
||||
} else {
|
||||
userId = request.getContext().getParent().asType(Expense.class).getUser().getId().toString();
|
||||
userName = request.getContext().getParent().asType(Expense.class).getUser().getFullName();
|
||||
}
|
||||
Employee employee =
|
||||
Beans.get(EmployeeRepository.class).all().filter("self.user.id = ?1", userId).fetchOne();
|
||||
|
||||
if (employee == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),
|
||||
userName);
|
||||
}
|
||||
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
try {
|
||||
amount = Beans.get(KilometricService.class).computeKilometricExpense(expenseLine, employee);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
|
||||
response.setValue("totalAmount", amount);
|
||||
response.setValue("untaxedAmount", amount);
|
||||
}
|
||||
|
||||
public void updateKAPOfKilometricAllowance(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class);
|
||||
|
||||
if (expenseLine.getExpense() == null) {
|
||||
setExpense(request, expenseLine);
|
||||
}
|
||||
|
||||
try {
|
||||
List<KilometricAllowParam> kilometricAllowParamList =
|
||||
Beans.get(ExpenseService.class).getListOfKilometricAllowParamVehicleFilter(expenseLine);
|
||||
if (kilometricAllowParamList == null || kilometricAllowParamList.isEmpty()) {
|
||||
response.setAttr("kilometricAllowParam", "domain", "self.id IN (0)");
|
||||
} else {
|
||||
response.setAttr(
|
||||
"kilometricAllowParam",
|
||||
"domain",
|
||||
"self.id IN (" + StringTool.getIdListString(kilometricAllowParamList) + ")");
|
||||
}
|
||||
|
||||
KilometricAllowParam currentKilometricAllowParam = expenseLine.getKilometricAllowParam();
|
||||
boolean vehicleOk = false;
|
||||
|
||||
if (kilometricAllowParamList != null && kilometricAllowParamList.size() == 1) {
|
||||
response.setValue("kilometricAllowParam", kilometricAllowParamList.get(0));
|
||||
} else if (kilometricAllowParamList != null) {
|
||||
for (KilometricAllowParam kilometricAllowParam : kilometricAllowParamList) {
|
||||
if (currentKilometricAllowParam != null
|
||||
&& currentKilometricAllowParam.equals(kilometricAllowParam)) {
|
||||
expenseLine.setKilometricAllowParam(kilometricAllowParam);
|
||||
vehicleOk = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!vehicleOk) {
|
||||
response.setValue("kilometricAllowParam", null);
|
||||
} else {
|
||||
response.setValue("kilometricAllowParam", expenseLine.getKilometricAllowParam());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setExpense(ActionRequest request, ExpenseLine expenseLine) {
|
||||
|
||||
Context parent = request.getContext().getParent();
|
||||
|
||||
if (parent != null && parent.get("_model").equals(Expense.class.getName())) {
|
||||
expenseLine.setExpense(parent.asType(Expense.class));
|
||||
}
|
||||
}
|
||||
|
||||
public void domainOnSelectOnKAP(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class);
|
||||
|
||||
if (expenseLine.getExpense() == null) {
|
||||
setExpense(request, expenseLine);
|
||||
}
|
||||
|
||||
try {
|
||||
List<KilometricAllowParam> kilometricAllowParamList =
|
||||
Beans.get(ExpenseService.class).getListOfKilometricAllowParamVehicleFilter(expenseLine);
|
||||
response.setAttr(
|
||||
"kilometricAllowParam",
|
||||
"domain",
|
||||
"self.id IN (" + StringTool.getIdListString(kilometricAllowParamList) + ")");
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void computeDistanceAndKilometricExpense(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
// Compute distance.
|
||||
try {
|
||||
|
||||
if (!Beans.get(AppHumanResourceService.class)
|
||||
.getAppExpense()
|
||||
.getComputeDistanceWithWebService()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Context context = request.getContext();
|
||||
ExpenseLine expenseLine = context.asType(ExpenseLine.class);
|
||||
|
||||
if (Strings.isNullOrEmpty(expenseLine.getFromCity())
|
||||
|| Strings.isNullOrEmpty(expenseLine.getToCity())) {
|
||||
return;
|
||||
}
|
||||
|
||||
KilometricService kilometricService = Beans.get(KilometricService.class);
|
||||
BigDecimal distance = kilometricService.computeDistance(expenseLine);
|
||||
expenseLine.setDistance(distance);
|
||||
response.setValue("distance", distance);
|
||||
|
||||
// Compute kilometric expense.
|
||||
|
||||
if (expenseLine.getKilometricAllowParam() == null
|
||||
|| expenseLine.getExpenseDate() == null
|
||||
|| expenseLine.getKilometricTypeSelect() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Expense expense = expenseLine.getExpense();
|
||||
|
||||
if (expense == null) {
|
||||
expense = context.getParent().asType(Expense.class);
|
||||
}
|
||||
|
||||
Employee employee = expense.getUser().getEmployee();
|
||||
|
||||
if (employee == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),
|
||||
expense.getUser().getName());
|
||||
}
|
||||
|
||||
BigDecimal amount = kilometricService.computeKilometricExpense(expenseLine, employee);
|
||||
response.setValue("totalAmount", amount);
|
||||
response.setValue("untaxedAmount", amount);
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user