Add : Attendance Module + QVM Module
This commit is contained in:
@@ -22,12 +22,12 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import wslite.json.JSONException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
|
||||||
import org.apache.batik.util.io.StringDecoder;
|
import org.apache.batik.util.io.StringDecoder;
|
||||||
|
|
||||||
@@ -48,9 +48,6 @@ import com.axelor.meta.schema.actions.ActionView;
|
|||||||
import com.axelor.rpc.ActionRequest;
|
import com.axelor.rpc.ActionRequest;
|
||||||
import com.axelor.rpc.ActionResponse;
|
import com.axelor.rpc.ActionResponse;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import com.mongodb.util.JSON;
|
|
||||||
|
|
||||||
import net.minidev.json.JSONObject;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class AppBaseController {
|
public class AppBaseController {
|
||||||
@@ -174,4 +171,69 @@ public class AppBaseController {
|
|||||||
Process p = Runtime.getRuntime().exec(args);
|
Process p = Runtime.getRuntime().exec(args);
|
||||||
// BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
// BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getAccessToken() throws Exception {
|
||||||
|
AppSettings appSettings = AppSettings.get();
|
||||||
|
String BASE_URL = appSettings.get("portail.api.baseurl");
|
||||||
|
String username = appSettings.get("portail.api.user");
|
||||||
|
String password = appSettings.get("portail.api.password");
|
||||||
|
|
||||||
|
String endpoint = BASE_URL + "token/";
|
||||||
|
URL url = new URL(endpoint);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
conn.setRequestProperty("Content-Type", "application/json");
|
||||||
|
conn.setRequestProperty("Accept", "application/json");
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
|
||||||
|
// Create a JSON object for the input
|
||||||
|
JSONObject jsonInput = new JSONObject();
|
||||||
|
jsonInput.put("username", username);
|
||||||
|
jsonInput.put("password", password);
|
||||||
|
|
||||||
|
// Write the JSON input to the output stream
|
||||||
|
try (OutputStream os = conn.getOutputStream()) {
|
||||||
|
byte[] input = jsonInput.toString().getBytes("utf-8");
|
||||||
|
os.write(input, 0, input.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
return parseAccessToken(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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the JSON response to extract the access token
|
||||||
|
private static String parseAccessToken(String jsonResponse) {
|
||||||
|
try {
|
||||||
|
JSONObject jsonObject = new JSONObject(jsonResponse);
|
||||||
|
return jsonObject.get("access").toString(); // Extract the access token
|
||||||
|
} catch (JSONException e) {
|
||||||
|
System.err.println("Failed to parse JSON: " + jsonResponse);
|
||||||
|
e.printStackTrace();
|
||||||
|
return null; // Handle error appropriately
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -208,4 +208,8 @@ public interface IExceptionMessage {
|
|||||||
|
|
||||||
static final String EMPLOYEE_TIMESHEET_REMINDER_TEMPLATE = /*$$(*/
|
static final String EMPLOYEE_TIMESHEET_REMINDER_TEMPLATE = /*$$(*/
|
||||||
"Please configure the template for email reminder" /*)*/;
|
"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,85 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
public class FetchAttendanceJob implements Job {
|
||||||
|
|
||||||
|
private final Logger log = LoggerFactory.getLogger(FetchCheckInOutJob.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(JobExecutionContext context) throws JobExecutionException{
|
||||||
|
|
||||||
|
if (isRunning(context)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Define the command to run the Python script with the correct path (V3)
|
||||||
|
String[] args = {"python", "C:\\Users\\administrator\\Desktop\\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,99 @@
|
|||||||
|
package com.axelor.apps.hr.job;
|
||||||
|
|
||||||
|
import com.axelor.apps.hr.db.CheckInOut;
|
||||||
|
import com.axelor.apps.hr.db.repo.CheckInOutRepository;
|
||||||
|
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 com.axelor.inject.Beans;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import org.quartz.SchedulerException;
|
||||||
|
|
||||||
|
public class FetchCheckInOutJob implements Job {
|
||||||
|
|
||||||
|
private final Logger log = LoggerFactory.getLogger(FetchCheckInOutJob.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||||
|
|
||||||
|
if (isRunning(context)) {
|
||||||
|
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", "C:\\Users\\administrator\\Desktop\\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,214 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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,24 @@
|
|||||||
|
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.util.List;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public interface AbsenceService {
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void attachTheAbsenceWithDailyReport(Absence absence, List<DailyReport> dailyreports);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void deAttachTheAbsenceWithDailyReport(Absence absence, List<DailyReport> dailyreports);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void chooseAbsenceType(Absence absence, String selectedType);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
BigDecimal calculateTotalAbsenceHours(LocalDateTime absenceStartDate, LocalDateTime absenceEndDate);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
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.EventsPlanningRepository;
|
||||||
|
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.google.inject.Inject;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
import java.util.List;
|
||||||
|
import java.time.Year;
|
||||||
|
import java.time.DayOfWeek;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
|
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.setAbsence(absence); // Set the absence for each report
|
||||||
|
dailyReportRepository.save(dailyreport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void deAttachTheAbsenceWithDailyReport(Absence absence, List<DailyReport> dailyreports) {
|
||||||
|
if(dailyreports != null){
|
||||||
|
// Iterate over each DailyReport in the list
|
||||||
|
for (DailyReport dailyreport : dailyreports) {
|
||||||
|
dailyreport.setAbsence(null); // Set the absence for each report
|
||||||
|
dailyReportRepository.save(dailyreport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
absence.setArchived(true);
|
||||||
|
absenceRepository.save(absence);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void chooseAbsenceType(Absence absence, String 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSpecialOvertimeDay(LocalDate date) {
|
||||||
|
for (EventsPlanningLine line : eventsPlanningLines) {
|
||||||
|
if (line.getDate().equals(date)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,498 @@
|
|||||||
|
package com.axelor.apps.hr.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.hr.db.Authorization;
|
||||||
|
import com.axelor.apps.hr.db.Employee;
|
||||||
|
import com.axelor.apps.hr.db.DailyReport;
|
||||||
|
import com.axelor.apps.hr.db.repo.AuthorizationRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
|
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 java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import wslite.json.JSONException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
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.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(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.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 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.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,13 @@
|
|||||||
|
package com.axelor.apps.hr.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.hr.db.DailyReport;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
|
|
||||||
|
public interface DailyReportService {
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void workingHours(DailyReport DailyReport);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void determineShift(DailyReport DailyReport);
|
||||||
|
}
|
||||||
@@ -0,0 +1,548 @@
|
|||||||
|
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.EventsPlanningRepository;
|
||||||
|
import com.axelor.apps.base.db.repo.EventsPlanningLineRepository;
|
||||||
|
import com.axelor.apps.hr.db.Absence;
|
||||||
|
import com.axelor.apps.hr.db.Employee;
|
||||||
|
import com.axelor.apps.hr.db.OffDayWork;
|
||||||
|
import com.axelor.apps.hr.db.DailyReport;
|
||||||
|
import com.axelor.apps.hr.db.Shift;
|
||||||
|
import com.axelor.apps.hr.db.Authorization;
|
||||||
|
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.AuthorizationRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.OffDayWorkRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.ShiftRepository;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
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.time.Year;
|
||||||
|
import java.util.List;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
LocalTime shiftStartHour = null, shiftEndHour = null;
|
||||||
|
if(shift != null){
|
||||||
|
System.out.println("rapporurnalier: ????????????????"+ dailyReport.getId());
|
||||||
|
shiftStartHour = dailyReport.getShift().getStartHour();
|
||||||
|
shiftEndHour = dailyReport.getShift().getEndHour();
|
||||||
|
System.out.println("Shift: "+ shift);
|
||||||
|
System.out.println("shiftStartHour: "+ shiftStartHour);
|
||||||
|
System.out.println("shiftENDHour: "+ shiftEndHour);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enters[0] != null && quits[0] != null) {
|
||||||
|
// Calculate total work duration
|
||||||
|
Duration totalDuration = Duration.ZERO;
|
||||||
|
Duration totalSupDuration = Duration.ZERO;
|
||||||
|
Duration nightDuration = Duration.ZERO;
|
||||||
|
Duration pauseDuration = Duration.ZERO;
|
||||||
|
LocalDateTime firstEnter = enters[0];
|
||||||
|
LocalDateTime 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(customRound(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(customRound(totalNightHours));
|
||||||
|
|
||||||
|
// Pause Hours
|
||||||
|
pauseDuration = calculatePauseDuration(enters, quits, employee);
|
||||||
|
long pauseMinutes = pauseDuration.toMinutes();
|
||||||
|
BigDecimal pauseHours = BigDecimal.valueOf(pauseMinutes).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
|
||||||
|
dailyReport.setBreakHours(customRound(pauseHours));
|
||||||
|
|
||||||
|
// 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(customRound(extraHours100));
|
||||||
|
dailyReport.setExtraHours50(customRound(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(customRound(totalHours).subtract(customRound(totalNightHours)));
|
||||||
|
dailyReport.setExtraHours100(customRound(totalNightHours));
|
||||||
|
dailyReport.setAllowanceRecall(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||||
|
} else {
|
||||||
|
dailyReport.setExtraHours50(customRound(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(customRound(totalHours));
|
||||||
|
dailyReport.setAllowanceRecall(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(shift == 0 || shift == 3){
|
||||||
|
dailyReport.setExtraHours50(customRound(totalSupHours).subtract(customRound(totalNightHours)));
|
||||||
|
dailyReport.setExtraHours100(customRound(totalNightHours));
|
||||||
|
dailyReport.setAllowance(totalHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||||
|
dailyReport.setAllowanceRecall(totalSupHours.compareTo(BigDecimal.valueOf(5)) >= 0 ? 1 : 0);
|
||||||
|
} else {
|
||||||
|
dailyReport.setExtraHours50(customRound(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(customRound(calculateItp(totalHours, shift,dailyReport.getHasItp())));
|
||||||
|
dailyReport.setIsCalculated(true);
|
||||||
|
|
||||||
|
} else if (enters[0] != null && quits[0] == null) {
|
||||||
|
// When the employee registers attendance only once
|
||||||
|
dailyReport.setWorkHours(BigDecimal.valueOf(8));
|
||||||
|
dailyReport.setAbsenceHours(BigDecimal.valueOf(0));
|
||||||
|
dailyReport.setIsCalculated(true);
|
||||||
|
} else if (enters.length != quits.length) {
|
||||||
|
|
||||||
|
Duration totalDuration = Duration.ZERO;
|
||||||
|
LocalDateTime firstEnter = enters[0];
|
||||||
|
LocalDateTime 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(customRound(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 {
|
||||||
|
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")
|
||||||
|
.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){
|
||||||
|
Authorization authorization = Beans.get(AuthorizationRepository.class)
|
||||||
|
.all()
|
||||||
|
.filter("self.employee = :employee and self.requisitionDate = :reportDate")
|
||||||
|
.bind("employee",employee)
|
||||||
|
.bind("reportDate",reportDate)
|
||||||
|
.fetchOne();
|
||||||
|
if (authorization != null) {
|
||||||
|
authorization.setDailyReport(dailyReport);
|
||||||
|
if(authorization.getStatusSelect() == 3)
|
||||||
|
dailyReport.setIsAuthorizedAbsence(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(customRound(BigDecimal.valueOf(8).subtract(dailyReport.getWorkHours())));
|
||||||
|
} 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 calculatePauseDuration(
|
||||||
|
LocalDateTime[] enters, LocalDateTime[] quits, Employee employee) {
|
||||||
|
|
||||||
|
Duration pauseDuration = Duration.ZERO;
|
||||||
|
for (int i = 1; i < quits.length; i++) {
|
||||||
|
if (enters[i] != null && quits[i - 1] != null) {
|
||||||
|
pauseDuration = pauseDuration.plus(Duration.between(quits[i - 1], enters[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pauseDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal calculateItp(BigDecimal totalHours, Integer shift, Boolean hasItp) {
|
||||||
|
// Shift 0 (no itp)
|
||||||
|
if (hasItp == false)
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
else
|
||||||
|
return totalHours.min(BigDecimal.valueOf(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
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.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 calculePrimeAssiduite(Mensuels mensuels);*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
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.Authorization;
|
||||||
|
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.DailyReport;
|
||||||
|
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.AuthorizationRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.MonthlyReportRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.temporal.TemporalAdjusters;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
|
||||||
|
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();
|
||||||
|
BigDecimal heureSup100 = dailyReport.getExtraHours100();
|
||||||
|
BigDecimal itp = dailyReport.getItp();
|
||||||
|
BigDecimal nuissance = dailyReport.getNuissance();
|
||||||
|
|
||||||
|
if(dailyReport.getDeduceSupHours50())
|
||||||
|
heureSup50 = heureSup50.subtract(dailyReport.getSupHours50ToDeduce());
|
||||||
|
if(dailyReport.getDeduceSupHours100())
|
||||||
|
heureSup100 = heureSup100.subtract(dailyReport.getSupHours100ToDeduce());
|
||||||
|
if(dailyReport.getDeduceItp())
|
||||||
|
itp = itp.subtract(dailyReport.getItpToDeduce());
|
||||||
|
if(dailyReport.getDeduceNuissance())
|
||||||
|
nuissance = nuissance.subtract(dailyReport.getNuissanceToDeduce());
|
||||||
|
|
||||||
|
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();
|
||||||
|
LeaveRequest leaveRequest = dailyReport.getLeaveRequest();
|
||||||
|
Absence absence = dailyReport.getAbsence();
|
||||||
|
|
||||||
|
if (isAuthorizedAbsence == false && leaveRequest == null && absence == null) {
|
||||||
|
irregularAbsenceMonth = irregularAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||||
|
} else if(isAuthorizedAbsence){
|
||||||
|
justifiedAbsenceMonth = justifiedAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||||
|
} else if(leaveRequest != null){
|
||||||
|
recuperationLeaveAbsenceMonth = recuperationLeaveAbsenceMonth.add(dailyReport.getAbsenceHours());
|
||||||
|
} else if(absence != null){
|
||||||
|
totalAbsence = dailyReport.getAbsenceHours();
|
||||||
|
switch (absence.getAbsenceType()) {
|
||||||
|
case "Absence autorisé de payée":
|
||||||
|
breastfeedingAbsenceMonth = breastfeedingAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence allaitement":
|
||||||
|
breastfeedingAbsenceMonth = breastfeedingAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence congé récupération":
|
||||||
|
recuperationLeaveAbsenceMonth = recuperationLeaveAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence formation":
|
||||||
|
trainingAbsenceMonth = trainingAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence mission":
|
||||||
|
missionAbsenceMonth = missionAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence hospitalisation":
|
||||||
|
hospitalizationAbsenceMonth = hospitalizationAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence maladie":
|
||||||
|
sicknessAbsenceMonth = sicknessAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Accident de travail":
|
||||||
|
workAccidentMonth = workAccidentMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Maternité":
|
||||||
|
maternityMonth = maternityMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence autorisée non payée":
|
||||||
|
authorizedUnpaidAbsenceMonth = authorizedUnpaidAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence conge annuel":
|
||||||
|
annualLeaveAbsenceMonth = annualLeaveAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence conge sans solde":
|
||||||
|
unpaidLeaveAbsenceMonth = unpaidLeaveAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence conge statutaire":
|
||||||
|
statutoryLeaveAbsenceMonth = statutoryLeaveAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence démission":
|
||||||
|
resignationAbsenceMonth = resignationAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence fin de contrat":
|
||||||
|
contractEndAbsenceMonth = contractEndAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence justifieé":
|
||||||
|
justifiedAbsenceMonth = justifiedAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence recrutement":
|
||||||
|
recruitmentAbsenceMonth = recruitmentAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Suspension":
|
||||||
|
suspensionAbsenceMonth = suspensionAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence irrégulière":
|
||||||
|
irregularAbsenceMonth = irregularAbsenceMonth.add(totalAbsence);
|
||||||
|
break;
|
||||||
|
case "Absence service militaire":
|
||||||
|
militaryServiceAbsence = militaryServiceAbsence.add(totalAbsence);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import com.axelor.exception.AxelorException;
|
|||||||
import com.google.inject.persist.Transactional;
|
import com.google.inject.persist.Transactional;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
|
||||||
public interface ExtraHoursService {
|
public interface ExtraHoursService {
|
||||||
|
|
||||||
@@ -50,6 +51,9 @@ public interface ExtraHoursService {
|
|||||||
@Transactional(rollbackOn = {Exception.class})
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
public void refuse(ExtraHours extraHours) throws AxelorException;
|
public void refuse(ExtraHours extraHours) throws AxelorException;
|
||||||
|
|
||||||
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
|
public void saveExtraHours(JSONObject jsonObject) throws AxelorException;
|
||||||
|
|
||||||
public Message sendRefusalEmail(ExtraHours extraHours)
|
public Message sendRefusalEmail(ExtraHours extraHours)
|
||||||
throws AxelorException, ClassNotFoundException, InstantiationException,
|
throws AxelorException, ClassNotFoundException, InstantiationException,
|
||||||
IllegalAccessException, MessagingException, IOException;
|
IllegalAccessException, MessagingException, IOException;
|
||||||
|
|||||||
@@ -17,6 +17,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.hr.service.extra.hours;
|
package com.axelor.apps.hr.service.extra.hours;
|
||||||
|
|
||||||
|
|
||||||
|
import com.axelor.apps.hr.db.DailyReport;
|
||||||
|
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
|
import com.axelor.apps.hr.db.Employee;
|
||||||
|
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.base.service.app.AppBaseService;
|
||||||
import com.axelor.apps.hr.db.ExtraHours;
|
import com.axelor.apps.hr.db.ExtraHours;
|
||||||
import com.axelor.apps.hr.db.ExtraHoursLine;
|
import com.axelor.apps.hr.db.ExtraHoursLine;
|
||||||
@@ -30,9 +37,17 @@ import com.axelor.exception.AxelorException;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.persist.Transactional;
|
import com.google.inject.persist.Transactional;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
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.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
|
import wslite.json.JSONException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
|
||||||
public class ExtraHoursServiceImpl implements ExtraHoursService {
|
public class ExtraHoursServiceImpl implements ExtraHoursService {
|
||||||
|
|
||||||
@@ -40,15 +55,24 @@ public class ExtraHoursServiceImpl implements ExtraHoursService {
|
|||||||
protected AppBaseService appBaseService;
|
protected AppBaseService appBaseService;
|
||||||
protected HRConfigService hrConfigService;
|
protected HRConfigService hrConfigService;
|
||||||
protected TemplateMessageService templateMessageService;
|
protected TemplateMessageService templateMessageService;
|
||||||
|
protected CompanyRepository companyRepo;
|
||||||
|
protected DailyReportRepository dailyReportRepo;
|
||||||
|
protected EmployeeRepository employeeRepo;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ExtraHoursServiceImpl(
|
public ExtraHoursServiceImpl(
|
||||||
|
EmployeeRepository employeeRepo,
|
||||||
|
CompanyRepository companyRepo,
|
||||||
|
DailyReportRepository dailyReportRepo,
|
||||||
ExtraHoursRepository extraHoursRepo,
|
ExtraHoursRepository extraHoursRepo,
|
||||||
AppBaseService appBaseService,
|
AppBaseService appBaseService,
|
||||||
HRConfigService hrConfigService,
|
HRConfigService hrConfigService,
|
||||||
TemplateMessageService templateMessageService) {
|
TemplateMessageService templateMessageService) {
|
||||||
|
|
||||||
this.extraHoursRepo = extraHoursRepo;
|
this.extraHoursRepo = extraHoursRepo;
|
||||||
|
this.employeeRepo = employeeRepo;
|
||||||
|
this.companyRepo = companyRepo;
|
||||||
|
this.dailyReportRepo = dailyReportRepo;
|
||||||
this.appBaseService = appBaseService;
|
this.appBaseService = appBaseService;
|
||||||
this.hrConfigService = hrConfigService;
|
this.hrConfigService = hrConfigService;
|
||||||
this.templateMessageService = templateMessageService;
|
this.templateMessageService = templateMessageService;
|
||||||
@@ -162,4 +186,188 @@ public class ExtraHoursServiceImpl implements ExtraHoursService {
|
|||||||
|
|
||||||
extraHours.setTotalQty(totalQty);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,13 @@ import java.math.BigDecimal;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
|
||||||
public interface LeaveService {
|
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) throws AxelorException;
|
||||||
|
|
||||||
public BigDecimal computeDuration(LeaveRequest leave, LocalDate fromDate, LocalDate toDate)
|
public BigDecimal computeDuration(LeaveRequest leave, LocalDate fromDate, LocalDate toDate)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.axelor.apps.base.db.DayPlanning;
|
|||||||
import com.axelor.apps.base.db.EventsPlanning;
|
import com.axelor.apps.base.db.EventsPlanning;
|
||||||
import com.axelor.apps.base.db.ICalendarEvent;
|
import com.axelor.apps.base.db.ICalendarEvent;
|
||||||
import com.axelor.apps.base.db.WeeklyPlanning;
|
import com.axelor.apps.base.db.WeeklyPlanning;
|
||||||
|
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||||
import com.axelor.apps.base.db.repo.ICalendarEventRepository;
|
import com.axelor.apps.base.db.repo.ICalendarEventRepository;
|
||||||
import com.axelor.apps.base.ical.ICalendarService;
|
import com.axelor.apps.base.ical.ICalendarService;
|
||||||
import com.axelor.apps.base.service.app.AppBaseService;
|
import com.axelor.apps.base.service.app.AppBaseService;
|
||||||
@@ -31,6 +32,9 @@ import com.axelor.apps.hr.db.HRConfig;
|
|||||||
import com.axelor.apps.hr.db.LeaveLine;
|
import com.axelor.apps.hr.db.LeaveLine;
|
||||||
import com.axelor.apps.hr.db.LeaveReason;
|
import com.axelor.apps.hr.db.LeaveReason;
|
||||||
import com.axelor.apps.hr.db.LeaveRequest;
|
import com.axelor.apps.hr.db.LeaveRequest;
|
||||||
|
import com.axelor.apps.hr.db.DailyReport;
|
||||||
|
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
import com.axelor.apps.hr.db.repo.LeaveLineRepository;
|
import com.axelor.apps.hr.db.repo.LeaveLineRepository;
|
||||||
import com.axelor.apps.hr.db.repo.LeaveReasonRepository;
|
import com.axelor.apps.hr.db.repo.LeaveReasonRepository;
|
||||||
import com.axelor.apps.hr.db.repo.LeaveRequestRepository;
|
import com.axelor.apps.hr.db.repo.LeaveRequestRepository;
|
||||||
@@ -55,6 +59,12 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
|
import wslite.json.JSONException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
|
||||||
|
|
||||||
public class LeaveServiceImpl implements LeaveService {
|
public class LeaveServiceImpl implements LeaveService {
|
||||||
|
|
||||||
@@ -67,10 +77,16 @@ public class LeaveServiceImpl implements LeaveService {
|
|||||||
protected TemplateMessageService templateMessageService;
|
protected TemplateMessageService templateMessageService;
|
||||||
protected ICalendarEventRepository icalEventRepo;
|
protected ICalendarEventRepository icalEventRepo;
|
||||||
protected ICalendarService icalendarService;
|
protected ICalendarService icalendarService;
|
||||||
|
protected CompanyRepository companyRepo;
|
||||||
|
protected DailyReportRepository dailyReportRepo;
|
||||||
|
protected EmployeeRepository employeeRepo;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LeaveServiceImpl(
|
public LeaveServiceImpl(
|
||||||
LeaveLineRepository leaveLineRepo,
|
LeaveLineRepository leaveLineRepo,
|
||||||
|
CompanyRepository companyRepo,
|
||||||
|
DailyReportRepository dailyReportRepo,
|
||||||
|
EmployeeRepository employeeRepo,
|
||||||
WeeklyPlanningService weeklyPlanningService,
|
WeeklyPlanningService weeklyPlanningService,
|
||||||
PublicHolidayHrService publicHolidayHrService,
|
PublicHolidayHrService publicHolidayHrService,
|
||||||
LeaveRequestRepository leaveRequestRepo,
|
LeaveRequestRepository leaveRequestRepo,
|
||||||
@@ -89,6 +105,9 @@ public class LeaveServiceImpl implements LeaveService {
|
|||||||
this.templateMessageService = templateMessageService;
|
this.templateMessageService = templateMessageService;
|
||||||
this.icalEventRepo = icalEventRepo;
|
this.icalEventRepo = icalEventRepo;
|
||||||
this.icalendarService = icalendarService;
|
this.icalendarService = icalendarService;
|
||||||
|
this.companyRepo = companyRepo;
|
||||||
|
this.employeeRepo = employeeRepo;
|
||||||
|
this.dailyReportRepo = dailyReportRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -913,4 +932,170 @@ public class LeaveServiceImpl implements LeaveService {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
|
public void saveCR(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 dateDebut = jsonObject.getString("de");
|
||||||
|
String dateFin = jsonObject.getString("a");
|
||||||
|
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 Dates
|
||||||
|
LocalDate debutDate;
|
||||||
|
try {
|
||||||
|
debutDate = LocalDate.parse(dateDebut);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
System.out.println("Error parsing dateDebut: " + dateDebut);
|
||||||
|
debutDate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDate finDate;
|
||||||
|
try {
|
||||||
|
finDate = LocalDate.parse(dateFin);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
System.out.println("Error parsing dateFin: " + dateFin);
|
||||||
|
finDate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDateTime debutDateTime = debutDate.atStartOfDay();
|
||||||
|
LocalDateTime finDateTime = finDate.atStartOfDay();
|
||||||
|
|
||||||
|
LeaveRequest leaveRequest = leaveRequestRepo
|
||||||
|
.all()
|
||||||
|
.filter("self.ticketId = :ticketId")
|
||||||
|
.bind("ticketId", idInt)
|
||||||
|
.fetchOne();
|
||||||
|
|
||||||
|
if (leaveRequest != null) {
|
||||||
|
// Authorization exists, compare previous and new status
|
||||||
|
int previousStatus = leaveRequest.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
|
||||||
|
leaveRequest.setValidatedByEmployee(validatedByEmployee);
|
||||||
|
leaveRequest.setValidationDate(validationDate);
|
||||||
|
leaveRequest.setStatusSelect(newStatus);
|
||||||
|
// Save the updated Authorization
|
||||||
|
leaveRequestRepo.save(leaveRequest);
|
||||||
|
// Get Daily report
|
||||||
|
List<DailyReport> dailyReports = dailyReportRepo
|
||||||
|
.all()
|
||||||
|
.filter("self.employee = :employee and self.reportDate >= :debutDate and self.reportDate <= :finDate")
|
||||||
|
.bind("employee", employee)
|
||||||
|
.bind("debutDate", debutDate)
|
||||||
|
.bind("finDate", finDate)
|
||||||
|
.fetch();
|
||||||
|
|
||||||
|
if (dailyReports != null) {
|
||||||
|
for (DailyReport dailyReport : dailyReports) {
|
||||||
|
dailyReport.setIsAuthorizedAbsence(true);
|
||||||
|
dailyReportRepo.save(dailyReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (previousStatus == 2 && newStatus == 4) {
|
||||||
|
System.out.println("Tickets :" + idInt + " Status changed from " + previousStatus + " to " + newStatus);
|
||||||
|
leaveRequest.setRefusedByEmployee(validatedByEmployee);
|
||||||
|
leaveRequest.setRefusalDate(validationDate);
|
||||||
|
leaveRequest.setStatusSelect(newStatus);
|
||||||
|
// Save the updated Authorization
|
||||||
|
leaveRequestRepo.save(leaveRequest);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create an instance of ExtraHours
|
||||||
|
leaveRequest = new LeaveRequest();
|
||||||
|
leaveRequest.setEmployee(employee);
|
||||||
|
leaveRequest.setTicketId(idInt);
|
||||||
|
leaveRequest.setTicket(ticketLink);
|
||||||
|
leaveRequest.setFromDateT(debutDateTime);
|
||||||
|
leaveRequest.setToDateT(finDateTime);
|
||||||
|
leaveRequest.setDescription(commentaire);
|
||||||
|
leaveRequest.setStatusSelect(validation_status);
|
||||||
|
leaveRequest.setCompany(company);
|
||||||
|
|
||||||
|
if (validation_status == 3) {
|
||||||
|
leaveRequest.setValidatedByEmployee(validatedByEmployee);
|
||||||
|
leaveRequest.setValidationDate(validationDate);
|
||||||
|
} else if (validation_status == 4) {
|
||||||
|
leaveRequest.setRefusedByEmployee(validatedByEmployee);
|
||||||
|
leaveRequest.setRefusalDate(validationDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the ExtraHours entity
|
||||||
|
leaveRequestRepo.save(leaveRequest);
|
||||||
|
|
||||||
|
// Get Daily report
|
||||||
|
List<DailyReport> dailyReports = dailyReportRepo
|
||||||
|
.all()
|
||||||
|
.filter("self.employee = :employee and self.reportDate >= :debutDate and self.reportDate <= :finDate")
|
||||||
|
.bind("employee", employee)
|
||||||
|
.bind("debutDate", debutDate)
|
||||||
|
.bind("finDate", finDate)
|
||||||
|
.fetch();
|
||||||
|
|
||||||
|
if (dailyReports != null) {
|
||||||
|
for (DailyReport dailyReport : dailyReports) {
|
||||||
|
dailyReport.setLeaveRequest(leaveRequest); // Set the recup leave for each report
|
||||||
|
if(validation_status == 3)
|
||||||
|
dailyReport.setIsAuthorizedAbsence(true);
|
||||||
|
dailyReportRepo.save(dailyReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
System.err.println("Failed to parse JSON: " + jsonObject.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package com.axelor.apps.hr.web;
|
||||||
|
|
||||||
|
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.repo.AbsenceRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
|
import com.axelor.apps.hr.service.AbsenceServiceImpl;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
import com.axelor.rpc.ActionRequest;
|
||||||
|
import com.axelor.rpc.ActionResponse;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.DayOfWeek;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
List<DailyReport> dailyreports =
|
||||||
|
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 (dailyreports.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Beans.get(AbsenceServiceImpl.class).attachTheAbsenceWithDailyReport(absence, dailyreports);
|
||||||
|
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
|
||||||
|
String selectedType = (String) 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);
|
||||||
|
} 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,286 @@
|
|||||||
|
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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package com.axelor.apps.hr.web;
|
||||||
|
|
||||||
|
import com.axelor.apps.hr.db.Shift;
|
||||||
|
import com.axelor.apps.hr.db.DailyReport;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.ShiftRepository;
|
||||||
|
import com.axelor.apps.hr.service.DailyReportServiceImpl;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
import com.axelor.rpc.ActionRequest;
|
||||||
|
import com.axelor.rpc.ActionResponse;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.util.List;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.hr.web;
|
package com.axelor.apps.hr.web;
|
||||||
|
|
||||||
|
import com.axelor.apps.hr.db.Granding;
|
||||||
|
import com.axelor.apps.hr.db.repo.GrandingRepository;
|
||||||
import com.axelor.apps.ReportFactory;
|
import com.axelor.apps.ReportFactory;
|
||||||
import com.axelor.apps.base.db.Partner;
|
import com.axelor.apps.base.db.Partner;
|
||||||
import com.axelor.apps.hr.db.DPAE;
|
import com.axelor.apps.hr.db.DPAE;
|
||||||
@@ -42,6 +44,9 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import wslite.json.JSONException;
|
import wslite.json.JSONException;
|
||||||
import wslite.json.JSONObject;
|
import wslite.json.JSONObject;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class EmployeeController {
|
public class EmployeeController {
|
||||||
@@ -141,4 +146,81 @@ public class EmployeeController {
|
|||||||
|
|
||||||
response.setReload(true);
|
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();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
String[] args = {
|
||||||
|
"python",
|
||||||
|
"C:\\Users\\administrator\\Desktop\\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).");
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package com.axelor.apps.hr.web;
|
||||||
|
|
||||||
|
|
||||||
|
import com.axelor.apps.hr.db.Granding;
|
||||||
|
import com.axelor.apps.hr.db.repo.GrandingRepository;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
import com.axelor.rpc.ActionRequest;
|
||||||
|
import com.axelor.rpc.ActionResponse;
|
||||||
|
import java.time.temporal.TemporalAdjusters;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import com.axelor.exception.service.TraceBackService;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
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,223 @@
|
|||||||
|
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.Employee;
|
||||||
|
import com.axelor.apps.hr.db.DailyReport;
|
||||||
|
import com.axelor.apps.hr.db.MonthlyReport;
|
||||||
|
import com.axelor.apps.hr.db.repo.AbsenceRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.EmployeeRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.MonthlyReportRepository;
|
||||||
|
import com.axelor.apps.hr.db.repo.DailyReportRepository;
|
||||||
|
import com.axelor.apps.hr.service.MonthlyReportServiceImpl;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
import com.axelor.rpc.ActionRequest;
|
||||||
|
import com.axelor.rpc.ActionResponse;
|
||||||
|
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 java.util.List;
|
||||||
|
|
||||||
|
public class MonthlyReportController {
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
System.out.println("Employee: "+ employee.getRegistrationNumber());
|
||||||
|
|
||||||
|
if (!employeeDailyReports.isEmpty() || !employeeAbsences.isEmpty()) {
|
||||||
|
System.out.println("Calculé pour: "+ employee.getRegistrationNumber());
|
||||||
|
// Process the employee's monthly report using filtered rapport and absences
|
||||||
|
Beans.get(MonthlyReportServiceImpl.class)
|
||||||
|
.createMensuelReport(
|
||||||
|
employee,
|
||||||
|
period,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
employeeDailyReports,
|
||||||
|
employeeAbsences);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,13 +17,18 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.hr.web.extra.hours;
|
package com.axelor.apps.hr.web.extra.hours;
|
||||||
|
|
||||||
|
import com.axelor.app.AppSettings;
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.base.db.ImportConfiguration;
|
||||||
import com.axelor.apps.base.db.Wizard;
|
import com.axelor.apps.base.db.Wizard;
|
||||||
|
import com.axelor.apps.base.db.repo.ImportConfigurationRepository;
|
||||||
import com.axelor.apps.base.service.PeriodService;
|
import com.axelor.apps.base.service.PeriodService;
|
||||||
import com.axelor.apps.base.service.message.MessageServiceBaseImpl;
|
import com.axelor.apps.base.service.message.MessageServiceBaseImpl;
|
||||||
|
import com.axelor.apps.base.web.AppBaseController;
|
||||||
import com.axelor.apps.hr.db.Employee;
|
import com.axelor.apps.hr.db.Employee;
|
||||||
import com.axelor.apps.hr.db.ExtraHours;
|
import com.axelor.apps.hr.db.ExtraHours;
|
||||||
import com.axelor.apps.hr.db.repo.ExtraHoursRepository;
|
import com.axelor.apps.hr.db.repo.ExtraHoursRepository;
|
||||||
|
import com.axelor.apps.hr.exception.IExceptionMessage;
|
||||||
import com.axelor.apps.hr.service.HRMenuTagService;
|
import com.axelor.apps.hr.service.HRMenuTagService;
|
||||||
import com.axelor.apps.hr.service.HRMenuValidateService;
|
import com.axelor.apps.hr.service.HRMenuValidateService;
|
||||||
import com.axelor.apps.hr.service.extra.hours.ExtraHoursService;
|
import com.axelor.apps.hr.service.extra.hours.ExtraHoursService;
|
||||||
@@ -31,6 +36,7 @@ import com.axelor.apps.message.db.Message;
|
|||||||
import com.axelor.apps.message.db.repo.MessageRepository;
|
import com.axelor.apps.message.db.repo.MessageRepository;
|
||||||
import com.axelor.auth.AuthUtils;
|
import com.axelor.auth.AuthUtils;
|
||||||
import com.axelor.auth.db.User;
|
import com.axelor.auth.db.User;
|
||||||
|
import com.axelor.csv.script.ImportExtraHoursConfiguration;
|
||||||
import com.axelor.db.Query;
|
import com.axelor.db.Query;
|
||||||
import com.axelor.exception.AxelorException;
|
import com.axelor.exception.AxelorException;
|
||||||
import com.axelor.exception.service.TraceBackService;
|
import com.axelor.exception.service.TraceBackService;
|
||||||
@@ -41,12 +47,27 @@ import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
|
|||||||
import com.axelor.rpc.ActionRequest;
|
import com.axelor.rpc.ActionRequest;
|
||||||
import com.axelor.rpc.ActionResponse;
|
import com.axelor.rpc.ActionResponse;
|
||||||
import com.google.inject.Singleton;
|
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 java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import wslite.json.JSONArray;
|
||||||
|
import wslite.json.JSONException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class ExtraHoursController {
|
public class ExtraHoursController {
|
||||||
|
|
||||||
|
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 editExtraHours(ActionRequest request, ActionResponse response) {
|
public void editExtraHours(ActionRequest request, ActionResponse response) {
|
||||||
List<ExtraHours> extraHoursList =
|
List<ExtraHours> extraHoursList =
|
||||||
Beans.get(ExtraHoursRepository.class)
|
Beans.get(ExtraHoursRepository.class)
|
||||||
@@ -284,10 +305,124 @@ public class ExtraHoursController {
|
|||||||
public void compute(ActionRequest request, ActionResponse response) {
|
public void compute(ActionRequest request, ActionResponse response) {
|
||||||
try {
|
try {
|
||||||
ExtraHours extraHours = request.getContext().asType(ExtraHours.class);
|
ExtraHours extraHours = request.getContext().asType(ExtraHours.class);
|
||||||
Beans.get(ExtraHoursService.class).compute(extraHours);
|
// Beans.get(ExtraHoursService.class).compute(extraHours);
|
||||||
response.setValue("totalQty", extraHours.getTotalQty());
|
response.setValue("totalQty", extraHours.getTotalQty());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TraceBackService.trace(response, e);
|
TraceBackService.trace(response, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void getExtraHoursImportConfig(ActionRequest request, ActionResponse response) {
|
||||||
|
|
||||||
|
ImportConfiguration extraHoursImportConfig =
|
||||||
|
Beans.get(ImportConfigurationRepository.class)
|
||||||
|
.all()
|
||||||
|
.filter(
|
||||||
|
"self.bindMetaFile.fileName = ?1",
|
||||||
|
ImportExtraHoursConfiguration.IMPORT_EXTRA_HOURS_CONFIG)
|
||||||
|
.fetchOne();
|
||||||
|
|
||||||
|
logger.debug("ImportConfig for lead: {}", extraHoursImportConfig);
|
||||||
|
|
||||||
|
if (extraHoursImportConfig == null) {
|
||||||
|
response.setFlash(I18n.get(IExceptionMessage.EXTRA_HOURS_1));
|
||||||
|
} else {
|
||||||
|
response.setView(
|
||||||
|
ActionView.define(I18n.get(IExceptionMessage.EXTRA_HOURS_2))
|
||||||
|
.model("com.axelor.apps.base.db.ImportConfiguration")
|
||||||
|
.add("form", "import-configuration-form")
|
||||||
|
.param("popup", "reload")
|
||||||
|
.param("forceEdit", "true")
|
||||||
|
.param("popup-save", "false")
|
||||||
|
.param("show-toolbar", "false")
|
||||||
|
.context("_showRecord", extraHoursImportConfig.getId().toString())
|
||||||
|
.map());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fetchExtraHours(ActionRequest request, ActionResponse response) {
|
||||||
|
try {
|
||||||
|
String accessToken = AppBaseController.getAccessToken();
|
||||||
|
if (accessToken == null) {
|
||||||
|
logger.error("Access token is null, unable to proceed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String jsonResponse = fetchHS(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(ExtraHoursService.class).saveExtraHours(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 fetchHS.");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// General catch for unexpected exceptions
|
||||||
|
System.err.println("An error occurred while fetching extra hours: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String fetchHS(String accessToken) {
|
||||||
|
String endpoint = BASE_URL + "tickets/hs/";
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.hr.web.leave;
|
package com.axelor.apps.hr.web.leave;
|
||||||
|
|
||||||
|
import com.axelor.app.AppSettings;
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
import com.axelor.apps.base.db.Wizard;
|
import com.axelor.apps.base.db.Wizard;
|
||||||
import com.axelor.apps.base.service.PeriodService;
|
import com.axelor.apps.base.service.PeriodService;
|
||||||
import com.axelor.apps.base.service.message.MessageServiceBaseImpl;
|
import com.axelor.apps.base.service.message.MessageServiceBaseImpl;
|
||||||
|
import com.axelor.apps.base.web.AppBaseController;
|
||||||
import com.axelor.apps.hr.db.Employee;
|
import com.axelor.apps.hr.db.Employee;
|
||||||
import com.axelor.apps.hr.db.ExtraHours;
|
import com.axelor.apps.hr.db.ExtraHours;
|
||||||
import com.axelor.apps.hr.db.LeaveLine;
|
import com.axelor.apps.hr.db.LeaveLine;
|
||||||
@@ -51,10 +53,26 @@ import com.google.inject.Singleton;
|
|||||||
import com.google.inject.persist.Transactional;
|
import com.google.inject.persist.Transactional;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import wslite.json.JSONArray;
|
||||||
|
import wslite.json.JSONException;
|
||||||
|
import wslite.json.JSONObject;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class LeaveController {
|
public class LeaveController {
|
||||||
|
|
||||||
|
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 editLeave(ActionRequest request, ActionResponse response) {
|
public void editLeave(ActionRequest request, ActionResponse response) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -398,4 +416,91 @@ public class LeaveController {
|
|||||||
return Beans.get(HRMenuTagService.class)
|
return Beans.get(HRMenuTagService.class)
|
||||||
.countRecordsTag(LeaveRequest.class, LeaveRequestRepository.STATUS_AWAITING_VALIDATION);
|
.countRecordsTag(LeaveRequest.class, LeaveRequestRepository.STATUS_AWAITING_VALIDATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fetchRecupLeave(ActionRequest request, ActionResponse response) {
|
||||||
|
try {
|
||||||
|
String accessToken = AppBaseController.getAccessToken();
|
||||||
|
if (accessToken == null) {
|
||||||
|
logger.error("Access token is null, unable to proceed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String jsonResponse = fetchCR(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(LeaveService.class).saveCR(jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload the response after successfully saving extra hours
|
||||||
|
response.setReload(true);
|
||||||
|
|
||||||
|
} catch (JSONException e) {
|
||||||
|
// Log the specific JSON parsing error
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("No response received from fetchCR.");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// General catch for unexpected exceptions
|
||||||
|
System.err.println("An error occurred while fetching congé recup: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String fetchCR(String accessToken) {
|
||||||
|
String endpoint = BASE_URL + "tickets/cr/";
|
||||||
|
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
|
||||||
|
System.out.println("HR CR Tickets Response: " + response.toString());
|
||||||
|
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,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models
|
||||||
|
https://axelor.com/xml/ns/domain-models/domain-models_6.0.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db" />
|
||||||
|
|
||||||
|
<entity name="Absence">
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee"/>
|
||||||
|
<string name="absenceType" title="Type Absence" selection="hr.type.absence.selection"/>
|
||||||
|
|
||||||
|
<datetime name="startDate" title="Date Début"/>
|
||||||
|
<datetime name="endDate" title="Date Fin"/>
|
||||||
|
<decimal name="totalAbsenceHours" precision="20" scale="2"/>
|
||||||
|
<one-to-many name="dailyReport" ref="com.axelor.apps.hr.db.DailyReport"/>
|
||||||
|
|
||||||
|
<string name="fullName" namecolumn="true">
|
||||||
|
<![CDATA[
|
||||||
|
String fullName = "";
|
||||||
|
if (employee != null && employee.getContactPartner() != null && employee.getContactPartner().getFullName() != null) {
|
||||||
|
fullName += employee.getContactPartner().getFullName();
|
||||||
|
}
|
||||||
|
if (absenceType != null) {
|
||||||
|
fullName += " - " + absenceType;
|
||||||
|
}
|
||||||
|
if (startDate != null && endDate != null) {
|
||||||
|
java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
|
||||||
|
fullName += " (from " + startDate.format(formatter) + " to " + endDate.format(formatter) + ")";
|
||||||
|
}
|
||||||
|
return fullName;
|
||||||
|
]]>
|
||||||
|
</string>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
<track>
|
||||||
|
<field name="employee"/>
|
||||||
|
<field name="absenceType"/>
|
||||||
|
<field name="startDate"/>
|
||||||
|
<field name="endDate"/>
|
||||||
|
</track>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models
|
||||||
|
https://axelor.com/xml/ns/domain-models/domain-models_6.0.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db" />
|
||||||
|
|
||||||
|
<entity name="Authorization">
|
||||||
|
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee"/>
|
||||||
|
<date name="requisitionDate" title="Requisition Date" required="true"/>
|
||||||
|
<string name="description" title="Description" large="true"/>
|
||||||
|
<integer name="authorizationType" title="Authorization Type" selection="hr.type.absence.authorization.selection"/>
|
||||||
|
<integer name="statusSelect" title="Status" selection="hrs.leave.request.status.select" default="1" readonly="true"/>
|
||||||
|
|
||||||
|
|
||||||
|
<many-to-one name="validatedByEmployee" ref="com.axelor.apps.hr.db.Employee" title="Validated by" readonly="true"/>
|
||||||
|
<many-to-one name="refusedByEmployee" ref="com.axelor.apps.hr.db.Employee" title="Refused By" readonly="true"/>
|
||||||
|
|
||||||
|
<date name="validationDate" title="Validation Date" readonly="true"/>
|
||||||
|
<date name="refusalDate" title="Refusal Date" readonly="true"/>
|
||||||
|
<integer name="ticketId" readonly="true" required="true"/>
|
||||||
|
<string name="ticket" title="My Sophal Ticket" readonly="true" required="true"/>
|
||||||
|
|
||||||
|
<time name="heureAuthorization" title="Authorized Absence Hours"/>
|
||||||
|
|
||||||
|
<many-to-one name="dailyReport" ref="com.axelor.apps.hr.db.DailyReport" mappedBy="dailyReportList"/>
|
||||||
|
<unique-constraint columns="ticketId"/>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models
|
||||||
|
https://axelor.com/xml/ns/domain-models/domain-models_6.0.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db"/>
|
||||||
|
|
||||||
|
<entity name="CheckInOut">
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee"/>
|
||||||
|
<date name="date_attendance"/>
|
||||||
|
<time name="time_attendance"/>
|
||||||
|
<many-to-one name="granding" ref="com.axelor.apps.hr.db.Granding"/>
|
||||||
|
|
||||||
|
<unique-constraint columns="employee,date_attendance,time_attendance"/>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models
|
||||||
|
https://axelor.com/xml/ns/domain-models/domain-models_6.0.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db"/>
|
||||||
|
<entity name="DailyReport">
|
||||||
|
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee"/>
|
||||||
|
|
||||||
|
<date name="reportDate"/>
|
||||||
|
|
||||||
|
<!-- Pointage -->
|
||||||
|
<datetime name="enter1" required="false"/>
|
||||||
|
<datetime name="quit1" required="false"/>
|
||||||
|
<datetime name="enter2" required="false"/>
|
||||||
|
<datetime name="quit2" required="false"/>
|
||||||
|
<datetime name="enter3" required="false"/>
|
||||||
|
<datetime name="quit3" required="false"/>
|
||||||
|
<datetime name="enter4" required="false"/>
|
||||||
|
<datetime name="quit4" required="false"/>
|
||||||
|
<datetime name="enter5" required="false"/>
|
||||||
|
<datetime name="quit5" required="false"/>
|
||||||
|
<datetime name="enter6" required="false"/>
|
||||||
|
<datetime name="quit6" required="false"/>
|
||||||
|
<datetime name="lastQuit" required="false"/>
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
<decimal name="workHours" precision="20" scale="2" /> <!-- Heures de travail -->
|
||||||
|
<decimal name="nightHours" precision="20" scale="2" /> <!-- Heures de nuit -->
|
||||||
|
<decimal name="breakHours" precision="20" scale="2" /> <!-- Heures de pause -->
|
||||||
|
<decimal name="extraHours50" precision="20" scale="2" /> <!-- Heures supplémentaires à 50% -->
|
||||||
|
<decimal name="extraHours100" precision="20" scale="2" /> <!-- Heures supplémentaires à 100% -->
|
||||||
|
<decimal name="absenceHours" precision="20" scale="2" /> <!-- Heures d'absence -->
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
<decimal name="lateArrival" title ="Late arrival" precision="20" scale="2" />
|
||||||
|
<decimal name="earlyDeparture" title ="Early departure" precision="20" scale="2" />
|
||||||
|
|
||||||
|
<decimal name="itp" precision="20" scale="2" />
|
||||||
|
<decimal name="nuissance" precision="20" scale="2" />
|
||||||
|
<integer name="allowance" precision="20" scale="2" /> <!-- Panier -->
|
||||||
|
<integer name="allowanceRecall" precision="20" scale="2"/> <!-- Rappel de panier -->
|
||||||
|
|
||||||
|
<boolean name="isFerieDay" default="False"/>
|
||||||
|
<boolean name="isValidSupHours" default="False"/>
|
||||||
|
<boolean name="isAuthorizedAbsence" default="False"/>
|
||||||
|
<boolean name="isCalculated" default="False"/>
|
||||||
|
<boolean name="isTransfaire" title="Transfaire"/>
|
||||||
|
<boolean name="hasItp" title="Transfaire"/>
|
||||||
|
<boolean name="hasNuissance" title="Transfaire"/>
|
||||||
|
<boolean name="isChangeTheShift" default="False"/>
|
||||||
|
<boolean name="isWeekend" default="False"/>
|
||||||
|
<boolean name="isChanged" default="False"/>
|
||||||
|
<boolean name="isClosed" default="False"/>
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
<boolean name="deduceSupHours50" default="False"/>
|
||||||
|
<boolean name="deduceSupHours100" default="False"/>
|
||||||
|
<boolean name="deduceItp" default="False"/>
|
||||||
|
<boolean name="deduceNuissance" default="False"/>
|
||||||
|
|
||||||
|
<decimal name="supHours50ToDeduce" precision="20" scale="2"/>
|
||||||
|
<decimal name="supHours100ToDeduce" precision="20" scale="2"/>
|
||||||
|
<decimal name="itpToDeduce" precision="20" scale="2"/>
|
||||||
|
<decimal name="nuissanceToDeduce" precision="20" scale="2"/>
|
||||||
|
|
||||||
|
|
||||||
|
<many-to-one name="shift" title="Shift" ref="com.axelor.apps.hr.db.Shift" mappedBy="dailyReportList"/>
|
||||||
|
<one-to-many name="supHoursList" title="Sup Hours" ref="com.axelor.apps.hr.db.ExtraHours" />
|
||||||
|
<one-to-many name="authorizationList" title="Autorization" ref="com.axelor.apps.hr.db.Authorization" mappedBy="dailyReport"/>
|
||||||
|
<many-to-one name="leaveRequest" title="Leave" ref="com.axelor.apps.hr.db.LeaveRequest" mappedBy="dailyReport"/>
|
||||||
|
<many-to-one name="absence" title="Absence" ref="com.axelor.apps.hr.db.Absence" mappedBy="dailyReport"/>
|
||||||
|
<many-to-one name="monthlyReport" title="Monthly Report" ref="com.axelor.apps.hr.db.MonthlyReport" mappedBy="dailyReports"/>
|
||||||
|
|
||||||
|
<unique-constraint columns="employee,reportDate"/>
|
||||||
|
<track>
|
||||||
|
<field name="enter1"/>
|
||||||
|
<field name="enter2"/>
|
||||||
|
<field name="enter3"/>
|
||||||
|
<field name="enter4"/>
|
||||||
|
<field name="enter5"/>
|
||||||
|
<field name="enter6"/>
|
||||||
|
<field name="quit1"/>
|
||||||
|
<field name="quit2"/>
|
||||||
|
<field name="quit3"/>
|
||||||
|
<field name="quit4"/>
|
||||||
|
<field name="quit5"/>
|
||||||
|
<field name="quit6"/>
|
||||||
|
<field name="isValidSupHours"/>
|
||||||
|
<field name="isAuthorizedAbsence"/>
|
||||||
|
<field name="deduceSupHours50"/>
|
||||||
|
<field name="deduceSupHours100"/>
|
||||||
|
<field name="deduceItp"/>
|
||||||
|
<field name="deduceNuissance"/>
|
||||||
|
<field name="supHours50ToDeduce"/>
|
||||||
|
<field name="supHours100ToDeduce"/>
|
||||||
|
<field name="itpToDeduce"/>
|
||||||
|
<field name="nuissanceToDeduce"/>
|
||||||
|
</track>
|
||||||
|
</entity>
|
||||||
|
</domain-models>
|
||||||
@@ -82,6 +82,18 @@
|
|||||||
]]>
|
]]>
|
||||||
</extra-code>
|
</extra-code>
|
||||||
|
|
||||||
|
<!-- SOPHAL -->
|
||||||
|
<boolean name="isTransfaire" title="Transfaire"/>
|
||||||
|
<boolean name="hasNuissance" title="Nuissance" massUpdate="true"/>
|
||||||
|
<boolean name="hasItp" title="Itp" default="false" massUpdate="true"/>
|
||||||
|
<boolean name="isEnrolled" title="Enrolled" readonly="true"/>
|
||||||
|
<date name="quitDate" title="Quit date"/>
|
||||||
|
<string name="registrationNumber" title="Registration Number"/>
|
||||||
|
<many-to-one name="managerEmployee" ref="com.axelor.apps.hr.db.Employee" title="Manager" massUpdate="true"/>
|
||||||
|
<many-to-one name="initialShift" ref="com.axelor.apps.hr.db.Shift" title="Shift Initial" mappedBy="employee"/>
|
||||||
|
<one-to-many name="dailyReport" title="Daily Report" ref="com.axelor.apps.hr.db.DailyReport" mappedBy="employee"/>
|
||||||
|
<one-to-many name="offDaysWork" ref="com.axelor.apps.hr.db.OffDayWork" mappedBy="employee"/>
|
||||||
|
|
||||||
</entity>
|
</entity>
|
||||||
|
|
||||||
</domain-models>
|
</domain-models>
|
||||||
|
|||||||
@@ -14,11 +14,22 @@
|
|||||||
|
|
||||||
<many-to-one name="validatedBy" ref="com.axelor.auth.db.User" title="Validated by" readonly="true"/>
|
<many-to-one name="validatedBy" ref="com.axelor.auth.db.User" title="Validated by" readonly="true"/>
|
||||||
<many-to-one name="refusedBy" ref="com.axelor.auth.db.User" title="Refused By" readonly="true"/>
|
<many-to-one name="refusedBy" ref="com.axelor.auth.db.User" title="Refused By" readonly="true"/>
|
||||||
<date name="validationDate" title="Validation Date" readonly="true"/>
|
|
||||||
<date name="refusalDate" title="Refusal Date" readonly="true" />
|
|
||||||
<string name="groundForRefusal" title="Ground For Refusal" large="true"/>
|
<string name="groundForRefusal" title="Ground For Refusal" large="true"/>
|
||||||
|
|
||||||
|
<date name="requisitionDate" title="Requisition Date" required="true"/>
|
||||||
|
<string name="description" title="Description" large="true"/>
|
||||||
|
<time name="startHour" title="Start Hour" required="true"/>
|
||||||
|
<time name="endHour" title="End Hour" required="true"/>
|
||||||
|
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee"/>
|
||||||
|
<many-to-one name="validatedByEmployee" ref="com.axelor.apps.hr.db.Employee" title="Validated by" readonly="true"/>
|
||||||
|
<many-to-one name="refusedByEmployee" ref="com.axelor.apps.hr.db.Employee" title="Refused By" readonly="true"/>
|
||||||
|
<date name="validationDate" title="Validation Date" readonly="true"/>
|
||||||
|
<date name="refusalDate" title="Refusal Date" readonly="true"/>
|
||||||
<decimal name="totalQty" title="Total (h)" readonly="true"/>
|
<decimal name="totalQty" title="Total (h)" readonly="true"/>
|
||||||
|
<integer name="ticketId" readonly="true" required="true"/>
|
||||||
|
<string name="ticket" title="My Sophal Ticket" readonly="true"/>
|
||||||
|
<many-to-one name="dailyReport" ref="com.axelor.apps.hr.db.DailyReport"/>
|
||||||
|
|
||||||
<one-to-many name="extraHoursLineList" ref="com.axelor.apps.hr.db.ExtraHoursLine" title="Extra Hours" mappedBy="extraHours"/>
|
<one-to-many name="extraHoursLineList" ref="com.axelor.apps.hr.db.ExtraHoursLine" title="Extra Hours" mappedBy="extraHours"/>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models
|
||||||
|
https://axelor.com/xml/ns/domain-models/domain-models_6.0.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db"/>
|
||||||
|
|
||||||
|
<entity name="Granding">
|
||||||
|
<string name="name" title="Granding name"/>
|
||||||
|
<string name="ipAdress" title="ip Adress"/>
|
||||||
|
<integer name="port" title="Port"/>
|
||||||
|
<integer name="code" title="Code"/>
|
||||||
|
|
||||||
|
</entity>
|
||||||
|
</domain-models>
|
||||||
@@ -28,6 +28,15 @@
|
|||||||
<decimal name="quantityBeforeValidation" title="Available quantity (before validation)" scale="4" precision="8" />
|
<decimal name="quantityBeforeValidation" title="Available quantity (before validation)" scale="4" precision="8" />
|
||||||
<boolean name="toJustifyLeaveReason" title="Leave to justify"/>
|
<boolean name="toJustifyLeaveReason" title="Leave to justify"/>
|
||||||
|
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee"/>
|
||||||
|
<one-to-many name="dailyReport" ref="com.axelor.apps.hr.db.DailyReport"/>
|
||||||
|
<string name="description" title="Description" large="true"/>
|
||||||
|
<integer name="ticketId" readonly="true" required="true"/>
|
||||||
|
<string name="ticket" title="My Sophal Ticket" readonly="true" required="true"/>
|
||||||
|
<many-to-one name="validatedByEmployee" ref="com.axelor.apps.hr.db.Employee" title="Validated by" readonly="true"/>
|
||||||
|
<many-to-one name="refusedByEmployee" ref="com.axelor.apps.hr.db.Employee" title="Refused By" readonly="true"/>
|
||||||
|
|
||||||
|
|
||||||
<string name="fullName" namecolumn="true" readonly="true">
|
<string name="fullName" namecolumn="true" readonly="true">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
if(this.getUser() != null && this.getCreatedOn() != null)
|
if(this.getUser() != null && this.getCreatedOn() != null)
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models
|
||||||
|
https://axelor.com/xml/ns/domain-models/domain-models_6.0.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db"/>
|
||||||
|
<entity name="MonthlyReport">
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee"/>
|
||||||
|
|
||||||
|
<integer name="monthlyAllowance" precision="20" scale="2" /> <!-- Allocation mensuelle -->
|
||||||
|
<integer name="monthlyAllowanceRecall" precision="20" scale="2" /> <!-- Rappel de l'allocation mensuelle -->
|
||||||
|
<decimal name="monthlyNuisanceValue" precision="20" scale="2" /> <!-- Valeur des nuisances mensuelles -->
|
||||||
|
<decimal name="totalNuissance" precision="20" scale="2" /> <!-- Total des nuisances -->
|
||||||
|
<decimal name="monthlyNightHours" precision="20" scale="2" /> <!-- Heures de nuit mensuelles -->
|
||||||
|
<decimal name="monthlyITP" precision="20" scale="2" /> <!-- ITP mensuel (Indemnité de Transport et Prime) -->
|
||||||
|
<decimal name="monthlyExtraHours50" precision="20" scale="2" /> <!-- Heures supplémentaires mensuelles à 50% -->
|
||||||
|
<decimal name="monthlyExtraHours100" precision="20" scale="2" /> <!-- Heures supplémentaires mensuelles à 100% -->
|
||||||
|
<decimal name="excessHours50" precision="20" scale="2" /> <!-- Heures supplémentaires excédentaires à 50% -->
|
||||||
|
<decimal name="excessHours100" precision="20" scale="2" /> <!-- Heures supplémentaires excédentaires à 100% -->
|
||||||
|
|
||||||
|
|
||||||
|
<one-to-many name="dailyReports" ref="com.axelor.apps.hr.db.DailyReport" mappedBy="monthlyReport"/>
|
||||||
|
|
||||||
|
<decimal name="primeAssiduite" precision="20" scale="2" /> <!-- Prime d'assiduité -->
|
||||||
|
|
||||||
|
|
||||||
|
<decimal name="totalWorkHours" precision="20" scale="2" /> <!-- Total des heures de travail -->
|
||||||
|
<decimal name="authorizedPaidAbsenceMonth" precision="20" scale="2" /> <!-- Absence autorisée payée du mois -->
|
||||||
|
<decimal name="recuperationLeaveAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour congé de récupération du mois -->
|
||||||
|
<decimal name="breastfeedingAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour allaitement du mois -->
|
||||||
|
<decimal name="trainingAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour formation du mois -->
|
||||||
|
<decimal name="missionAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour mission du mois -->
|
||||||
|
<decimal name="hospitalizationAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour hospitalisation du mois -->
|
||||||
|
<decimal name="sicknessAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour maladie du mois -->
|
||||||
|
<decimal name="workAccidentMonth" precision="20" scale="2" /> <!-- Absence pour accident de travail du mois -->
|
||||||
|
<decimal name="maternityMonth" precision="20" scale="2" /> <!-- Absence pour maternité du mois -->
|
||||||
|
<decimal name="authorizedUnpaidAbsenceMonth" precision="20" scale="2" /> <!-- Absence autorisée non payée du mois -->
|
||||||
|
<decimal name="annualLeaveAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour congé annuel du mois -->
|
||||||
|
<decimal name="unpaidLeaveAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour congé sans solde du mois -->
|
||||||
|
<decimal name="statutoryLeaveAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour congé statutaire du mois -->
|
||||||
|
<decimal name="resignationAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour démission du mois -->
|
||||||
|
<decimal name="contractEndAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour fin de contrat du mois -->
|
||||||
|
<decimal name="justifiedAbsenceMonth" precision="20" scale="2" /> <!-- Absence justifiée du mois -->
|
||||||
|
<decimal name="recruitmentAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour recrutement du mois -->
|
||||||
|
<decimal name="suspensionAbsenceMonth" precision="20" scale="2" /> <!-- Absence pour suspension du mois -->
|
||||||
|
<decimal name="militaryServiceAbsence" precision="20" scale="2" /> <!-- Absence pour service militaire -->
|
||||||
|
<decimal name="irregularAbsenceMonth" precision="20" scale="2" /> <!-- Absence irrégulière du mois -->
|
||||||
|
|
||||||
|
|
||||||
|
<many-to-one name="period" ref="com.axelor.apps.base.db.Period" mappedBy="monthlyReport"/>
|
||||||
|
|
||||||
|
<unique-constraint columns="employee,period"/>
|
||||||
|
</entity>
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db"/>
|
||||||
|
|
||||||
|
<entity name="OffDayWork">
|
||||||
|
|
||||||
|
<many-to-one name="employee" ref="com.axelor.apps.hr.db.Employee" mappedBy="offDaysWork"/>
|
||||||
|
<date name="offDay" title="Off Day" required="true"/>
|
||||||
|
<boolean name="taken" title="Taken" default="false"/>
|
||||||
|
<many-to-one name="recuperationLeave" ref="com.axelor.apps.hr.db.RecuperationLeave" mappedBy="OffDayWorkLines"/>
|
||||||
|
|
||||||
|
<unique-constraint columns="employee,offDay"/>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db"/>
|
||||||
|
|
||||||
|
<entity name="RecuperationLeave">
|
||||||
|
|
||||||
|
<many-to-one name="employee" title="Employee" ref="com.axelor.apps.hr.db.Employee" mappedBy="offDaysWork"/>
|
||||||
|
<one-to-many name="offDayWorkLines" ref="com.axelor.apps.hr.db.OffDayWork" mappedBy="recuperationLeave"/>
|
||||||
|
<date name="startDate" title="Start Date" required="true"/>
|
||||||
|
<date name="endDate" title="End Date" required="true"/>
|
||||||
|
<string name="description" title="Description"/>
|
||||||
|
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models
|
||||||
|
https://axelor.com/xml/ns/domain-models/domain-models_6.0.xsd">
|
||||||
|
|
||||||
|
<module name="human-resource" package="com.axelor.apps.hr.db"/>
|
||||||
|
<entity name="Shift">
|
||||||
|
<integer name="shift" title="Shift" min="0" max="3"/>
|
||||||
|
<string name="shiftName" title="Shift name" namecolumn="true"/>
|
||||||
|
<time name="startHour" title="Start Hour"/>
|
||||||
|
<time name="endHour" title="End Hour"/>
|
||||||
|
<time name="enterMin" title="Minimum Entry Time"/>
|
||||||
|
<time name="enterMax" title="Maximum Entry Time"/>
|
||||||
|
|
||||||
|
<one-to-many name="rapportJournalierList" ref="com.axelor.apps.hr.db.DailyReport " title="Rapports Journalier" mappedBy="shift"/>
|
||||||
|
<one-to-many name="employee" ref="com.axelor.apps.hr.db.Employee" title="Employees" mappedBy="initialShift"/>
|
||||||
|
<track>
|
||||||
|
<field name="startHour"/>
|
||||||
|
<field name="endHour"/>
|
||||||
|
<field name="enterMin"/>
|
||||||
|
<field name="enterMax"/>
|
||||||
|
</track>
|
||||||
|
</entity>
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views
|
||||||
|
https://axelor.com/xml/ns/object-views/object-views_6.0.xsd">
|
||||||
|
|
||||||
|
<grid name="absence-grid" title="Absence" model="com.axelor.apps.hr.db.Absence">
|
||||||
|
<toolbar>
|
||||||
|
<button name="chooseAbsenceType" title="Choisir Type d'absence" onClick="action-choose-absence-type-wizard" colSpan="12"/>
|
||||||
|
</toolbar>
|
||||||
|
<field name="employee" title="Employé"/>
|
||||||
|
<field name="typeAbsence" title="Type Absence"/>
|
||||||
|
<field name="absDate" readonly="true"/>
|
||||||
|
<field name="absDateFin"/>
|
||||||
|
<field name="heureAbsence" title="Heure Absence"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<form name="absence-form" title="Form" model="com.axelor.apps.hr.db.Absence" onSave="save,action-method-absence-save,save">
|
||||||
|
<panel name="absence" title="Absence Form">
|
||||||
|
<field name="employee" title="Employé"/>
|
||||||
|
<field name="typeAbsence" title="Type Absence"/>
|
||||||
|
<field name="absDate"/>
|
||||||
|
<field name="absDateFin"/>
|
||||||
|
<field name="heureAbsence" title="Heure Absence"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="commentaire" title="Commentaire">
|
||||||
|
<field name="commentaire" showTitle="false" colSpan="12" widget="HTML"/>
|
||||||
|
</panel>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<action-view name="action-absence" model="com.axelor.apps.hr.db.Absence" title="Absence">
|
||||||
|
<view name="absence-grid" type="grid"/>
|
||||||
|
<view name="absence-form" type="form"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-method name="action-method-absence-save">
|
||||||
|
<call class="com.axelor.apps.hr.web.AbsenceController" method="attachTheAbsenceWithDailyReport"/>
|
||||||
|
</action-method>
|
||||||
|
|
||||||
|
<form name="choose-absence-type-popup-form" title="Voir les absences" model="com.axelor.apps.base.db.Wizard">
|
||||||
|
<panel name="absence-all-day-popup" title="Les absences">
|
||||||
|
<field name="$chooseTypeAbsence" title="Type Absence" widget="SelectProgress" selection="hr.type.absence.selection"/>
|
||||||
|
<button name="chooseAbsenceTypeButton" title="Ajouter Type" onClick="save,action-method-hr-choose-absence-type,save,close" colSpan="12"/>
|
||||||
|
</panel>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<action-view name="action-choose-absence-type-wizard" model="com.axelor.apps.base.db.Wizard" title="Choisir Type d'absence">
|
||||||
|
<view name="choose-absence-type-popup-form" type="form"/>
|
||||||
|
<view-param name="popup" value="true"/>
|
||||||
|
<view-param name="show-toolbar" value="false"/>
|
||||||
|
<view-param name="show-confirm" value="false"/>
|
||||||
|
<view-param name="popup-save" value="false"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-method name="action-method-hr-choose-absence-type">
|
||||||
|
<call class="com.axelor.apps.hr.web.AbsenceController" method="chooseAbsenceType"/>
|
||||||
|
</action-method>
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views
|
||||||
|
https://axelor.com/xml/ns/object-views/object-views_6.0.xsd">
|
||||||
|
|
||||||
|
<grid name="absence-aut-grid" title="Absence" model="com.axelor.apps.hr.db.Authorization">
|
||||||
|
<field name="employee" title="Employee"/>
|
||||||
|
<field name="typeAbsenceAut" title="Authorization Type" showIf="typeSelect = 2"/>
|
||||||
|
<field name="absAutDate" readonly="true"/>
|
||||||
|
<field name="heureAutorisationAbsence" readonly="true"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<form name="absence-aut-form" title="Form" model="com.axelor.apps.hr.db.Autorisation" onSave="save,action-method-hr-autorisation,save">
|
||||||
|
<panel name="autorisation" showIf="self.typeSelect = 2" hideIf="self.typeSelect = 1" title="Authorization Form">
|
||||||
|
<field name="employee" title="Employee"/>
|
||||||
|
<field name="typeAbsenceAut" title="Authorization Type"/>
|
||||||
|
<field name="absAutDate" title="Date"/>
|
||||||
|
<field name="heureAutorisationAbsence" readonly="true"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="commentaire" title="Commentaire">
|
||||||
|
<field name="commentaire" showTitle="false" colSpan="12" widget="HTML"/>
|
||||||
|
</panel>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<action-view name="action-autorisation" model="com.axelor.apps.hr.db.Authorization" title="Authorization">
|
||||||
|
<view name="absence-aut-grid" type="grid"/>
|
||||||
|
<view name="absence-aut-form" type="form"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-method name="action-method-hr-autorisation">
|
||||||
|
<call class="com.axelor.apps.hr.controller.AutorisationController" method="autHours"/>
|
||||||
|
</action-method>
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views http://axelor.com/xml/ns/object-views/object-views_5.2.xsd">
|
||||||
|
|
||||||
|
<grid name="granding-grid" title="Grandings" model="com.axelor.apps.hr.db.Granding" edit-icon="true">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="ipAdress"/>
|
||||||
|
<field name="port"/>
|
||||||
|
<field name="code"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<form name="granding-form" title="Grinding" model="com.axelor.apps.hr.db.Granding">
|
||||||
|
<panel name="granding" title="Granding Form">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="ipAdress"/>
|
||||||
|
<field name="port"/>
|
||||||
|
<field name="code"/>
|
||||||
|
</panel>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views
|
||||||
|
https://axelor.com/xml/ns/object-views/object-views_6.0.xsd">
|
||||||
|
|
||||||
|
<grid name="off-day-work-grid" title="Off days" model="com.axelor.apps.hr.db.OffDayWork">
|
||||||
|
<field name="employee" title="Employé" />
|
||||||
|
<field name="offDay"/>
|
||||||
|
<field name="taken"/>
|
||||||
|
<field name="recuperationLeave"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<form name="off-day-work-form" title="Off days" model="com.axelor.apps.hr.db.OffDayWork">
|
||||||
|
<field name="employee" title="Employé"/>
|
||||||
|
<field name="offDay"/>
|
||||||
|
<field name="taken"/>
|
||||||
|
<field name="recuperationLeave"/>
|
||||||
|
<panel name="sidePanel" sidebar="true">
|
||||||
|
<field name="createdOn"/>
|
||||||
|
<field name="createdBy"/>
|
||||||
|
<field name="updatedOn"/>
|
||||||
|
<field name="updatedBy"/>
|
||||||
|
</panel>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views
|
||||||
|
https://axelor.com/xml/ns/object-views/object-views_6.0.xsd">
|
||||||
|
|
||||||
|
<grid name="shift-grid" title="Shift" model="com.axelor.apps.hr.db.Shift">
|
||||||
|
<field name="shift" />
|
||||||
|
<field name="shiftName" />
|
||||||
|
<field name="startHour"/>
|
||||||
|
<field name="endHour"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<form name="shift-form" title="Shift" model="com.axelor.apps.hr.db.Shift">
|
||||||
|
<panel name="shiftPanel" title="Shift">
|
||||||
|
<field name="shift" />
|
||||||
|
<field name="shiftName" />
|
||||||
|
<field name="startHour"/>
|
||||||
|
<field name="endHour"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="sidePanel" sidebar="true">
|
||||||
|
<field name="createdOn"/>
|
||||||
|
<field name="createdBy"/>
|
||||||
|
<field name="updatedOn"/>
|
||||||
|
<field name="updatedBy"/>
|
||||||
|
</panel>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<action-view name="action.shift.hr" model="com.axelor.apps.hr.db.Shift" title="Shift">
|
||||||
|
<view name="shift-grid" type="grid"/>
|
||||||
|
<view name="shift-form" type="form"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
</object-views>
|
||||||
19
modules/axelor-open-suite/axelor-qvm/build.gradle
Normal file
19
modules/axelor-open-suite/axelor-qvm/build.gradle
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apply plugin: "com.axelor.app-module"
|
||||||
|
|
||||||
|
apply from: "../version.gradle"
|
||||||
|
|
||||||
|
apply {
|
||||||
|
version = openSuiteVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
axelor {
|
||||||
|
title "Axelor QVM"
|
||||||
|
description "Axelor QVM"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(":modules:axelor-production")
|
||||||
|
compile project(":modules:axelor-base")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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.qvm.module;
|
||||||
|
|
||||||
|
import com.axelor.app.AxelorModule;
|
||||||
|
import com.axelor.apps.qvm.service.OperationService;
|
||||||
|
import com.axelor.apps.qvm.service.OperationServiceImpl;
|
||||||
|
|
||||||
|
public class QvmModule extends AxelorModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(OperationService.class).to(OperationServiceImpl.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.qvm.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.qvm.db.Operation;
|
||||||
|
import com.axelor.exception.AxelorException;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
|
|
||||||
|
public interface OperationService {
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Operation createCalibrationSeq(Company company) throws AxelorException;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Operation createQualificationSeq(Company company) throws AxelorException;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Operation createOperationSeq(Company company) throws AxelorException;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Operation setMachine(Operation operation) throws AxelorException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.qvm.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.base.db.repo.SequenceRepository;
|
||||||
|
import com.axelor.apps.base.service.administration.SequenceService;
|
||||||
|
import com.axelor.apps.qvm.db.Operation;
|
||||||
|
import com.axelor.exception.AxelorException;
|
||||||
|
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||||
|
import com.axelor.i18n.I18n;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
|
|
||||||
|
public class OperationServiceImpl implements OperationService {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected SequenceService sequenceService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Operation createCalibrationSeq(Company company) throws AxelorException {
|
||||||
|
|
||||||
|
Operation calibration = new Operation();
|
||||||
|
calibration.setSerialNumber(this.getCalibrationSequence(company));
|
||||||
|
|
||||||
|
return calibration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Operation createQualificationSeq(Company company) throws AxelorException {
|
||||||
|
|
||||||
|
Operation qualification = new Operation();
|
||||||
|
qualification.setSerialNumber(this.getQualificationSequence(company));
|
||||||
|
|
||||||
|
return qualification;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Operation createOperationSeq(Company company) throws AxelorException {
|
||||||
|
|
||||||
|
Operation operation = new Operation();
|
||||||
|
operation.setSerialNumber(this.getOperationSequence(company));
|
||||||
|
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCalibrationSequence(Company company) throws AxelorException {
|
||||||
|
String seq = sequenceService.getSequenceNumber(SequenceRepository.CALIB_SEQ, company);
|
||||||
|
if (seq == null) {
|
||||||
|
throw new AxelorException(
|
||||||
|
company,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
I18n.get("IExceptionMessage.PURCHASE_ORDER_1"),
|
||||||
|
company.getName());
|
||||||
|
}
|
||||||
|
System.out.println("seq before : " + seq);
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQualificationSequence(Company company) throws AxelorException {
|
||||||
|
String seq = sequenceService.getSequenceNumber(SequenceRepository.QUAL_SEQ, company);
|
||||||
|
if (seq == null) {
|
||||||
|
throw new AxelorException(
|
||||||
|
company,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
I18n.get("IExceptionMessage.PURCHASE_ORDER_1"),
|
||||||
|
company.getName());
|
||||||
|
}
|
||||||
|
System.out.println("seq before : " + seq);
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOperationSequence(Company company) throws AxelorException {
|
||||||
|
String seq = sequenceService.getSequenceNumber(SequenceRepository.OP_SEQ, company);
|
||||||
|
if (seq == null) {
|
||||||
|
throw new AxelorException(
|
||||||
|
company,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
I18n.get("IExceptionMessage.PURCHASE_ORDER_1"),
|
||||||
|
company.getName());
|
||||||
|
}
|
||||||
|
System.out.println("seq before : " + seq);
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Operation setMachine(Operation calibration) throws AxelorException {
|
||||||
|
if (calibration.getMachineName() != null) {
|
||||||
|
System.out.println("calibration.getMachineName : " + calibration.getMachineName());
|
||||||
|
}
|
||||||
|
return calibration;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.qvm.web;
|
||||||
|
|
||||||
|
import com.axelor.apps.qvm.db.Operation;
|
||||||
|
import com.axelor.apps.qvm.service.OperationService;
|
||||||
|
import com.axelor.apps.qvm.service.OperationServiceImpl;
|
||||||
|
import com.axelor.exception.AxelorException;
|
||||||
|
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.lang.invoke.MethodHandles;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class QvmOperationController {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||||
|
|
||||||
|
public void setSequenceOperation(ActionRequest request, ActionResponse response) {
|
||||||
|
try {
|
||||||
|
Operation calibration = request.getContext().asType(Operation.class);
|
||||||
|
|
||||||
|
if (calibration != null && calibration.getCompany() != null) {
|
||||||
|
response.setValue(
|
||||||
|
"serialNumber",
|
||||||
|
Beans.get(OperationService.class)
|
||||||
|
.createOperationSeq(calibration.getCompany())
|
||||||
|
.getSerialNumber());
|
||||||
|
} else {
|
||||||
|
System.out.println("Operation or company est null");
|
||||||
|
System.out.println("Operation : " + calibration);
|
||||||
|
System.out.println("Company : " + calibration.getCompany());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
TraceBackService.trace(response, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSequenceCalibration(ActionRequest request, ActionResponse response) {
|
||||||
|
try {
|
||||||
|
Operation calibration = request.getContext().asType(Operation.class);
|
||||||
|
|
||||||
|
if (calibration != null && calibration.getCompany() != null) {
|
||||||
|
response.setValue(
|
||||||
|
"serialNumber",
|
||||||
|
Beans.get(OperationService.class)
|
||||||
|
.createCalibrationSeq(calibration.getCompany())
|
||||||
|
.getSerialNumber());
|
||||||
|
} else {
|
||||||
|
System.out.println("Operation or company est null");
|
||||||
|
System.out.println("Operation : " + calibration);
|
||||||
|
System.out.println("Company : " + calibration.getCompany());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
TraceBackService.trace(response, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSequenceQualification(ActionRequest request, ActionResponse response) {
|
||||||
|
try {
|
||||||
|
Operation calibration = request.getContext().asType(Operation.class);
|
||||||
|
|
||||||
|
if (calibration != null && calibration.getCompany() != null) {
|
||||||
|
response.setValue(
|
||||||
|
"serialNumber",
|
||||||
|
Beans.get(OperationService.class)
|
||||||
|
.createQualificationSeq(calibration.getCompany())
|
||||||
|
.getSerialNumber());
|
||||||
|
} else {
|
||||||
|
System.out.println("Operation or company est null");
|
||||||
|
System.out.println("Operation : " + calibration);
|
||||||
|
System.out.println("Company : " + calibration.getCompany());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
TraceBackService.trace(response, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMachineInfo(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
|
Operation calibration = request.getContext().asType(Operation.class);
|
||||||
|
Operation newOperation = Beans.get(OperationService.class).setMachine(calibration);
|
||||||
|
// response.setValue(calibration,newOperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||||
|
|
||||||
|
<module name="production" package="com.axelor.apps.production.db"/>
|
||||||
|
|
||||||
|
<entity name="Machine">
|
||||||
|
<one-to-many name="operationList" ref="com.axelor.apps.qvm.db.Operation" mappedBy="machineName" title="Calibrations" />
|
||||||
|
<many-to-one name="machineLocation" ref="com.axelor.apps.qvm.db.MachineLocation" title="Machine Location" required="true"/>
|
||||||
|
<string name="model" title="Model"/>
|
||||||
|
<string name="machineId" title="ID"/>
|
||||||
|
<integer name="typeSelect" title="Type Select" default="0"/>
|
||||||
|
<integer name="machineOperationType" required="true" selection="operation.machine.type.status.select" default="1"/>
|
||||||
|
<string name="remarque" title="Remarque"/>
|
||||||
|
</entity>
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||||
|
|
||||||
|
<module name="qvm" package="com.axelor.apps.qvm.db"/>
|
||||||
|
|
||||||
|
<entity name="MachineLocation">
|
||||||
|
<string name="name" title="Location" required="true"/>
|
||||||
|
<many-to-one name="parent" ref="com.axelor.apps.qvm.db.MachineLocation" title="parent"/>
|
||||||
|
<one-to-many name="machineList" ref="com.axelor.apps.production.db.Machine" mappedBy="machineLocation" title="Machine List" />
|
||||||
|
<integer name="orderByState"/>
|
||||||
|
<integer name="stockUnity" selection="operation.parent.location.select" default="0"/>
|
||||||
|
<integer name="typeSelect" title="Type Select" default="0"/>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||||
|
|
||||||
|
<module name="qvm" package="com.axelor.apps.qvm.db"/>
|
||||||
|
|
||||||
|
<entity name="Operation">
|
||||||
|
|
||||||
|
<string name="serialNumber" />
|
||||||
|
<many-to-one name="operationType" ref="com.axelor.apps.qvm.db.OperationType" required="true"/>
|
||||||
|
|
||||||
|
<many-to-one name="machineName" ref="com.axelor.apps.production.db.Machine" required="true"/>
|
||||||
|
<string name="machineId"/>
|
||||||
|
<string name="machineBrand"/>
|
||||||
|
<string name="machineModel"/>
|
||||||
|
<string name="machineSerialNumber"/>
|
||||||
|
<many-to-one name="machineLocalisation" ref="com.axelor.apps.qvm.db.MachineLocation"/>
|
||||||
|
<many-to-one name="machineLocalisationParent" ref="com.axelor.apps.qvm.db.MachineLocation"/>
|
||||||
|
<integer name="stockUnity" selection="operation.parent.location.select" default="0"/>
|
||||||
|
|
||||||
|
<string name="fullRange"/>
|
||||||
|
<string name="operationRange"/>
|
||||||
|
<decimal name="leastCount"/>
|
||||||
|
|
||||||
|
<string name="operationFrequency"/>
|
||||||
|
<date name="pastOperationDate"/>
|
||||||
|
|
||||||
|
<date name="operationDate"/>
|
||||||
|
<date name="operationDueDate"/>
|
||||||
|
<integer name="countdown"/>
|
||||||
|
<string name="reportCertifiacteNumber"/>
|
||||||
|
<boolean name="externalInternal" default="true"/>
|
||||||
|
|
||||||
|
<integer name="statusSelect" selection="operation.status.select" default="1"/>
|
||||||
|
<many-to-one name="company" ref="com.axelor.apps.base.db.Company" title="Company" hidden="true"/>
|
||||||
|
<integer name="typeSelect" title="Type Select" selection = "operation.type.status.select" default="0"/>
|
||||||
|
|
||||||
|
<integer name="orderByState"/>
|
||||||
|
<many-to-one name="purchaseRequest" ref="com.axelor.apps.purchase.db.PurchaseRequest" />
|
||||||
|
<integer name="parentLocation" selection="operation.parent.location.select" default="0"/>
|
||||||
|
|
||||||
|
<track>
|
||||||
|
<field name="createdOn"/>orderByState
|
||||||
|
<field name="statusSelect"/>
|
||||||
|
<field name="machineName"/>
|
||||||
|
<field name="machineId"/>
|
||||||
|
<field name="machineBrand"/>
|
||||||
|
<field name="machineModel"/>
|
||||||
|
<field name="machineSerialNumber"/>
|
||||||
|
<field name="machineLocalisation"/>
|
||||||
|
<field name="fullRange"/>
|
||||||
|
<field name="operationRange"/>
|
||||||
|
<field name="leastCount"/>
|
||||||
|
<field name="operationDate"/>
|
||||||
|
<field name="operationDueDate"/>
|
||||||
|
<field name="countdown"/>
|
||||||
|
<field name="reportCertifiacteNumber"/>
|
||||||
|
<field name="external"/>
|
||||||
|
<field name="internal"/>
|
||||||
|
</track>
|
||||||
|
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||||
|
|
||||||
|
<module name="qvm" package="com.axelor.apps.qvm.db"/>
|
||||||
|
|
||||||
|
<entity name="OperationType">
|
||||||
|
<string name="fullName" namecolumn="true">
|
||||||
|
<![CDATA[
|
||||||
|
|
||||||
|
return name+" "+stockUnity;
|
||||||
|
]]>
|
||||||
|
</string>
|
||||||
|
<string name="name" title="Operation Type" required="true"/>
|
||||||
|
<!--<many-to-one name="parent" ref="com.axelor.apps.qvm.db.MachineLocation" title="parent"/>-->
|
||||||
|
<integer name="stockUnity" selection="operation.parent.location.select" default="0"/>
|
||||||
|
<integer name="orderByState"/>
|
||||||
|
<one-to-many name="operationList" ref="com.axelor.apps.qvm.db.Operation" mappedBy="operationType" title="Operations" />
|
||||||
|
<integer name="typeSelect"/>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
|
||||||
|
|
||||||
|
<module name="base" package="com.axelor.apps.base.db"/>
|
||||||
|
|
||||||
|
<entity name="Sequence" lang="java">
|
||||||
|
|
||||||
|
<extra-code><![CDATA[
|
||||||
|
|
||||||
|
//SEQUENCE SELECT
|
||||||
|
public static final String CALIB_SEQ = "calibrationSeq";
|
||||||
|
public static final String QUAL_SEQ = "qualificationSeq";
|
||||||
|
public static final String OP_SEQ = "operationSeq";
|
||||||
|
|
||||||
|
]]></extra-code>
|
||||||
|
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views http://axelor.com/xml/ns/object-views/object-views_5.2.xsd">
|
||||||
|
|
||||||
|
<grid name="machine-grid-qvm" title="Instrument / Equipment" model="com.axelor.apps.production.db.Machine">
|
||||||
|
<field name="machineId" title="ID"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="brand"/>
|
||||||
|
<field name="model"/>
|
||||||
|
<field name="serialNumber"/>
|
||||||
|
<field name="machineLocation" title="Location" grid-view="machine-location-grid" form-view="machine-location-form"/>
|
||||||
|
<field name="machineLocation.parent" title="Location Parent" grid-view="machine-location-grid" form-view="machine-location-form"/>
|
||||||
|
<field name="machineLocation.stockUnity" title="Location Unity" grid-view="machine-location-grid" form-view="machine-location-form"/>
|
||||||
|
<field name="description" title="Description"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<form name="machine-form-qvm" title="Instrument / Equipment" model="com.axelor.apps.production.db.Machine" width="large" onNew="set-qvm-machine-type"
|
||||||
|
onLoad="action-record-machine-set-operating-duration">
|
||||||
|
|
||||||
|
<panel name="informationsPanel" colSpan="9">
|
||||||
|
<field name="picture" showTitle="false" colSpan="12" widget="Image"/>
|
||||||
|
<field name="serialNumber" colSpan="4" placeholder="Serial Number"/>
|
||||||
|
<field name="name" required="true" colSpan="4" placeholder="Name"/>
|
||||||
|
<field name="machineOperationType" required="true" title="Type" colSpan="4" placeholder="Operation Type" onChange="machine-operation-type-panel-title-changer"/>
|
||||||
|
<!--<panel name="actionPanel" colSpan="6">
|
||||||
|
<button name="$operatingDurationBtn" title="Operating duration" colSpan="12" icon="fa-clock-o" widget="info-button"/>
|
||||||
|
</panel>-->
|
||||||
|
</panel>
|
||||||
|
|
||||||
|
<panel name="mainPanel" title="">
|
||||||
|
<field name="machineId" title="ID" colSpan="4"/>
|
||||||
|
<field name="brand" colSpan="4"/>
|
||||||
|
<field name="machineLocation" title="Location" colSpan="4" required="true"/>
|
||||||
|
<field name="startingDuration" colSpan="4" widget="duration" x-big="true" x-seconds="true"/>
|
||||||
|
<field name="setupDuration" colSpan="4" widget="duration" x-big="true" x-seconds="true"/>
|
||||||
|
<field name="endingDuration" colSpan="4" widget="duration" x-big="true" x-seconds="true"/>
|
||||||
|
<field name="weeklyPlanning" canNew="true"/>
|
||||||
|
<field name="description" colSpan="12"/>
|
||||||
|
</panel>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<action-view name="manufacturing.equipement.qvm" model="com.axelor.apps.production.db.Machine" title="Instrument / Equipment">
|
||||||
|
<view name="machine-grid-qvm" type="grid"/>
|
||||||
|
<view name="machine-form-qvm" type="form"/>
|
||||||
|
<domain>self.typeSelect = 1 or self.typeSelect = 2</domain>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-method name="action-operation-set-machine-info">
|
||||||
|
<call method="setMachineInfo" class="com.axelor.apps.qvm.web.QvmOperationController"/>
|
||||||
|
</action-method>
|
||||||
|
|
||||||
|
<action-record name="set-qvm-machine-type" model="com.axelor.apps.production.db.Machine">
|
||||||
|
<field name="statusSelect" expr="eval: 2"/>
|
||||||
|
</action-record>
|
||||||
|
|
||||||
|
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views http://axelor.com/xml/ns/object-views/object-views_5.2.xsd">
|
||||||
|
|
||||||
|
<grid name="machine-location-grid-qvm" title="Equipement Location" model="com.axelor.apps.qvm.db.MachineLocation">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="parent"/>
|
||||||
|
<field name="stockUnity"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<form name="machine-location-form-qvm" title="Equipement Location" model="com.axelor.apps.qvm.db.MachineLocation" >
|
||||||
|
<panel name="mainPanel">
|
||||||
|
<field name="name" colSpan="4"/>
|
||||||
|
<field name="parent" colSpan="4" onChange="save,action-record-machine_location-default-location-record"/>
|
||||||
|
<field name="stockUnity" colSpan="4"/>
|
||||||
|
<field name="machineList" grid-view="machine-grid-qvm" form-view="machine-form-qvm" colSpan="12"/>
|
||||||
|
</panel>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<kanban name="machine-location-kanban-view" title="Machine Location" model="com.axelor.apps.qvm.db.MachineLocation" columnBy="stockUnity" sequenceBy="orderByState" draggable="false" limit="30">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="parent"/>
|
||||||
|
<template><![CDATA[
|
||||||
|
<h4>{{name}}</h4>]]>
|
||||||
|
</template>
|
||||||
|
</kanban>
|
||||||
|
|
||||||
|
<action-view name="machine.location.qvm" model="com.axelor.apps.qvm.db.MachineLocation" title="Equipement Location">
|
||||||
|
<view name="machine-location-grid-qvm" type="grid"/>
|
||||||
|
<view name="machine-location-form-qvm" type="form"/>
|
||||||
|
<view name="machine-location-kanban-view" type="kanban"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,354 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views http://axelor.com/xml/ns/object-views/object-views_5.2.xsd">
|
||||||
|
<!-- Operation -->
|
||||||
|
<form name="operation-form" title="Operations" onNew="action-record-operation-default-record" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<toolbar>
|
||||||
|
<button name="printBtn" title="Print" readonlyIf="!id" icon="fa-print" onClick="action-production-request-method-print"/>
|
||||||
|
</toolbar>
|
||||||
|
<panel name="statusSelectPanel" colSpan="12">
|
||||||
|
<field name="statusSelect" title="Status" selection="operation.status.select" showTitle="false" readonly="true" colSpan="12" widget="nav-select"/>
|
||||||
|
<field name="serialNumber" title="Serial Number" colSpan="12" readonly="true"/>
|
||||||
|
<field name="operationType" title="Operation Type" grid-view="operation-type-grid" form-view="operation-type-form" onChange="action-record-operation-default-type-record"/>
|
||||||
|
<field name="purchaseRequest" title="Purchase Request" grid-view="purchase-request-grid" form-view="purchase-request-form" domain="self.familleProduit = 149 and self.statusSelect != 7 and self.statusSelect != 8"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="detailPanel" sidebar="true">
|
||||||
|
<button name="draftBtn" title="Draft" showIf="statusSelect == 5" css="btn-info" icon="fa-edit" onClick="save,action-operation-request-set-status-draft, save"/>
|
||||||
|
<button name="requestBtn" title="Request" showIf="statusSelect == 1" icon="fa-bullhorn" onClick="action-operation-set-seq-group,action-operation-request-set-status-request,save"/>
|
||||||
|
<button name="acceptBtn" title="Accept" showIf="statusSelect == 2" icon="fa-check" css="btn-success" onClick="save,action-operation-request-set-status-accept,save"/>
|
||||||
|
<button name="refuseBtn" title="Refuse" showIf="statusSelect == 2 " css="btn-warning" icon="fa-times" onClick="save,action-operation-request-set-status-refuse,save"/>
|
||||||
|
<button name="cancelBtn" title="Cancel" showIf="statusSelect == 1 || statusSelect == 2 || statusSelect == 3 || statusSelect == 4" css="btn-danger" icon="fa-times-circle" onClick="save,action-operation-request-set-status-cancel,save"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="machine" >
|
||||||
|
<field name="machineName" title="Name" grid-view="machine-grid-qvm" form-view="machine-form-qvm" onChange="action-record-machine-operation-default" domain="self.typeSelect != 0" colSpan="6"/>
|
||||||
|
<spacer colSpan="6" />
|
||||||
|
<field name="machineId" title="Id" colSpan="4"/>
|
||||||
|
<field name="machineBrand" title="Brand" colSpan="4"/>
|
||||||
|
<field name="machineModel" title="Model" colSpan="4"/>
|
||||||
|
<field name="machineSerialNumber" title="Serial Number" colSpan="4"/>
|
||||||
|
<field name="machineLocation" title="Location" colSpan="4"/>
|
||||||
|
<field name="machineLocationParent" title="Location Parent" colSpan="4"/>
|
||||||
|
</panel>
|
||||||
|
<panel>
|
||||||
|
<field name="fullRange" title="Full Range"/>
|
||||||
|
<field name="operationRange" title="Operation Range"/>
|
||||||
|
<field name="leastCount" title="Least Count"/>
|
||||||
|
<field name="operationFrequency" title="Operation Frequency"/>
|
||||||
|
<field name="pastOperationDate" title="Past Operation Date"/>
|
||||||
|
<field name="operationDate" title="Operation Date"/>
|
||||||
|
<field name="operationDueDate" title="Operation Due Date"/>
|
||||||
|
<field name="countdown" title="Countdown"/>
|
||||||
|
<field name="reportCertifiacteNumber" title="Report / Certifiacte Number"/>
|
||||||
|
<field name="externalInternal" title="Internal" onChange = "internal-external-validation-title-changer" widget="boolean-switch"/>
|
||||||
|
</panel>
|
||||||
|
<panel sidebar="true" title="Suivi" canCollapse="true" collapseIf="true">
|
||||||
|
<field name="createdOn"/>
|
||||||
|
<field name="createdBy"/>
|
||||||
|
<field name="updatedOn"/>
|
||||||
|
<field name="updatedBy"/>
|
||||||
|
</panel>
|
||||||
|
<panel-mail>
|
||||||
|
<mail-messages limit="4" />
|
||||||
|
<mail-followers />
|
||||||
|
</panel-mail>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<grid name="operation-grid" title="Operations" model="com.axelor.apps.qvm.db.Operation" edit-icon="true">
|
||||||
|
<hilite background="success" if="$moment(operationDueDate).diff(todayDate,'days') < 0"/>
|
||||||
|
<hilite background="primary" if="$moment(operationDueDate).diff(todayDate,'days') == 0"/>
|
||||||
|
<hilite background="danger" if="$moment(operationDueDate).diff(todayDate,'days') < 10 && $moment(operationDueDate).diff(todayDate,'days') > 0"/>
|
||||||
|
<hilite background="warning" if="$moment(operationDueDate).diff(todayDate,'days') < 30 && $moment(operationDueDate).diff(todayDate,'days') > 10"/>
|
||||||
|
<hilite background="info" if="$moment(operationDueDate).diff(todayDate,'days') < 40 && $moment(operationDueDate).diff(todayDate,'days') > 30"/>
|
||||||
|
|
||||||
|
<field name="serialNumber" title="Serial Number"/>
|
||||||
|
<field name="statusSelect" title="Status">
|
||||||
|
<hilite color="primary" if="statusSelect == 2"/>
|
||||||
|
<hilite color="success" if="statusSelect == 3"/>
|
||||||
|
<hilite color="warning" if="statusSelect == 4"/>
|
||||||
|
<hilite color="danger" if="statusSelect == 5"/>
|
||||||
|
</field>
|
||||||
|
<field name="operationType" title="Operation Type"/>
|
||||||
|
<field name="typeSelect" title="Type"/>
|
||||||
|
<field name="purchaseRequest" title="Purchase Request"/>
|
||||||
|
<field name="machineName" title="Name"/>
|
||||||
|
<field name="machineId" title="Id"/>
|
||||||
|
<field name="machineBrand" title="Brand"/>
|
||||||
|
<field name="machineModel" title="Model"/>
|
||||||
|
<field name="machineSerialNumber" title="Serial Number"/>
|
||||||
|
<field name="machineLocation" title="Location"/>
|
||||||
|
<field name="machineLocationParent" title="Location Parent"/>
|
||||||
|
<field name="fullRange" title="Full Range"/>
|
||||||
|
<field name="operationRange" title="Operation Range"/>
|
||||||
|
<field name="leastCount" title="Least Count"/>
|
||||||
|
<field name="operationFrequency" title="Operation Frequency"/>
|
||||||
|
<field name="pastOperationDate" title="Past Operation Date"/>
|
||||||
|
<field name="operationDate" title="Operation Date"/>
|
||||||
|
<field name="operationDueDate" title="Operation Due Date"/>
|
||||||
|
<field name="countdown" title="Countdown"/>
|
||||||
|
<field name="reportCertifiacteNumber" title="Report / Certifiacte Number"/>
|
||||||
|
<field name="externalInternal" title="Internal"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<!-- Calibration -->
|
||||||
|
<form name="calibration-form" title="Calibrations" onNew="action-record-operation-default-record" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<toolbar>
|
||||||
|
<button name="printBtn" title="Print" readonlyIf="!id" icon="fa-print" onClick="action-production-request-method-print"/>
|
||||||
|
</toolbar>
|
||||||
|
<panel name="statusSelectPanel" colSpan="12">
|
||||||
|
<field name="statusSelect" title="Status" selection="operation.status.select" showTitle="false" readonly="true" colSpan="12" widget="nav-select"/>
|
||||||
|
<field name="serialNumber" title="Serial Number" colSpan="12" readonly="true"/>
|
||||||
|
<field name="operationType" domain="self.typeSelect = 2" title="Operation Type" grid-view="operation-type-grid" form-view="operation-type-form" onChange="action-record-operation-default-type-record"/>
|
||||||
|
<field name="purchaseRequest" title="Purchase Request" grid-view="purchase-request-grid" form-view="purchase-request-form" domain="self.familleProduit = 149 and self.statusSelect != 7 and self.statusSelect != 8"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="detailPanel" sidebar="true">
|
||||||
|
<button name="draftBtn" title="Draft" showIf="statusSelect == 5" css="btn-info" icon="fa-edit" onClick="save,action-operation-request-set-status-draft, save"/>
|
||||||
|
<button name="requestBtn" title="Request" showIf="statusSelect == 1" icon="fa-bullhorn" onClick="action-operation-set-seq-group,action-operation-request-set-status-request,save"/>
|
||||||
|
<button name="acceptBtn" title="Accept" showIf="statusSelect == 2" icon="fa-check" css="btn-success" onClick="save,action-operation-request-set-status-accept,save"/>
|
||||||
|
<button name="refuseBtn" title="Refuse" showIf="statusSelect == 2 " css="btn-warning" icon="fa-times" onClick="save,action-operation-request-set-status-refuse,save"/>
|
||||||
|
<button name="cancelBtn" title="Cancel" showIf="statusSelect == 1 || statusSelect == 2 || statusSelect == 3 || statusSelect == 4" css="btn-danger" icon="fa-times-circle" onClick="save,action-operation-request-set-status-cancel,save"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="machine" >
|
||||||
|
<field name="machineName" title="Name" grid-view="machine-grid-qvm" form-view="machine-form-qvm" onChange="action-record-machine-operation-default" domain="self.typeSelect != 0" colSpan="6"/>
|
||||||
|
<spacer colSpan="6" />
|
||||||
|
<field name="machineId" title="Id" colSpan="4"/>
|
||||||
|
<field name="machineBrand" title="Brand" colSpan="4"/>
|
||||||
|
<field name="machineModel" title="Model" colSpan="4"/>
|
||||||
|
<field name="machineSerialNumber" title="Serial Number" colSpan="4"/>
|
||||||
|
<field name="machineLocation" title="Location" colSpan="4"/>
|
||||||
|
<field name="machineLocationParent" title="Location Parent" colSpan="4"/>
|
||||||
|
</panel>
|
||||||
|
<panel>
|
||||||
|
<field name="fullRange" title="Full Range"/>
|
||||||
|
<field name="operationRange" title="Calibration Range"/>
|
||||||
|
<field name="leastCount" title="Least Count"/>
|
||||||
|
<field name="operationFrequency" title="Calibration Frequency"/>
|
||||||
|
<field name="pastOperationDate" title="Past Calibration Date"/>
|
||||||
|
<field name="operationDate" title="Calibration Date"/>
|
||||||
|
<field name="operationDueDate" title="Calibration Due Date"/>
|
||||||
|
<field name="countdown" title="Countdown"/>
|
||||||
|
<field name="reportCertifiacteNumber" title="Report / Certifiacte Number"/>
|
||||||
|
<field name="externalInternal" title="Internal" onChange = "internal-external-validation-title-changer" widget="boolean-switch"/>
|
||||||
|
</panel>
|
||||||
|
<panel sidebar="true" title="Suivi" canCollapse="true" collapseIf="true">
|
||||||
|
<field name="createdOn"/>
|
||||||
|
<field name="createdBy"/>
|
||||||
|
<field name="updatedOn"/>
|
||||||
|
<field name="updatedBy"/>
|
||||||
|
</panel>
|
||||||
|
<panel-mail>
|
||||||
|
<mail-messages limit="4" />
|
||||||
|
<mail-followers />
|
||||||
|
</panel-mail>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<grid name="calibration-grid" title="Calibrations" model="com.axelor.apps.qvm.db.Operation" edit-icon="true">
|
||||||
|
<hilite background="success" if="$moment(operationDueDate).diff(todayDate,'days') < 0"/>
|
||||||
|
<hilite background="primary" if="$moment(operationDueDate).diff(todayDate,'days') == 0"/>
|
||||||
|
<hilite background="danger" if="$moment(operationDueDate).diff(todayDate,'days') < 10 && $moment(operationDueDate).diff(todayDate,'days') > 0"/>
|
||||||
|
<hilite background="warning" if="$moment(operationDueDate).diff(todayDate,'days') < 30 && $moment(operationDueDate).diff(todayDate,'days') > 10"/>
|
||||||
|
<hilite background="info" if="$moment(operationDueDate).diff(todayDate,'days') < 40 && $moment(operationDueDate).diff(todayDate,'days') > 30"/>
|
||||||
|
|
||||||
|
<field name="serialNumber" title="Serial Number"/>
|
||||||
|
<field name="statusSelect" title="Status">
|
||||||
|
<hilite color="primary" if="statusSelect == 2"/>
|
||||||
|
<hilite color="success" if="statusSelect == 3"/>
|
||||||
|
<hilite color="warning" if="statusSelect == 4"/>
|
||||||
|
<hilite color="danger" if="statusSelect == 5"/>
|
||||||
|
</field>
|
||||||
|
<field name="operationType" title="Calibration Type"/>
|
||||||
|
<field name="typeSelect" title="Type"/>
|
||||||
|
<field name="purchaseRequest" title="Purchase Request"/>
|
||||||
|
<field name="machineName" title="Name"/>
|
||||||
|
<field name="machineId" title="Id"/>
|
||||||
|
<field name="machineBrand" title="Brand"/>
|
||||||
|
<field name="machineModel" title="Model"/>
|
||||||
|
<field name="machineSerialNumber" title="Serial Number"/>
|
||||||
|
<field name="machineLocation" title="Location"/>
|
||||||
|
<field name="machineLocationParent" title="Location Parent"/>
|
||||||
|
<field name="fullRange" title="Full Range"/>
|
||||||
|
<field name="operationRange" title="Calibration Range"/>
|
||||||
|
<field name="leastCount" title="Least Count"/>
|
||||||
|
<field name="operationFrequency" title="Calibration Frequency"/>
|
||||||
|
<field name="pastOperationDate" title="Past Calibration Date"/>
|
||||||
|
<field name="operationDate" title="Calibration Date"/>
|
||||||
|
<field name="operationDueDate" title="Calibration Due Date"/>
|
||||||
|
<field name="countdown" title="Countdown"/>
|
||||||
|
<field name="reportCertifiacteNumber" title="Report / Certifiacte Number"/>
|
||||||
|
<field name="externalInternal" title="Internal"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<!-- Qualification -->
|
||||||
|
<form name="qualification-form" title="Qualifications" onNew="action-record-operation-default-record" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<toolbar>
|
||||||
|
<button name="printBtn" title="Print" readonlyIf="!id" icon="fa-print" onClick="action-production-request-method-print"/>
|
||||||
|
</toolbar>
|
||||||
|
<panel name="statusSelectPanel" colSpan="12">
|
||||||
|
<field name="statusSelect" title="Status" selection="operation.status.select" showTitle="false" readonly="true" colSpan="12" widget="nav-select"/>
|
||||||
|
<field name="serialNumber" title="Serial Number" colSpan="12" readonly="true"/>
|
||||||
|
<field name="operationType" domain="self.typeSelect = 2" title="Operation Type" grid-view="operation-type-grid" form-view="operation-type-form" onChange="action-record-operation-default-type-record"/>
|
||||||
|
<field name="purchaseRequest" title="Purchase Request" grid-view="purchase-request-grid" form-view="purchase-request-form" domain="self.familleProduit = 149 and self.statusSelect != 7 and self.statusSelect != 8"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="detailPanel" sidebar="true">
|
||||||
|
<button name="draftBtn" title="Draft" showIf="statusSelect == 5" css="btn-info" icon="fa-edit" onClick="save,action-operation-request-set-status-draft, save"/>
|
||||||
|
<button name="requestBtn" title="Request" showIf="statusSelect == 1" icon="fa-bullhorn" onClick="action-operation-set-seq-group,action-operation-request-set-status-request,save"/>
|
||||||
|
<button name="acceptBtn" title="Accept" showIf="statusSelect == 2" icon="fa-check" css="btn-success" onClick="save,action-operation-request-set-status-accept,save"/>
|
||||||
|
<button name="refuseBtn" title="Refuse" showIf="statusSelect == 2 " css="btn-warning" icon="fa-times" onClick="save,action-operation-request-set-status-refuse,save"/>
|
||||||
|
<button name="cancelBtn" title="Cancel" showIf="statusSelect == 1 || statusSelect == 2 || statusSelect == 3 || statusSelect == 4" css="btn-danger" icon="fa-times-circle" onClick="save,action-operation-request-set-status-cancel,save"/>
|
||||||
|
</panel>
|
||||||
|
<panel name="machine" >
|
||||||
|
<field name="machineName" title="Name" grid-view="machine-grid-qvm" form-view="machine-form-qvm" onChange="action-record-machine-operation-default" domain="self.typeSelect != 0" colSpan="6"/>
|
||||||
|
<spacer colSpan="6" />
|
||||||
|
<field name="machineId" title="Id" colSpan="4"/>
|
||||||
|
<field name="machineBrand" title="Brand" colSpan="4"/>
|
||||||
|
<field name="machineModel" title="Model" colSpan="4"/>
|
||||||
|
<field name="machineSerialNumber" title="Serial Number" colSpan="4"/>
|
||||||
|
<field name="machineLocation" title="Location" colSpan="4"/>
|
||||||
|
<field name="machineLocationParent" title="Location Parent" colSpan="4"/>
|
||||||
|
</panel>
|
||||||
|
<panel>
|
||||||
|
<field name="fullRange" title="Full Range"/>
|
||||||
|
<field name="operationRange" title="Qualification Range"/>
|
||||||
|
<field name="leastCount" title="Least Count"/>
|
||||||
|
<field name="operationFrequency" title="Qualification Frequency"/>
|
||||||
|
<field name="pastOperationDate" title="Past Qualification Date"/>
|
||||||
|
<field name="operationDate" title="Qualification Date"/>
|
||||||
|
<field name="operationDueDate" title="Qualification Due Date"/>
|
||||||
|
<field name="countdown" title="Countdown"/>
|
||||||
|
<field name="reportCertifiacteNumber" title="Report / Certifiacte Number"/>
|
||||||
|
<field name="externalInternal" title="Internal" onChange = "internal-external-validation-title-changer" widget="boolean-switch"/>
|
||||||
|
</panel>
|
||||||
|
<panel sidebar="true" title="Suivi" canCollapse="true" collapseIf="true">
|
||||||
|
<field name="createdOn"/>
|
||||||
|
<field name="createdBy"/>
|
||||||
|
<field name="updatedOn"/>
|
||||||
|
<field name="updatedBy"/>
|
||||||
|
</panel>
|
||||||
|
<panel-mail>
|
||||||
|
<mail-messages limit="4" />
|
||||||
|
<mail-followers />
|
||||||
|
</panel-mail>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<grid name="qualification-grid" title="Qualifications" model="com.axelor.apps.qvm.db.Operation" edit-icon="true">
|
||||||
|
<hilite background="success" if="$moment(operationDueDate).diff(todayDate,'days') < 0"/>
|
||||||
|
<hilite background="primary" if="$moment(operationDueDate).diff(todayDate,'days') == 0"/>
|
||||||
|
<hilite background="danger" if="$moment(operationDueDate).diff(todayDate,'days') < 10 && $moment(operationDueDate).diff(todayDate,'days') > 0"/>
|
||||||
|
<hilite background="warning" if="$moment(operationDueDate).diff(todayDate,'days') < 30 && $moment(operationDueDate).diff(todayDate,'days') > 10"/>
|
||||||
|
<hilite background="info" if="$moment(operationDueDate).diff(todayDate,'days') < 40 && $moment(operationDueDate).diff(todayDate,'days') > 30"/>
|
||||||
|
|
||||||
|
<field name="serialNumber" title="Serial Number"/>
|
||||||
|
<field name="statusSelect" title="Status">
|
||||||
|
<hilite color="primary" if="statusSelect == 2"/>
|
||||||
|
<hilite color="success" if="statusSelect == 3"/>
|
||||||
|
<hilite color="warning" if="statusSelect == 4"/>
|
||||||
|
<hilite color="danger" if="statusSelect == 5"/>
|
||||||
|
</field>
|
||||||
|
<field name="operationType" title="Qualification Type"/>
|
||||||
|
<field name="typeSelect" title="Type"/>
|
||||||
|
<field name="purchaseRequest" title="Purchase Request"/>
|
||||||
|
<field name="machineName" title="Name"/>
|
||||||
|
<field name="machineId" title="Id"/>
|
||||||
|
<field name="machineBrand" title="Brand"/>
|
||||||
|
<field name="machineModel" title="Model"/>
|
||||||
|
<field name="machineSerialNumber" title="Serial Number"/>
|
||||||
|
<field name="machineLocation" title="Location"/>
|
||||||
|
<field name="machineLocationParent" title="Location Parent"/>
|
||||||
|
<field name="fullRange" title="Full Range"/>
|
||||||
|
<field name="operationRange" title="Qualification Range"/>
|
||||||
|
<field name="leastCount" title="Least Count"/>
|
||||||
|
<field name="operationFrequency" title="Qualification Frequency"/>
|
||||||
|
<field name="pastOperationDate" title="Past Qualification Date"/>
|
||||||
|
<field name="operationDate" title="Qualification Date"/>
|
||||||
|
<field name="operationDueDate" title="Qualification Due Date"/>
|
||||||
|
<field name="countdown" title="Countdown"/>
|
||||||
|
<field name="reportCertifiacteNumber" title="Report / Certifiacte Number"/>
|
||||||
|
<field name="externalInternal" title="Internal"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<action-record name="action-record-machine-operation-default" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<field name="machineId" expr="eval:machineName.machineId" if="machineName != null"/>
|
||||||
|
<field name="machineBrand" expr="eval:machineName.brand" if="machineName != null"/>
|
||||||
|
<field name="machineModel" expr="eval:machineName.model" if="machineName != null"/>
|
||||||
|
<field name="machineSerialNumber" expr="eval:machineName.serialNumber" if="machineName != null"/>
|
||||||
|
<field name="machineLocation" expr="eval:machineName.machineLocation" if="machineName != null"/>
|
||||||
|
<field name="machineLocationParent" expr="eval:machineName.machineLocation.parent" if="machineName != null"/>
|
||||||
|
<field name="stockUnity" expr="eval:machineName.machineLocation.parent.stockUnity" if="machineName != null"/>
|
||||||
|
</action-record>
|
||||||
|
|
||||||
|
<action-record name="action-record-operation-default-record" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<field name="company" expr="eval:__user__.activeCompany" if="__user__.activeCompany != null"/>
|
||||||
|
<field name="company" expr="eval:__repo__(Company).all().fetchOne()" if="__user__.activeCompany == null && __repo__(Company).all().fetch().size == 1"/>
|
||||||
|
</action-record>
|
||||||
|
|
||||||
|
<action-record name="action-operation-request-set-status-accept" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<field name="statusSelect" expr="eval:3"/>
|
||||||
|
</action-record>
|
||||||
|
<action-record name="action-operation-request-set-status-cancel" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<field name="statusSelect" expr="eval:5"/>
|
||||||
|
</action-record>
|
||||||
|
<action-record name="action-operation-request-set-status-draft" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<field name="statusSelect" expr="eval:1"/>
|
||||||
|
</action-record>
|
||||||
|
<action-record name="action-operation-request-set-status-refuse" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<field name="statusSelect" expr="eval:4"/>
|
||||||
|
</action-record>
|
||||||
|
<action-record name="action-operation-request-set-status-request" model="com.axelor.apps.qvm.db.Operation">
|
||||||
|
<field name="statusSelect" expr="eval:2"/>
|
||||||
|
</action-record>
|
||||||
|
|
||||||
|
<action-attrs name="internal-external-operation-title-changer">
|
||||||
|
<attribute if="externalInternal == false" name="title" expr="External :" for="externalInternal"/>
|
||||||
|
<attribute if="externalInternal == true" name="title" expr="Internal :" for="externalInternal"/>
|
||||||
|
</action-attrs>
|
||||||
|
|
||||||
|
<action-view name="operation.action.view" model="com.axelor.apps.qvm.db.Operation" title="Operations">
|
||||||
|
<view name="operation-grid" type="grid"/>
|
||||||
|
<view name="operation-kanban-view" type="kanban"/>
|
||||||
|
<view name="operation-form" type="form"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-view name="operation.operation.action.view" model="com.axelor.apps.qvm.db.Operation" title="Calibrations">
|
||||||
|
<view name="operation-grid" type="grid"/>
|
||||||
|
<view name="operation-kanban-view" type="kanban"/>
|
||||||
|
<view name="operation-form" type="form"/>
|
||||||
|
<domain>self.typeSelect = :_ts</domain>
|
||||||
|
<context name="_ts" expr="eval: 1"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-view name="qualification.operation.action.view" model="com.axelor.apps.qvm.db.Operation" title="Qualifications">
|
||||||
|
<view name="operation-grid" type="grid"/>
|
||||||
|
<view name="operation-kanban-view" type="kanban"/>
|
||||||
|
<view name="operation-form" type="form"/>
|
||||||
|
<domain>self.typeSelect = :_ts</domain>
|
||||||
|
<context name="_ts" expr="eval: 2"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-view name="operation.action.view.related" model="com.axelor.apps.qvm.db.Operation" title="Operations">
|
||||||
|
<view name="operation-grid" type="grid"/>
|
||||||
|
<view name="operation-form" type="form"/>
|
||||||
|
<domain>self.operationType = :_id</domain>
|
||||||
|
<context name="_id" expr="eval: id"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
<action-group name="action-operation-set-seq-group">
|
||||||
|
<action name="action-calibration-set-seq"/>
|
||||||
|
<action name="action-qualification-set-seq"/>
|
||||||
|
<action name="action-operation-set-seq"/>
|
||||||
|
</action-group>
|
||||||
|
|
||||||
|
<action-method name="action-calibration-set-seq">
|
||||||
|
<!--<call method="setSequence" class="com.axelor.apps.qvm.web.CalibrationController"/>-->
|
||||||
|
<call if="typeSelect == 1" method="setSequenceCalibration" class="com.axelor.qvm.web.OperationController"/>
|
||||||
|
</action-method>
|
||||||
|
|
||||||
|
<action-method name="action-qualification-set-seq">
|
||||||
|
<call if="typeSelect == 2" method="setSequenceQualification" class="com.axelor.qvm.web.OperationController"/>
|
||||||
|
</action-method>
|
||||||
|
|
||||||
|
<action-method name="action-operation-set-seq">
|
||||||
|
<call if="typeSelect == 3" method="setSequenceOperation" class="com.axelor.qvm.web.OperationController"/>
|
||||||
|
</action-method>
|
||||||
|
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views http://axelor.com/xml/ns/object-views/object-views_5.2.xsd">
|
||||||
|
|
||||||
|
<form name="operation-type-form" title="Operations Type" model="com.axelor.apps.qvm.db.OperationType" width="large">
|
||||||
|
<panel name="Overview" colspan="12">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="stockUnity"/>
|
||||||
|
</panel>
|
||||||
|
<panel-dashlet name="operationList" title="Operations" action="operation.action.view.related" colSpan="12"/>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<grid name="operation-type-grid" title="Operations types" model="com.axelor.apps.qvm.db.OperationType" edit-icon="true">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="stockUnity"/>
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<kanban name="operation-type-kanban-view" title="Operations Type" model="com.axelor.apps.qvm.db.OperationType" columnBy="stockUnity" sequenceBy="stockUnity" draggable="false" limit="30">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="stockUnity"/>
|
||||||
|
<template><![CDATA[
|
||||||
|
<h4>{{name}}</h4>]]>
|
||||||
|
</template>
|
||||||
|
</kanban>
|
||||||
|
|
||||||
|
<action-view name="operation.type.action.view" model="com.axelor.apps.qvm.db.OperationType" title="Operations Type">
|
||||||
|
<view name="operation-type-grid" type="grid"/>
|
||||||
|
<view name="operation-type-kanban-view" type="kanban"/>
|
||||||
|
<view name="operation-type-form" type="form"/>
|
||||||
|
</action-view>
|
||||||
|
|
||||||
|
</object-views>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<object-views xmlns="http://axelor.com/xml/ns/object-views"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://axelor.com/xml/ns/object-views http://axelor.com/xml/ns/object-views/object-views_5.2.xsd">
|
||||||
|
|
||||||
|
|
||||||
|
<selection name="operation.status.select">
|
||||||
|
<option value="1">Draft</option>
|
||||||
|
<option value="2">Requested</option>
|
||||||
|
<option value="3">Accepted</option>
|
||||||
|
<option value="4">Refused</option>
|
||||||
|
<option value="5">Canceled</option>
|
||||||
|
</selection>
|
||||||
|
|
||||||
|
<selection name="operation.type.status.select">
|
||||||
|
<option value="1">Calibration</option>
|
||||||
|
<option value="2">Qualification</option>
|
||||||
|
<option value="3">Other</option>
|
||||||
|
</selection>
|
||||||
|
|
||||||
|
<selection name="operation.parent.location.select">
|
||||||
|
<option value="1">U1</option>
|
||||||
|
<option value="2">U2</option>
|
||||||
|
<option value="3">U3.1</option>
|
||||||
|
<option value="4">U3.2</option>
|
||||||
|
<option value="5">U4</option>
|
||||||
|
<option value="6">U5</option>
|
||||||
|
<option value="7">U6</option>
|
||||||
|
<option value="8">QC 1</option>
|
||||||
|
<option value="9">QC 2</option>
|
||||||
|
<option value="10">QVM</option>
|
||||||
|
<option value="11">OSD</option>
|
||||||
|
</selection>
|
||||||
|
|
||||||
|
<selection name="operation.machine.type.status.select">
|
||||||
|
<option value="1">Equipement</option>
|
||||||
|
<option value="2">Instrument</option>
|
||||||
|
</selection>
|
||||||
|
|
||||||
|
</object-views>
|
||||||
@@ -8,9 +8,15 @@
|
|||||||
# ~~~~~
|
# ~~~~~
|
||||||
db.default.driver = org.postgresql.Driver
|
db.default.driver = org.postgresql.Driver
|
||||||
db.default.ddl = update
|
db.default.ddl = update
|
||||||
db.default.url = jdbc:postgresql://localhost:5432/bdd_live2
|
db.default.url = jdbc:postgresql://localhost:5432/postgres5
|
||||||
db.default.user = postgres
|
db.default.user = postgres
|
||||||
db.default.password = Ijlv=bB^hSG@PV$,9jkhHzO*74
|
db.default.password = Mal@Ben$$23
|
||||||
|
|
||||||
|
# API
|
||||||
|
# ~~~~~
|
||||||
|
portail.api.baseurl = http://127.0.0.1:8000/api/
|
||||||
|
portail.api.user = admin
|
||||||
|
portail.api.password = 0000
|
||||||
|
|
||||||
# Application Information
|
# Application Information
|
||||||
# ~~~~~
|
# ~~~~~
|
||||||
|
|||||||
Reference in New Issue
Block a user