Add : Attendance Module + QVM Module

This commit is contained in:
Kheireddine Mehdi
2024-11-06 13:08:32 +01:00
parent c33245fd1f
commit c095b563a5
62 changed files with 5263 additions and 13 deletions

View File

@@ -22,12 +22,12 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
import java.net.URL;
import wslite.json.JSONException;
import wslite.json.JSONObject;
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.ActionResponse;
import com.google.inject.Singleton;
import com.mongodb.util.JSON;
import net.minidev.json.JSONObject;
@Singleton
public class AppBaseController {
@@ -174,4 +171,69 @@ public class AppBaseController {
Process p = Runtime.getRuntime().exec(args);
// 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
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -208,4 +208,8 @@ public interface IExceptionMessage {
static final String EMPLOYEE_TIMESHEET_REMINDER_TEMPLATE = /*$$(*/
"Please configure the template for email reminder" /*)*/;
static final String EXTRA_HOURS_1 = /*$$(*/ "No Extra hours import configuration found" /*)*/;
static final String EXTRA_HOURS_2 = /*$$(*/ "Import lead" /*)*/;
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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
}
}
}

View File

@@ -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);*/
}

View File

@@ -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);
}
*/
}

View File

@@ -23,6 +23,7 @@ import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.io.IOException;
import javax.mail.MessagingException;
import wslite.json.JSONObject;
public interface ExtraHoursService {
@@ -50,6 +51,9 @@ public interface ExtraHoursService {
@Transactional(rollbackOn = {Exception.class})
public void refuse(ExtraHours extraHours) throws AxelorException;
@Transactional(rollbackOn = {Exception.class})
public void saveExtraHours(JSONObject jsonObject) throws AxelorException;
public Message sendRefusalEmail(ExtraHours extraHours)
throws AxelorException, ClassNotFoundException, InstantiationException,
IllegalAccessException, MessagingException, IOException;

View File

@@ -17,6 +17,13 @@
*/
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.hr.db.ExtraHours;
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.persist.Transactional;
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.util.List;
import javax.mail.MessagingException;
import wslite.json.JSONException;
import wslite.json.JSONObject;
public class ExtraHoursServiceImpl implements ExtraHoursService {
@@ -40,15 +55,24 @@ public class ExtraHoursServiceImpl implements ExtraHoursService {
protected AppBaseService appBaseService;
protected HRConfigService hrConfigService;
protected TemplateMessageService templateMessageService;
protected CompanyRepository companyRepo;
protected DailyReportRepository dailyReportRepo;
protected EmployeeRepository employeeRepo;
@Inject
public ExtraHoursServiceImpl(
EmployeeRepository employeeRepo,
CompanyRepository companyRepo,
DailyReportRepository dailyReportRepo,
ExtraHoursRepository extraHoursRepo,
AppBaseService appBaseService,
HRConfigService hrConfigService,
TemplateMessageService templateMessageService) {
this.extraHoursRepo = extraHoursRepo;
this.employeeRepo = employeeRepo;
this.companyRepo = companyRepo;
this.dailyReportRepo = dailyReportRepo;
this.appBaseService = appBaseService;
this.hrConfigService = hrConfigService;
this.templateMessageService = templateMessageService;
@@ -162,4 +186,188 @@ public class ExtraHoursServiceImpl implements ExtraHoursService {
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();
}
}
}

View File

@@ -31,9 +31,13 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import javax.mail.MessagingException;
import wslite.json.JSONObject;
public interface LeaveService {
@Transactional(rollbackOn = {Exception.class})
public void saveCR(JSONObject jsonObject) throws AxelorException;
public BigDecimal computeDuration(LeaveRequest leave) throws AxelorException;
public BigDecimal computeDuration(LeaveRequest leave, LocalDate fromDate, LocalDate toDate)

View File

@@ -22,6 +22,7 @@ import com.axelor.apps.base.db.DayPlanning;
import com.axelor.apps.base.db.EventsPlanning;
import com.axelor.apps.base.db.ICalendarEvent;
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.ical.ICalendarService;
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.LeaveReason;
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.LeaveReasonRepository;
import com.axelor.apps.hr.db.repo.LeaveRequestRepository;
@@ -55,6 +59,12 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
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 {
@@ -67,10 +77,16 @@ public class LeaveServiceImpl implements LeaveService {
protected TemplateMessageService templateMessageService;
protected ICalendarEventRepository icalEventRepo;
protected ICalendarService icalendarService;
protected CompanyRepository companyRepo;
protected DailyReportRepository dailyReportRepo;
protected EmployeeRepository employeeRepo;
@Inject
public LeaveServiceImpl(
LeaveLineRepository leaveLineRepo,
CompanyRepository companyRepo,
DailyReportRepository dailyReportRepo,
EmployeeRepository employeeRepo,
WeeklyPlanningService weeklyPlanningService,
PublicHolidayHrService publicHolidayHrService,
LeaveRequestRepository leaveRequestRepo,
@@ -89,6 +105,9 @@ public class LeaveServiceImpl implements LeaveService {
this.templateMessageService = templateMessageService;
this.icalEventRepo = icalEventRepo;
this.icalendarService = icalendarService;
this.companyRepo = companyRepo;
this.employeeRepo = employeeRepo;
this.dailyReportRepo = dailyReportRepo;
}
/**
@@ -913,4 +932,170 @@ public class LeaveServiceImpl implements LeaveService {
}
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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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
}
}
}
}

View File

@@ -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.");
}
}

View File

@@ -17,6 +17,8 @@
*/
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.base.db.Partner;
import com.axelor.apps.hr.db.DPAE;
@@ -42,6 +44,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wslite.json.JSONException;
import wslite.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@Singleton
public class EmployeeController {
@@ -141,4 +146,81 @@ public class EmployeeController {
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();
}
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -17,13 +17,18 @@
*/
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.ImportConfiguration;
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.message.MessageServiceBaseImpl;
import com.axelor.apps.base.web.AppBaseController;
import com.axelor.apps.hr.db.Employee;
import com.axelor.apps.hr.db.ExtraHours;
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.HRMenuValidateService;
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.auth.AuthUtils;
import com.axelor.auth.db.User;
import com.axelor.csv.script.ImportExtraHoursConfiguration;
import com.axelor.db.Query;
import com.axelor.exception.AxelorException;
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.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 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
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) {
List<ExtraHours> extraHoursList =
Beans.get(ExtraHoursRepository.class)
@@ -284,10 +305,124 @@ public class ExtraHoursController {
public void compute(ActionRequest request, ActionResponse response) {
try {
ExtraHours extraHours = request.getContext().asType(ExtraHours.class);
Beans.get(ExtraHoursService.class).compute(extraHours);
// Beans.get(ExtraHoursService.class).compute(extraHours);
response.setValue("totalQty", extraHours.getTotalQty());
} catch (Exception 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
}
}
}
}

View File

@@ -17,10 +17,12 @@
*/
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.Wizard;
import com.axelor.apps.base.service.PeriodService;
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.ExtraHours;
import com.axelor.apps.hr.db.LeaveLine;
@@ -51,10 +53,26 @@ import com.google.inject.Singleton;
import com.google.inject.persist.Transactional;
import java.util.List;
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
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) {
try {
@@ -398,4 +416,91 @@ public class LeaveController {
return Beans.get(HRMenuTagService.class)
.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
}
}
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -82,6 +82,18 @@
]]>
</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>
</domain-models>

View File

@@ -14,11 +14,22 @@
<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"/>
<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"/>
<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"/>
<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"/>

View File

@@ -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>

View File

@@ -28,6 +28,15 @@
<decimal name="quantityBeforeValidation" title="Available quantity (before validation)" scale="4" precision="8" />
<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">
<![CDATA[
if(this.getUser() != null && this.getCreatedOn() != null)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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")
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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') &lt; 0"/>
<hilite background="primary" if="$moment(operationDueDate).diff(todayDate,'days') == 0"/>
<hilite background="danger" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 10 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 0"/>
<hilite background="warning" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 30 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 10"/>
<hilite background="info" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 40 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 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') &lt; 0"/>
<hilite background="primary" if="$moment(operationDueDate).diff(todayDate,'days') == 0"/>
<hilite background="danger" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 10 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 0"/>
<hilite background="warning" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 30 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 10"/>
<hilite background="info" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 40 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 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') &lt; 0"/>
<hilite background="primary" if="$moment(operationDueDate).diff(todayDate,'days') == 0"/>
<hilite background="danger" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 10 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 0"/>
<hilite background="warning" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 30 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 10"/>
<hilite background="info" if="$moment(operationDueDate).diff(todayDate,'days') &lt; 40 &amp;&amp; $moment(operationDueDate).diff(todayDate,'days') &gt; 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 &amp;&amp; __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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -8,9 +8,15 @@
# ~~~~~
db.default.driver = org.postgresql.Driver
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.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
# ~~~~~