Compare commits
57 Commits
pkg/stable
...
fictiv_use
Author | SHA1 | Date | |
---|---|---|---|
d5c81668e3 | |||
f82279e9b2 | |||
6b0b8bf281 | |||
5c690431dc | |||
8dee5b5ce4 | |||
c6ade61a08 | |||
1f2b36b7fd | |||
016d209d43 | |||
f54f582d25 | |||
f183d744cc | |||
756f946ce8 | |||
9604ce80ef | |||
d4b05c883c | |||
aeeb6384c4 | |||
8b46636159 | |||
9471ada755 | |||
df4d62df7d | |||
8b4d1e31ec | |||
dc182b6888 | |||
99b55dece3 | |||
cbe0cbf4e7 | |||
c30bd74e6f | |||
80b6e4964f | |||
1fb5c4c715 | |||
a316a4c753 | |||
46805a2e3d | |||
2513eced52 | |||
38b8b79fb1 | |||
78b6651483 | |||
8f5f136607 | |||
0ba2f94521 | |||
0ee945eed3 | |||
d92e1d8d5c | |||
25f78e3f34 | |||
6452f94cfe | |||
5a4e0c6c0b | |||
19889197ce | |||
ee6601bc35 | |||
7fbed84998 | |||
32c08bcb52 | |||
dd4f03a00e | |||
ae78edf02f | |||
00fc14c91b | |||
5643360f9d | |||
7f19e8c5ff | |||
7edbdbd3e7 | |||
f944981109 | |||
6c68abf922 | |||
79b8fb9af5 | |||
efa4f1fc62 | |||
|
6b00cec84b | ||
20d42d319a | |||
|
80227e7416 | ||
|
c948be02cc | ||
08249abbf5 | |||
03680beba1 | |||
1eafb7090e |
@@ -6,7 +6,9 @@
|
|||||||
|
|
||||||
<containers>
|
<containers>
|
||||||
<container name='web'>
|
<container name='web'>
|
||||||
|
<!--
|
||||||
<package>schedule-apps</package>
|
<package>schedule-apps</package>
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- service de configuration apache -->
|
<!-- service de configuration apache -->
|
||||||
<service method="apache" servicelist="schedule">schedule</service>
|
<service method="apache" servicelist="schedule">schedule</service>
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
<variable type='string' name='schedule_allow_hosts' description="Hôtes authorisés à utiliser la base de données" multi='True'/>
|
<variable type='string' name='schedule_allow_hosts' description="Hôtes authorisés à utiliser la base de données" multi='True'/>
|
||||||
<variable type='string' name='schedule_dbuser' description='Utilisateur du serveur de base de données'/>
|
<variable type='string' name='schedule_dbuser' description='Utilisateur du serveur de base de données'/>
|
||||||
<variable type='string' name='schedule_dbpass' description='Fichier de mot de passe du serveur'/>
|
<variable type='string' name='schedule_dbpass' description='Fichier de mot de passe du serveur'/>
|
||||||
|
<variable type='mail' name='schedule_email_global_notif' description='Email pour envoie de notifications'/>
|
||||||
</family>
|
</family>
|
||||||
</variables>
|
</variables>
|
||||||
|
|
||||||
|
@@ -32,6 +32,16 @@ APP_NAME=Schedule
|
|||||||
APP_ENV=PROD
|
APP_ENV=PROD
|
||||||
APP_CRON=false
|
APP_CRON=false
|
||||||
|
|
||||||
|
# Office hours
|
||||||
|
OFFICE_HOUR_START=09:00
|
||||||
|
OFFICE_HOUR_END=17:30
|
||||||
|
|
||||||
|
# MAIL sendmail / smtp
|
||||||
|
MAILER_METHOD=sendmail
|
||||||
|
MAILER_URL=
|
||||||
|
MAILER_NOREPLY=noreply@noreply.fr
|
||||||
|
MAILER_DEFAULT_NOTIF=
|
||||||
|
|
||||||
# BDD
|
# BDD
|
||||||
DATABASE_NAME=
|
DATABASE_NAME=
|
||||||
DATABASE_USER=
|
DATABASE_USER=
|
||||||
@@ -46,3 +56,9 @@ CAS_USERNAME=username
|
|||||||
CAS_EMAIL=email
|
CAS_EMAIL=email
|
||||||
CAS_LASTNAME=lastname
|
CAS_LASTNAME=lastname
|
||||||
CAS_FIRSTNAME=firstname
|
CAS_FIRSTNAME=firstname
|
||||||
|
|
||||||
|
###> symfony/swiftmailer-bundle ###
|
||||||
|
# For Gmail as a transport, use: "gmail://username:password@localhost"
|
||||||
|
# For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode="
|
||||||
|
# Delivery is disabled by default via "null://localhost"
|
||||||
|
MAILER_URL=
|
1
src/schedule-2.0/.gitignore
vendored
1
src/schedule-2.0/.gitignore
vendored
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
###> symfony/webpack-encore-bundle ###
|
###> symfony/webpack-encore-bundle ###
|
||||||
/node_modules/
|
/node_modules/
|
||||||
/public/build/
|
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
###< symfony/webpack-encore-bundle ###
|
###< symfony/webpack-encore-bundle ###
|
||||||
|
609
src/schedule-2.0/assets/js/timer.js
Normal file
609
src/schedule-2.0/assets/js/timer.js
Normal file
@@ -0,0 +1,609 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/* Creates a new Task object. */
|
||||||
|
function Task(id ,name, description) {
|
||||||
|
this._name = name;
|
||||||
|
this._taskid = id;
|
||||||
|
this._description = description;
|
||||||
|
this._state = Task.State.STOPPED;
|
||||||
|
this._timeSpentInPreviousIterations = 0;
|
||||||
|
this._startDate = 0;
|
||||||
|
this._endDate = 0;
|
||||||
|
this._currentIterationStartTime = 0;
|
||||||
|
this._customTimeSpent = 0;
|
||||||
|
this._onChange = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Possible task states. */
|
||||||
|
Task.State = {
|
||||||
|
STOPPED: "stopped",
|
||||||
|
RUNNING: "running"
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.prototype = {
|
||||||
|
/* Returns the task name. */
|
||||||
|
getName: function() {
|
||||||
|
return this._name;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Returns the task description. */
|
||||||
|
getDescription: function() {
|
||||||
|
if (this._description == "NaN") {
|
||||||
|
this._description = ""
|
||||||
|
}
|
||||||
|
return this._description;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Returns the task state. */
|
||||||
|
getState: function() {
|
||||||
|
return this._state;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Is the task stopped? */
|
||||||
|
isStopped: function() {
|
||||||
|
return this._state == Task.State.STOPPED;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Is the task running? */
|
||||||
|
isRunning: function() {
|
||||||
|
return this._state == Task.State.RUNNING;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the "onChange" event handler. The "onChange" event is fired when the
|
||||||
|
* task is started, stopped, or reset.
|
||||||
|
*/
|
||||||
|
setOnChange: function(onChange) {
|
||||||
|
this._onChange = onChange;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the time spent on the task in the current work iteration. Works
|
||||||
|
* correctly only when the task is running.
|
||||||
|
*/
|
||||||
|
_getCurrentIterationTime: function() {
|
||||||
|
return (new Date).getTime() - this._currentIterationStartTime;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the total time spent on the task. This includes time spent in
|
||||||
|
* the current work iteration if the task is running.
|
||||||
|
*/
|
||||||
|
getTimeSpent: function() {
|
||||||
|
var result = this._timeSpentInPreviousIterations;
|
||||||
|
if (this._state == Task.State.RUNNING) {
|
||||||
|
result += this._getCurrentIterationTime();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Calls the "onChange" event handler if set. */
|
||||||
|
_callOnChange: function() {
|
||||||
|
if (typeof this._onChange == "function") {
|
||||||
|
this._onChange();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Starts a new task work iteration. */
|
||||||
|
start: function() {
|
||||||
|
if (this._state == Task.State.RUNNING) { return };
|
||||||
|
if (this._startDate == 0) {this._startDate = new Date()}
|
||||||
|
this._state = Task.State.RUNNING;
|
||||||
|
this._currentIterationStartTime = (new Date).getTime();
|
||||||
|
this._callOnChange();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Stops the current task work iteration. */
|
||||||
|
stop: function() {
|
||||||
|
if (this._state == Task.State.STOPPED) { return };
|
||||||
|
|
||||||
|
this._state = Task.State.STOPPED;
|
||||||
|
this._timeSpentInPreviousIterations += this._getCurrentIterationTime();
|
||||||
|
this._currentIterationStartTime = 0;
|
||||||
|
this._endDate = new Date();
|
||||||
|
this._callOnChange();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Stops the current task work iteration and resets the time data. */
|
||||||
|
reset: function() {
|
||||||
|
this.stop();
|
||||||
|
this._timeSpentInPreviousIterations = 0;
|
||||||
|
this._callOnChange();
|
||||||
|
},
|
||||||
|
save: function(task){
|
||||||
|
console.log(task)
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
data: {
|
||||||
|
taskname: task._name,
|
||||||
|
taskid: task._taskid,
|
||||||
|
description: task._description,
|
||||||
|
start: task._startDate,
|
||||||
|
end: task._endDate,
|
||||||
|
duration: task._timeSpentInPreviousIterations,
|
||||||
|
},
|
||||||
|
url: "{{ path('app_timer_create') }}",
|
||||||
|
success: function (response) {
|
||||||
|
response=JSON.parse(response);
|
||||||
|
if(response.return=="KO") {
|
||||||
|
$("#dataTable_wrapper").append("<div class='alert alert-danger' style='margin: 5px 0px'>"+response.error+"</div>");
|
||||||
|
}else{
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/* Serializes the task into a string. */
|
||||||
|
serialize: function() {
|
||||||
|
/*
|
||||||
|
* Originally, I wanted to use "toSource" and "eval" for serialization and
|
||||||
|
* deserialization, but "toSource" is not supported by WebKit, so I resorted
|
||||||
|
* to ugly hackery...
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
encodeURIComponent(this._name),
|
||||||
|
this._state,
|
||||||
|
this._timeSpentInPreviousIterations,
|
||||||
|
this._currentIterationStartTime,
|
||||||
|
this._startDate,
|
||||||
|
this._endDate,
|
||||||
|
this._taskid,
|
||||||
|
this._description,
|
||||||
|
].join("&");
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Deserializes the task from a string. */
|
||||||
|
deserialize: function(serialized) {
|
||||||
|
var parts = serialized.split("&");
|
||||||
|
this._name = decodeURIComponent(parts[0]);
|
||||||
|
this._state = parts[1];
|
||||||
|
this._timeSpentInPreviousIterations = parseInt(parts[2]);
|
||||||
|
this._currentIterationStartTime = parseInt(parts[3]);
|
||||||
|
this._startDate = parseInt(parts[4]);
|
||||||
|
this._endDate = parseInt(parts[5]);
|
||||||
|
this._taskid = parseInt(parts[6]);
|
||||||
|
this._description = parseInt(parts[7]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tasks ===== */
|
||||||
|
|
||||||
|
/* The Tasks class represents a list of tasks. */
|
||||||
|
|
||||||
|
/* Creates a new Tasks object. */
|
||||||
|
function Tasks() {
|
||||||
|
this._tasks = [];
|
||||||
|
|
||||||
|
this._onAdd = null;
|
||||||
|
this._onRemove = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tasks.prototype = {
|
||||||
|
/*
|
||||||
|
* Sets the "onAdd" event handler. The "onAdd" event is fired when a task
|
||||||
|
* is added to the list.
|
||||||
|
*/
|
||||||
|
setOnAdd: function(onAdd) {
|
||||||
|
this._onAdd = onAdd;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the "onRemove" event handler. The "onRemove" event is fired when a
|
||||||
|
* task is removed from the list.
|
||||||
|
*/
|
||||||
|
setOnRemove: function(onRemove) {
|
||||||
|
this._onRemove = onRemove;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Returns the length of the task list. */
|
||||||
|
length: function() {
|
||||||
|
return this._tasks.length
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns index-th task in the list, or "undefined" if the index is out of
|
||||||
|
* bounds.
|
||||||
|
*/
|
||||||
|
get: function(index) {
|
||||||
|
return this._tasks[index];
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls the callback function for each task in the list. The function is
|
||||||
|
* called with three parameters - the task, its index and the task list
|
||||||
|
* object. This is modeled after "Array.forEach" in JavaScript 1.6.
|
||||||
|
*/
|
||||||
|
forEach: function(callback) {
|
||||||
|
for (var i = 0; i < this._tasks.length; i++) {
|
||||||
|
callback(this._tasks[i], i, this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Calls the "onAdd" event handler if set. */
|
||||||
|
_callOnAdd: function(task) {
|
||||||
|
if (typeof this._onAdd == "function") {
|
||||||
|
this._onAdd(task);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Adds a new task to the end of the list. */
|
||||||
|
add: function(task) {
|
||||||
|
this._tasks.push(task);
|
||||||
|
this._callOnAdd(task);
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Calls the "onRemove" event handler if set. */
|
||||||
|
_callOnRemove: function(index) {
|
||||||
|
if (typeof this._onRemove == "function") {
|
||||||
|
this._onRemove(index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes index-th task from the list. Does not do anything if the index
|
||||||
|
* is out of bounds.
|
||||||
|
*/
|
||||||
|
remove: function(index) {
|
||||||
|
this._callOnRemove(index);
|
||||||
|
this._tasks.splice(index, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Serializes the list of tasks into a string. */
|
||||||
|
serialize: function() {
|
||||||
|
var serializedTasks = [];
|
||||||
|
this.forEach(function(task) {
|
||||||
|
serializedTasks.push(task.serialize());
|
||||||
|
});
|
||||||
|
return serializedTasks.join("|");
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Deserializes the list of tasks from a string. */
|
||||||
|
deserialize: function(serialized) {
|
||||||
|
/*
|
||||||
|
* Repeatedly use "remove" so the "onRemove" event is triggered. Do the same
|
||||||
|
* with the "add" method below.
|
||||||
|
*/
|
||||||
|
while (this._tasks.length > 0) {
|
||||||
|
this.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var serializedTasks = serialized.split("|");
|
||||||
|
for (var i = 0; i < serializedTasks.length; i++) {
|
||||||
|
var task = new Task(0 ,"", "");
|
||||||
|
task.deserialize(serializedTasks[i]);
|
||||||
|
this.add(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Extensions ===== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pads this string with another string on the left until the resulting string
|
||||||
|
* has specified length. If the padding string has more than one character, the
|
||||||
|
* resulting string may be longer than desired (the padding string is not
|
||||||
|
* truncated and it is only prepended as a whole). Bad API, I know, but it's
|
||||||
|
* good enough for me.
|
||||||
|
*/
|
||||||
|
String.prototype.pad = function(length, padding) {
|
||||||
|
var result = this;
|
||||||
|
while (result.length < length) {
|
||||||
|
result = padding + result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Task List + DOM Storage ===== */
|
||||||
|
|
||||||
|
/* The list of tasks. */
|
||||||
|
var tasks = new Tasks();
|
||||||
|
|
||||||
|
/* The last value of the serialized task list string. */
|
||||||
|
var lastSerializedTasksString;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key under which the serialized task list string is stored in the DOM
|
||||||
|
* Storage.
|
||||||
|
*/
|
||||||
|
var TASKS_DOM_STORAGE_KEY = "timerTasks";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns DOM Storage used by the application, or "null" if the browser does
|
||||||
|
* not support DOM Storage.
|
||||||
|
*/
|
||||||
|
function getStorage() {
|
||||||
|
/*
|
||||||
|
* HTML 5 says that the persistent storage is available in the
|
||||||
|
* "window.localStorage" attribute, however Firefox implements older version
|
||||||
|
* of the proposal, which uses "window.globalStorage" indexed by the domain
|
||||||
|
* name. We deal with this situation here as gracefully as possible (i.e.
|
||||||
|
* without concrete browser detection and with forward compatibility).
|
||||||
|
*
|
||||||
|
* For more information, see:
|
||||||
|
*
|
||||||
|
* http://www.whatwg.org/specs/web-apps/current-work/#storage
|
||||||
|
* https://developer.mozilla.org/En/DOM/Storage
|
||||||
|
*/
|
||||||
|
if (window.localStorage !== undefined) {
|
||||||
|
return window.localStorage;
|
||||||
|
} else if (window.globalStorage !== undefined) {
|
||||||
|
return window.globalStorage[location.hostname];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Saves the task list into a DOM Storage. Also updates the value of the
|
||||||
|
* "lastSerializedTasksString" variable.
|
||||||
|
*/
|
||||||
|
function saveTasks() {
|
||||||
|
var serializedTasksString = tasks.serialize();
|
||||||
|
getStorage()[TASKS_DOM_STORAGE_KEY] = serializedTasksString;
|
||||||
|
lastSerializedTasksString = serializedTasksString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads the serialized task list string from the DOM Storage. Returns
|
||||||
|
* "undefined" if the storage does not contain the string (this happens when
|
||||||
|
* running the application for the first time).
|
||||||
|
*/
|
||||||
|
function loadSerializedTasksString() {
|
||||||
|
var storedValue = getStorage()[TASKS_DOM_STORAGE_KEY];
|
||||||
|
/*
|
||||||
|
* The spec says "null" should be returned when the key is not found, but some
|
||||||
|
* browsers return "undefined" instead. Maybe it was in some earlier version
|
||||||
|
* of the spec (I didn't bother to check).
|
||||||
|
*/
|
||||||
|
if (storedValue !== null && storedValue !== undefined && storedValue.length > 0) {
|
||||||
|
/*
|
||||||
|
* The values retrieved from "globalStorage" use one more level of
|
||||||
|
* indirection.
|
||||||
|
*/
|
||||||
|
return (window.localStorage === undefined) ? storedValue.value : storedValue;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads the task list from the DOM Storage. Also updates the value of the
|
||||||
|
* "lastSerializedTasksString" variable.
|
||||||
|
*/
|
||||||
|
function loadTasks() {
|
||||||
|
var serializedTasksString = loadSerializedTasksString();
|
||||||
|
if (serializedTasksString !== undefined) {
|
||||||
|
tasks.deserialize(serializedTasksString);
|
||||||
|
lastSerializedTasksString = serializedTasksString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Was the task list changed outside of the application? Detects the change
|
||||||
|
* by comparing the current serialized task list string in the DOM Storage
|
||||||
|
* with a kept old value.
|
||||||
|
*/
|
||||||
|
function tasksHaveChangedOutsideApplication() {
|
||||||
|
var serializedTasksString = loadSerializedTasksString();
|
||||||
|
if (serializedTasksString != lastSerializedTasksString) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== View ===== */
|
||||||
|
|
||||||
|
/* Some time constants. */
|
||||||
|
var MILISECONDS_IN_SECOND = 1000;
|
||||||
|
var MILISECONDS_IN_MINUTE = 60 * MILISECONDS_IN_SECOND;
|
||||||
|
var MINUTES_IN_HOUR = 60;
|
||||||
|
|
||||||
|
/* Formats the time in the H:MM format. */
|
||||||
|
function formatTime(time) {
|
||||||
|
var timeInMinutes = time / MILISECONDS_IN_MINUTE;
|
||||||
|
var hours = Math.floor(timeInMinutes / MINUTES_IN_HOUR);
|
||||||
|
var minutes = Math.floor(timeInMinutes - hours * MINUTES_IN_HOUR);
|
||||||
|
return hours + ":" + String(minutes).pad(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Computes the URL of the image in the start/stop link according to the task
|
||||||
|
* state.
|
||||||
|
*/
|
||||||
|
function computeStartStopLinkImageUrl(state) {
|
||||||
|
switch (state) {
|
||||||
|
case Task.State.STOPPED:
|
||||||
|
return "fa-play";
|
||||||
|
case Task.State.RUNNING:
|
||||||
|
return "fa-stop";
|
||||||
|
default:
|
||||||
|
throw "Invalid task state."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the HTML element of the row in the task table corresponding to the
|
||||||
|
* specified task and index.
|
||||||
|
*/
|
||||||
|
function buildTaskRow(task, index) {
|
||||||
|
var result = $("<tr />");
|
||||||
|
|
||||||
|
var startStopLink = $(
|
||||||
|
"<a href='#' class='start-stop-link' title='Start/stop'>"
|
||||||
|
+ "<i class='fa " + computeStartStopLinkImageUrl(task.getState()) + "'></i>"
|
||||||
|
|
||||||
|
);
|
||||||
|
startStopLink.click(function() {
|
||||||
|
switch (task.getState()) {
|
||||||
|
case Task.State.STOPPED:
|
||||||
|
task.start();
|
||||||
|
break;
|
||||||
|
case Task.State.RUNNING:
|
||||||
|
task.stop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw "Invalid task state."
|
||||||
|
}
|
||||||
|
saveTasks();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var resetLink = $(
|
||||||
|
"<a href='#' title='Reset'>"
|
||||||
|
+ "<i class='fa fa-undo'></i>"
|
||||||
|
);
|
||||||
|
resetLink.click(function() {
|
||||||
|
task.reset();
|
||||||
|
saveTasks();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var deleteLink = $(
|
||||||
|
"<a href='#' title='Delete' class='deletetask'>"
|
||||||
|
+ "<i class='fa fa-trash-alt' class='deletetask'></i>"
|
||||||
|
|
||||||
|
);
|
||||||
|
deleteLink.click(function() {
|
||||||
|
if (confirm("Do you really want to delete task \"" + task.getName() + "\"?")) {
|
||||||
|
tasks.remove(index);
|
||||||
|
saveTasks();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var saveLink = $(
|
||||||
|
"<a href='#' title='Save' class='savetask'>"
|
||||||
|
+ "<i class='fa fa-download' class='savetask'></i>"
|
||||||
|
);
|
||||||
|
saveLink.click(function() {
|
||||||
|
tasks.remove(index);
|
||||||
|
saveTasks();
|
||||||
|
task.save(task);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
result
|
||||||
|
.addClass("state-" + task.getState())
|
||||||
|
.append($("<td class='task-name' />").text(task.getName()))
|
||||||
|
.append($("<td class='task-description' />").text(task.getDescription()))
|
||||||
|
.append($("<td class='task-time' />").text(formatTime(task.getTimeSpent())))
|
||||||
|
.append($("<td class='task-actions' />")
|
||||||
|
.append(startStopLink)
|
||||||
|
.append(" ")
|
||||||
|
.append(resetLink)
|
||||||
|
.append(" ")
|
||||||
|
.append(saveLink)
|
||||||
|
.append(" ")
|
||||||
|
.append(deleteLink)
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finds row with the specified index in the task table. */
|
||||||
|
function findRowWithIndex(index) {
|
||||||
|
return $("#task-table").find("tr").slice(1).eq(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the row in the task table corresponding to a task according to
|
||||||
|
* its state.
|
||||||
|
*/
|
||||||
|
function updateTaskRow(row, task) {
|
||||||
|
if (task.isStopped()) {
|
||||||
|
row.removeClass("state-running");
|
||||||
|
row.addClass("state-stopped");
|
||||||
|
} else if (task.isRunning()) {
|
||||||
|
row.removeClass("state-stopped");
|
||||||
|
row.addClass("state-running");
|
||||||
|
}
|
||||||
|
|
||||||
|
row.find(".task-time").text(formatTime(task.getTimeSpent()))
|
||||||
|
|
||||||
|
row.find(".start-stop-link i").removeClass();
|
||||||
|
row.find(".start-stop-link i").addClass("fa "+computeStartStopLinkImageUrl(task.getState()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Initialization ===== */
|
||||||
|
|
||||||
|
/* Initializes event handlers on the task list. */
|
||||||
|
function initializeTasksEventHandlers() {
|
||||||
|
tasks.setOnAdd(function(task) {
|
||||||
|
var row = buildTaskRow(task, tasks.length() - 1);
|
||||||
|
$("#task-table").append(row);
|
||||||
|
task.setOnChange(function() {
|
||||||
|
updateTaskRow(row, task);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tasks.setOnRemove(function(index) {
|
||||||
|
findRowWithIndex(index).remove();
|
||||||
|
if (tasks.length() == 1 ) {
|
||||||
|
$( "#task-table" ).css({"display":"none"});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes GUI event handlers. */
|
||||||
|
function initializeGuiEventHandlers() {
|
||||||
|
$( "#addtimer" ).click(function() {
|
||||||
|
displayTaskAdd();
|
||||||
|
});
|
||||||
|
|
||||||
|
$( "#timer-desc" ).keypress(function( event ) {
|
||||||
|
if ( event.which == 13 ) {
|
||||||
|
event.preventDefault();
|
||||||
|
displayTaskAdd();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
function displayTaskAdd() {
|
||||||
|
$( "#task-table" ).css({"display":"inline"});
|
||||||
|
var taskName = $("#timer-task option:selected").text();
|
||||||
|
var taskId = $("#timer-task option:selected").val();
|
||||||
|
var taskDesc = $("#timer-desc").val();
|
||||||
|
|
||||||
|
var task = new Task(taskId, taskName, taskDesc);
|
||||||
|
tasks.add(task);
|
||||||
|
saveTasks();
|
||||||
|
$("#timer-desc").val("");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Initializes a timer used to update task times and detect changes in the
|
||||||
|
* data stored in the DOM Storage.
|
||||||
|
*/
|
||||||
|
function initializeTimer() {
|
||||||
|
setInterval(function() {
|
||||||
|
tasks.forEach(function(task, index) {
|
||||||
|
updateTaskRow(findRowWithIndex(index), task);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tasksHaveChangedOutsideApplication()) {
|
||||||
|
loadTasks();
|
||||||
|
}
|
||||||
|
}, 10 * MILISECONDS_IN_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes the application. */
|
||||||
|
$(document).ready(function(){
|
||||||
|
try {
|
||||||
|
if (!getStorage()) {
|
||||||
|
alert("Timer requires a browser with DOM Storage support, such as Firefox 3+ or Safari 4+.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert("Timer does not work with file: URLs in Firefox.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTasksEventHandlers();
|
||||||
|
loadTasks();
|
||||||
|
initializeGuiEventHandlers();
|
||||||
|
initializeTimer();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@@ -33,6 +33,7 @@
|
|||||||
"symfony/profiler-pack": "^1.0",
|
"symfony/profiler-pack": "^1.0",
|
||||||
"symfony/security-bundle": "4.4.*",
|
"symfony/security-bundle": "4.4.*",
|
||||||
"symfony/serializer-pack": "*",
|
"symfony/serializer-pack": "*",
|
||||||
|
"symfony/swiftmailer-bundle": "^3.4",
|
||||||
"symfony/translation": "4.4.*",
|
"symfony/translation": "4.4.*",
|
||||||
"symfony/twig-pack": "*",
|
"symfony/twig-pack": "*",
|
||||||
"symfony/validator": "4.4.*",
|
"symfony/validator": "4.4.*",
|
||||||
|
129
src/schedule-2.0/composer.lock
generated
129
src/schedule-2.0/composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "24b27b5f4efd6efcabe5c89e1e1ac51b",
|
"content-hash": "1be2a2e3a398eb23cd3c3e26bc75c090",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "doctrine/annotations",
|
"name": "doctrine/annotations",
|
||||||
@@ -2557,6 +2557,68 @@
|
|||||||
],
|
],
|
||||||
"time": "2019-12-27T08:57:19+00:00"
|
"time": "2019-12-27T08:57:19+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "swiftmailer/swiftmailer",
|
||||||
|
"version": "v6.2.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/swiftmailer/swiftmailer.git",
|
||||||
|
"reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/149cfdf118b169f7840bbe3ef0d4bc795d1780c9",
|
||||||
|
"reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"egulias/email-validator": "~2.0",
|
||||||
|
"php": ">=7.0.0",
|
||||||
|
"symfony/polyfill-iconv": "^1.0",
|
||||||
|
"symfony/polyfill-intl-idn": "^1.10",
|
||||||
|
"symfony/polyfill-mbstring": "^1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mockery/mockery": "~0.9.1",
|
||||||
|
"symfony/phpunit-bridge": "^3.4.19|^4.1.8"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "Needed to support internationalized email addresses",
|
||||||
|
"true/punycode": "Needed to support internationalized email addresses, if ext-intl is not installed"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "6.2-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"lib/swift_required.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Chris Corbyn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Swiftmailer, free feature-rich PHP mailer",
|
||||||
|
"homepage": "https://swiftmailer.symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"email",
|
||||||
|
"mail",
|
||||||
|
"mailer"
|
||||||
|
],
|
||||||
|
"time": "2019-11-12T09:31:26+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/apache-pack",
|
"name": "symfony/apache-pack",
|
||||||
"version": "v1.0.1",
|
"version": "v1.0.1",
|
||||||
@@ -5811,6 +5873,71 @@
|
|||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"time": "2020-01-04T13:00:46+00:00"
|
"time": "2020-01-04T13:00:46+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/swiftmailer-bundle",
|
||||||
|
"version": "v3.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/swiftmailer-bundle.git",
|
||||||
|
"reference": "553d2474288349faed873da8ab7c1551a00d26ae"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/swiftmailer-bundle/zipball/553d2474288349faed873da8ab7c1551a00d26ae",
|
||||||
|
"reference": "553d2474288349faed873da8ab7c1551a00d26ae",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1",
|
||||||
|
"swiftmailer/swiftmailer": "^6.1.3",
|
||||||
|
"symfony/config": "^4.3.8|^5.0",
|
||||||
|
"symfony/dependency-injection": "^4.3.8|^5.0",
|
||||||
|
"symfony/http-kernel": "^4.3.8|^5.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"twig/twig": "<1.41|<2.10"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/console": "^4.3.8|^5.0",
|
||||||
|
"symfony/framework-bundle": "^4.3.8|^5.0",
|
||||||
|
"symfony/phpunit-bridge": "^4.3.8|^5.0",
|
||||||
|
"symfony/yaml": "^4.3.8|^5.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"psr/log": "Allows logging"
|
||||||
|
},
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.4-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Bundle\\SwiftmailerBundle\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "http://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony SwiftmailerBundle",
|
||||||
|
"homepage": "http://symfony.com",
|
||||||
|
"time": "2019-11-14T16:18:31+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/templating",
|
"name": "symfony/templating",
|
||||||
"version": "v4.4.5",
|
"version": "v4.4.5",
|
||||||
|
@@ -19,4 +19,5 @@ return [
|
|||||||
Tetranz\Select2EntityBundle\TetranzSelect2EntityBundle::class => ['all' => true],
|
Tetranz\Select2EntityBundle\TetranzSelect2EntityBundle::class => ['all' => true],
|
||||||
Oneup\UploaderBundle\OneupUploaderBundle::class => ['all' => true],
|
Oneup\UploaderBundle\OneupUploaderBundle::class => ['all' => true],
|
||||||
Knp\Bundle\SnappyBundle\KnpSnappyBundle::class => ['all' => true],
|
Knp\Bundle\SnappyBundle\KnpSnappyBundle::class => ['all' => true],
|
||||||
|
Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
5
src/schedule-2.0/config/packages/swiftmailer.yaml
Normal file
5
src/schedule-2.0/config/packages/swiftmailer.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
swiftmailer:
|
||||||
|
url: '%env(MAILER_URL)%'
|
||||||
|
spool:
|
||||||
|
type: file
|
||||||
|
path: '%kernel.project_dir%/var/spoolmail'
|
5
src/schedule-2.0/config/packages/test/swiftmailer.yaml
Normal file
5
src/schedule-2.0/config/packages/test/swiftmailer.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
swiftmailer:
|
||||||
|
url: '%env(MAILER_URL)%'
|
||||||
|
spool:
|
||||||
|
type: file
|
||||||
|
path: '%kernel.project_dir%/var/spoolmail'
|
@@ -343,6 +343,52 @@ app_validationholiday_activeholiday:
|
|||||||
path: /validator/validateholiday/activeholiday
|
path: /validator/validateholiday/activeholiday
|
||||||
defaults: { _controller: App\Controller\ValidationController:activeholiday }
|
defaults: { _controller: App\Controller\ValidationController:activeholiday }
|
||||||
|
|
||||||
|
#== Validationtimer ====================================================================================================
|
||||||
|
app_validationtimer:
|
||||||
|
path: /validator/validationtimer
|
||||||
|
defaults: { _controller: App\Controller\ValidationController:validationtimer }
|
||||||
|
|
||||||
|
app_validationtimer_validate:
|
||||||
|
path: /validator/validatetimer
|
||||||
|
defaults: { _controller: App\Controller\ValidationController:validatetimer }
|
||||||
|
|
||||||
|
app_validationtimer_devalidate:
|
||||||
|
path: /validator/devalidatetimer
|
||||||
|
defaults: { _controller: App\Controller\ValidationController:devalidatetimer }
|
||||||
|
|
||||||
|
app_validationtimer_activetimer:
|
||||||
|
path: /validator/validateholiday/activetimer
|
||||||
|
defaults: { _controller: App\Controller\ValidationController:activetimer }
|
||||||
|
|
||||||
|
#== Timer ====================================================================================================
|
||||||
|
app_timer:
|
||||||
|
path: /timer
|
||||||
|
defaults: { _controller: App\Controller\TimerController:list }
|
||||||
|
|
||||||
|
app_timer_view:
|
||||||
|
path: /timer/event
|
||||||
|
defaults: { _controller: App\Controller\TimerController:view }
|
||||||
|
|
||||||
|
app_timer_load:
|
||||||
|
path: /timer/event/load
|
||||||
|
defaults: { _controller: App\Controller\TimerController:load }
|
||||||
|
|
||||||
|
app_timer_submit:
|
||||||
|
path: /timer/submit
|
||||||
|
defaults: { _controller: App\Controller\TimerController:submit }
|
||||||
|
|
||||||
|
app_timer_create:
|
||||||
|
path: /timer/create
|
||||||
|
defaults: { _controller: App\Controller\TimerController:create }
|
||||||
|
|
||||||
|
app_timer_update:
|
||||||
|
path: /timer/update/{id}
|
||||||
|
defaults: { _controller: App\Controller\TimerController:update }
|
||||||
|
|
||||||
|
app_timer_delete:
|
||||||
|
path: /timer/delete/{id}
|
||||||
|
defaults: { _controller: App\Controller\TimerController:delete }
|
||||||
|
|
||||||
|
|
||||||
#== Customer ======================================================================================================
|
#== Customer ======================================================================================================
|
||||||
app_customer_report:
|
app_customer_report:
|
||||||
@@ -353,6 +399,24 @@ app_customer_planning:
|
|||||||
path: /customer/planning/{key}
|
path: /customer/planning/{key}
|
||||||
defaults: { _controller: App\Controller\ReportController:planning, access: 'customer' }
|
defaults: { _controller: App\Controller\ReportController:planning, access: 'customer' }
|
||||||
|
|
||||||
|
#== Export ======================================================================================================
|
||||||
|
app_export_view:
|
||||||
|
path: /export
|
||||||
|
defaults: { _controller: App\Controller\ExportController:view }
|
||||||
|
|
||||||
|
app_export_penalty_additional:
|
||||||
|
path: /export/export_penalty_additional
|
||||||
|
defaults: { _controller: App\Controller\ExportController:export_penalty_additional }
|
||||||
|
|
||||||
|
export_project_weekly:
|
||||||
|
path: /export/export_project_weekly
|
||||||
|
defaults: { _controller: App\Controller\ExportController:export_project_weekly }
|
||||||
|
|
||||||
|
export_full_worked_days:
|
||||||
|
path: /export/export_full_worked_days
|
||||||
|
defaults: { _controller: App\Controller\ExportController:export_full_worked_days }
|
||||||
|
|
||||||
|
|
||||||
#== API ===========================================================================================================
|
#== API ===========================================================================================================
|
||||||
app_api:
|
app_api:
|
||||||
path: /api/{key}
|
path: /api/{key}
|
||||||
|
@@ -9,6 +9,9 @@ parameters:
|
|||||||
appName: '%env(resolve:APP_NAME)%'
|
appName: '%env(resolve:APP_NAME)%'
|
||||||
appEnv: '%env(resolve:APP_ENV)%'
|
appEnv: '%env(resolve:APP_ENV)%'
|
||||||
appCron: '%env(resolve:APP_CRON)%'
|
appCron: '%env(resolve:APP_CRON)%'
|
||||||
|
appMailmethod: '%env(resolve:MAILER_METHOD)%'
|
||||||
|
appMailnoreply: '%env(resolve:MAILER_NOREPLY)%'
|
||||||
|
appMailnotif: '%env(resolve:MAILER_DEFAULT_NOTIF)%'
|
||||||
casHost: '%env(resolve:CAS_HOST)%'
|
casHost: '%env(resolve:CAS_HOST)%'
|
||||||
casPort: '%env(resolve:CAS_PORT)%'
|
casPort: '%env(resolve:CAS_PORT)%'
|
||||||
casPath: '%env(resolve:CAS_PATH)%'
|
casPath: '%env(resolve:CAS_PATH)%'
|
||||||
@@ -16,6 +19,8 @@ parameters:
|
|||||||
casEmail: '%env(resolve:CAS_EMAIL)%'
|
casEmail: '%env(resolve:CAS_EMAIL)%'
|
||||||
casLastname: '%env(resolve:CAS_LASTNAME)%'
|
casLastname: '%env(resolve:CAS_LASTNAME)%'
|
||||||
casFirstname: '%env(resolve:CAS_FIRSTNAME)%'
|
casFirstname: '%env(resolve:CAS_FIRSTNAME)%'
|
||||||
|
officeHourStart: '%env(resolve:OFFICE_HOUR_START)%'
|
||||||
|
officeHourEnd: '%env(resolve:OFFICE_HOUR_END)%'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# default configuration for services in *this* file
|
# default configuration for services in *this* file
|
||||||
@@ -59,3 +64,12 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: kernel.event_listener, event: kernel.request, method: onDomainParse }
|
- { name: kernel.event_listener, event: kernel.request, method: onDomainParse }
|
||||||
|
|
||||||
|
app.sendmail.transport:
|
||||||
|
class: Swift_SendmailTransport
|
||||||
|
public: true
|
||||||
|
arguments: ['/usr/sbin/sendmail -t']
|
||||||
|
|
||||||
|
app.mail.service:
|
||||||
|
public: true
|
||||||
|
class: App\Service\mailService
|
||||||
|
arguments: ["@mailer", "@twig"]
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
if [ ! -f /var/www/html/schedule/.key ]; then
|
if [ ! -f /var/www/html/schedule/.key ]; then
|
||||||
cat /dev/urandom | tr -dc '_A-Za-z0-9' | head -c${1:-32} > /var/www/html/schedule/.key
|
openssl rand -hex 32 > /var/www/html/schedule/.key
|
||||||
fi
|
fi
|
||||||
|
87
src/schedule-2.0/src/Command/SendMailCommand.php
Normal file
87
src/schedule-2.0/src/Command/SendMailCommand.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\ArrayInput;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
|
||||||
|
|
||||||
|
class SendMailCommand extends Command
|
||||||
|
{
|
||||||
|
private $container;
|
||||||
|
private $em;
|
||||||
|
private $output;
|
||||||
|
private $filesystem;
|
||||||
|
private $rootlog;
|
||||||
|
|
||||||
|
public function __construct(ContainerInterface $container,EntityManagerInterface $em)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->container = $container;
|
||||||
|
$this->em = $em;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('app:sendMail')
|
||||||
|
->setDescription('Envoi des mails')
|
||||||
|
->setHelp('Envoi des mails')
|
||||||
|
->addArgument('message-limit', InputArgument::OPTIONAL, 'limit message Mail')
|
||||||
|
->addArgument('env', InputArgument::OPTIONAL, 'env Mail')
|
||||||
|
->addArgument('cronid', InputArgument::OPTIONAL, 'ID Cron Job')
|
||||||
|
->addArgument('lastchance', InputArgument::OPTIONAL, 'Lastchance to run the cron')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$this->output = $output;
|
||||||
|
$this->filesystem = new Filesystem();
|
||||||
|
$this->rootlog = $this->container->get('kernel')->getRootDir()."/../var/logs/";
|
||||||
|
|
||||||
|
$this->writelnred('');
|
||||||
|
$this->writelnred('== app:sendMail');
|
||||||
|
$this->writelnred('==========================================================================================================');
|
||||||
|
|
||||||
|
$appMailmethod=$this->container->getParameter("appMailmethod");
|
||||||
|
|
||||||
|
$command = $this->getApplication()->find("swiftmailer:spool:send");
|
||||||
|
$tbparameter["--message-limit"]=100;
|
||||||
|
$tbparameter["--env"]="prod";
|
||||||
|
$tbparameter["--time-limit"]=5;
|
||||||
|
if($appMailmethod=="sendmail") $tbparameter["--transport"]="app.sendmail.transport";
|
||||||
|
|
||||||
|
|
||||||
|
$parameter = new ArrayInput($tbparameter);
|
||||||
|
try{
|
||||||
|
$returnCode = $command->run($parameter, $output);
|
||||||
|
}
|
||||||
|
catch(\Exception $e) {
|
||||||
|
$this->writeln("");
|
||||||
|
$this->writelnred("Impossible d'envoyer des mails");
|
||||||
|
$this->writeln("");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$this->writeln("");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function writelnred($string) {
|
||||||
|
$this->output->writeln('<fg=red>'.$string.'</>');
|
||||||
|
$this->filesystem->appendToFile($this->rootlog.'cron.log', $string."\n");
|
||||||
|
}
|
||||||
|
private function writeln($string) {
|
||||||
|
$this->output->writeln($string);
|
||||||
|
$this->filesystem->appendToFile($this->rootlog.'cron.log', $string."\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -136,8 +136,15 @@ class BreakdayController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
|
@@ -77,7 +77,6 @@ class CropController extends AbstractController
|
|||||||
|
|
||||||
// Cacul de la largeur
|
// Cacul de la largeur
|
||||||
protected function getWidth($image) {
|
protected function getWidth($image) {
|
||||||
dump($image);
|
|
||||||
$size = getimagesize($image);
|
$size = getimagesize($image);
|
||||||
$width = $size[0];
|
$width = $size[0];
|
||||||
return $width;
|
return $width;
|
||||||
|
@@ -146,8 +146,15 @@ class CustomerController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
|
@@ -17,6 +17,11 @@ class EventController extends AbstractController
|
|||||||
private $route = "app_event";
|
private $route = "app_event";
|
||||||
private $render = "Event/";
|
private $render = "Event/";
|
||||||
private $entity = "App:Event";
|
private $entity = "App:Event";
|
||||||
|
private $notificator;
|
||||||
|
|
||||||
|
public function __construct(\App\Service\notificationService $notificator) {
|
||||||
|
$this->notificator = $notificator;
|
||||||
|
}
|
||||||
|
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
@@ -40,12 +45,26 @@ class EventController extends AbstractController
|
|||||||
|
|
||||||
// Evenements
|
// Evenements
|
||||||
$iduser=$this->get("session")->get("iduser");
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
$user=$em->getRepository("App:User")->find($iduser);
|
||||||
if($iduser=="all")
|
if($iduser=="all")
|
||||||
$events=$em->getRepository("App:Event")->findAll();
|
$events=$em->getRepository("App:Event")->findAll();
|
||||||
else {
|
else {
|
||||||
$iduser=$this->get("session")->get("iduser");
|
$users= [];
|
||||||
$user=$em->getRepository("App:User")->find($iduser);
|
$fictivuser = $em->getRepository("App:User")->findOneBy([
|
||||||
$events=$em->getRepository("App:Event")->findBy(["user"=>$user]);
|
'service' => $user->getService(),
|
||||||
|
'fictive' => true,
|
||||||
|
]);
|
||||||
|
array_push($users,$fictivuser);
|
||||||
|
$selectedusers = $this->get("session")->get("selectedusers");
|
||||||
|
if (isset($selectedusers) && sizeof($selectedusers)>1){
|
||||||
|
foreach($selectedusers as $user) {
|
||||||
|
array_push($users,$em->getRepository("App:User")->find($user));
|
||||||
|
}
|
||||||
|
$events=$em->getRepository("App:Event")->findBy(["user"=>$users]);
|
||||||
|
}else{
|
||||||
|
array_push($users,$em->getRepository("App:User")->find($iduser));
|
||||||
|
$events=$em->getRepository("App:Event")->findBy(["user"=>$users]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($events as $event) {
|
foreach($events as $event) {
|
||||||
@@ -94,6 +113,7 @@ class EventController extends AbstractController
|
|||||||
$am = ($request->request->get('am')=="true");
|
$am = ($request->request->get('am')=="true");
|
||||||
$ap = ($request->request->get('ap')=="true");
|
$ap = ($request->request->get('ap')=="true");
|
||||||
$astreinte = ($request->request->get('astreinte')=="true");
|
$astreinte = ($request->request->get('astreinte')=="true");
|
||||||
|
$externaltrip = ($request->request->get('externaltrip')=="true");
|
||||||
$description = $request->request->get('description');
|
$description = $request->request->get('description');
|
||||||
|
|
||||||
$user = $em->getRepository("App:User")->find($iduser);
|
$user = $em->getRepository("App:User")->find($iduser);
|
||||||
@@ -237,6 +257,7 @@ class EventController extends AbstractController
|
|||||||
$event->setEnd($dateend);
|
$event->setEnd($dateend);
|
||||||
$event->setDuration($duration);
|
$event->setDuration($duration);
|
||||||
$event->setAllday($allday);
|
$event->setAllday($allday);
|
||||||
|
$event->setExternalTrip($externaltrip);
|
||||||
$event->setDescription($description);
|
$event->setDescription($description);
|
||||||
$event->setUser($user);
|
$event->setUser($user);
|
||||||
$event->setTask($task);
|
$event->setTask($task);
|
||||||
@@ -245,6 +266,12 @@ class EventController extends AbstractController
|
|||||||
|
|
||||||
$em->persist($event);
|
$em->persist($event);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
if($task->getNature()->getIsvacation()){
|
||||||
|
$idevent=$event->getId();
|
||||||
|
$valid_url = $this->generateUrl('app_validationholiday');
|
||||||
|
$this->notificator->sendNotifAttenteValid("Congés en attente de validation", $iduser, $idevent, $valid_url);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$output=$this->formatEvent($event);
|
$output=$this->formatEvent($event);
|
||||||
}
|
}
|
||||||
@@ -260,7 +287,10 @@ class EventController extends AbstractController
|
|||||||
$idevent = str_replace("A","",$request->request->get('idevent'));
|
$idevent = str_replace("A","",$request->request->get('idevent'));
|
||||||
$iduser = $request->request->get('iduser');
|
$iduser = $request->request->get('iduser');
|
||||||
$idtask = $request->request->get('idtask');
|
$idtask = $request->request->get('idtask');
|
||||||
|
$am = ($request->request->get('am')=="true");
|
||||||
|
$ap = ($request->request->get('ap')=="true");
|
||||||
$fgastreinte = ($request->request->get('fgastreinte')=="true");
|
$fgastreinte = ($request->request->get('fgastreinte')=="true");
|
||||||
|
$externaltrip = ($request->request->get('externaltrip')=="true");
|
||||||
$description = $request->request->get('description');
|
$description = $request->request->get('description');
|
||||||
|
|
||||||
$user = $em->getRepository("App:User")->find($iduser);
|
$user = $em->getRepository("App:User")->find($iduser);
|
||||||
@@ -316,8 +346,74 @@ class EventController extends AbstractController
|
|||||||
return new Response(json_encode($output));
|
return new Response(json_encode($output));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$datestart=$event->getStart();
|
||||||
|
$dateend =$event->getEnd();
|
||||||
|
$duration=$dateend->diff($datestart)->d;
|
||||||
|
if($am&&$ap) {
|
||||||
|
if ($duration >= 1) {
|
||||||
|
$dateend->SetTime(0,0,-1);
|
||||||
|
}
|
||||||
|
$datestart->SetTime(0,0,0);
|
||||||
|
$dateend->add(new \DateInterval('P1D'));
|
||||||
|
$dateend->SetTime(0,0,0);
|
||||||
|
$duration=$dateend->diff($datestart)->d;
|
||||||
|
$allday=true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$duration=$dateend->diff($datestart)->d;
|
||||||
|
if ($duration == 1) {
|
||||||
|
$dateend->SetTime(0,0,-1);
|
||||||
|
}
|
||||||
|
$duration=0.5;
|
||||||
|
$allday=false;
|
||||||
|
if($am) {
|
||||||
|
$datestart->SetTime(9,0,0);
|
||||||
|
$dateend->SetTime(12,0,0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$datestart->SetTime(13,0,0);
|
||||||
|
$dateend->SetTime(17,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// On regarde si une tache ne commence pas pendant une autre intervention ou qui se termine pendant une autre intervention ou qui a une intervention compris dans ses dates
|
||||||
|
$events = $em->createQueryBuilder('event')
|
||||||
|
->select('event')
|
||||||
|
->from('App:Event','event')
|
||||||
|
->Where('event.user=:user AND event.start<=:start AND event.end >:start')
|
||||||
|
->orWhere('event.user=:user AND event.start<:end AND event.end >=:end')
|
||||||
|
->orWhere('event.user=:user AND event.start>:start AND event.end <:end')
|
||||||
|
->setParameter('user',$iduser)
|
||||||
|
->setParameter('start',$datestart)
|
||||||
|
->setParameter('end',$dateend)
|
||||||
|
->getQuery()->getResult();
|
||||||
|
if($events) {
|
||||||
|
$tbevent=[];
|
||||||
|
foreach($events as $ev) {
|
||||||
|
if ($event->getId() != $ev->getId()) {
|
||||||
|
$tmp=[
|
||||||
|
"id" => $ev->getId(),
|
||||||
|
"task" => $ev->getTask()->getName(),
|
||||||
|
"start" => $ev->getStart(),
|
||||||
|
"end" => $ev->getEnd(),
|
||||||
|
];
|
||||||
|
array_push($tbevent,$tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sizeof($tbevent)>0) {
|
||||||
|
$output=["return"=>"KO","error"=>"Cet intervant a déjà une tache à cette date","start"=>$datestart,"end"=>$dateend,"events"=>$tbevent];
|
||||||
|
return new Response(json_encode($output));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Modification de l'évenement
|
// Modification de l'évenement
|
||||||
|
$event->setStart($datestart);
|
||||||
|
$event->setEnd($dateend);
|
||||||
$event->setDescription($description);
|
$event->setDescription($description);
|
||||||
|
$event->setDuration($duration);
|
||||||
|
$event->setAllday($allday);
|
||||||
|
$event->setExternalTrip($externaltrip);
|
||||||
$event->setUser($user);
|
$event->setUser($user);
|
||||||
$event->setTask($task);
|
$event->setTask($task);
|
||||||
|
|
||||||
@@ -326,7 +422,6 @@ class EventController extends AbstractController
|
|||||||
|
|
||||||
$output=$this->formatEvent($event);
|
$output=$this->formatEvent($event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(json_encode($output));
|
return new Response(json_encode($output));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,12 +495,16 @@ class EventController extends AbstractController
|
|||||||
"borderColor" => $event->getTask()->getColor(),
|
"borderColor" => $event->getTask()->getColor(),
|
||||||
"textColor" => "#ffffff",
|
"textColor" => "#ffffff",
|
||||||
"allDay" => $event->getAllday(),
|
"allDay" => $event->getAllday(),
|
||||||
|
"holiday" => $event->getTask()->getNature()->getIsvacation(),
|
||||||
|
"externaltrip" => ($event instanceof Penalty?false:$event->getExternalTrip()),
|
||||||
"editable" => $editable,
|
"editable" => $editable,
|
||||||
|
"fictivuser" => $event->getUser()->getFictive(),
|
||||||
"durationEditable" => false,
|
"durationEditable" => false,
|
||||||
"extendedProps" => [
|
"extendedProps" => [
|
||||||
"fulldescription" => ($event instanceof Penalty?"ASTREINTE\n":"").strtoupper($event->getTask()->getDisplayname())."\n\n".$event->getDescription(),
|
"fulldescription" => ($event instanceof Penalty?"ASTREINTE\n":"").strtoupper($event->getTask()->getDisplayname())."\n\n".$event->getDescription(),
|
||||||
"description" => $event->getDescription(),
|
"description" => $event->getDescription(),
|
||||||
"userid" => $event->getUser()->getId(),
|
"userid" => $event->getUser()->getId(),
|
||||||
|
"username" => $event->getUser()->getUsername(),
|
||||||
"taskid" => $event->getTask()->getId(),
|
"taskid" => $event->getTask()->getId(),
|
||||||
"avatar" => "/".$this->getParameter("appAlias")."/uploads/avatar/".$event->getUser()->getAvatar(),
|
"avatar" => "/".$this->getParameter("appAlias")."/uploads/avatar/".$event->getUser()->getAvatar(),
|
||||||
"estimate" => $event->getTask()->getDuration($event->getEnd())." / ".$event->getTask()->getQuantity(),
|
"estimate" => $event->getTask()->getDuration($event->getEnd())." / ".$event->getTask()->getQuantity(),
|
||||||
@@ -429,12 +528,15 @@ class EventController extends AbstractController
|
|||||||
"borderColor" => "#cdcdcd",
|
"borderColor" => "#cdcdcd",
|
||||||
"textColor" => "#ffffff",
|
"textColor" => "#ffffff",
|
||||||
"allDay" => true,
|
"allDay" => true,
|
||||||
|
"externaltrip" => false,
|
||||||
|
"holiday" => false,
|
||||||
"editable" => false,
|
"editable" => false,
|
||||||
"durationEditable" => false,
|
"durationEditable" => false,
|
||||||
"extendedProps" => [
|
"extendedProps" => [
|
||||||
"fulldescription" => "Jour Férié",
|
"fulldescription" => "Jour Férié",
|
||||||
"description" => "Jour Férié",
|
"description" => "Jour Férié",
|
||||||
"userid" => null,
|
"userid" => null,
|
||||||
|
"username" => "",
|
||||||
"taskid" => null,
|
"taskid" => null,
|
||||||
"avatar" => "/".$this->getParameter("appAlias")."/uploads/avatar/".$this->getUser()->getAvatar(),
|
"avatar" => "/".$this->getParameter("appAlias")."/uploads/avatar/".$this->getUser()->getAvatar(),
|
||||||
"estimate" => "",
|
"estimate" => "",
|
||||||
|
435
src/schedule-2.0/src/Controller/ExportController.php
Normal file
435
src/schedule-2.0/src/Controller/ExportController.php
Normal file
@@ -0,0 +1,435 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
|
||||||
|
class ExportController extends AbstractController
|
||||||
|
{
|
||||||
|
private $data = "export";
|
||||||
|
private $route = "app_exportèview";
|
||||||
|
private $render = "Export/";
|
||||||
|
private $entity = "App:Export";
|
||||||
|
|
||||||
|
|
||||||
|
public function view(Request $request)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$iduser = $this->get("session")->get("iduser");
|
||||||
|
$user = $em->getRepository("App:User")->find($iduser);
|
||||||
|
|
||||||
|
return $this->render($this->render.'list.html.twig',[
|
||||||
|
"useheader" => true,
|
||||||
|
"usesidebar" => true,
|
||||||
|
"user" => $user,
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function export_full_worked_days(Request $request,$access=null): Response
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$nbmonth=$this->get("session")->get("nbmonth");
|
||||||
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
|
||||||
|
if($iduser=="all") {
|
||||||
|
$users=$em->getRepository("App:User")->findAll();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$users=$em->getRepository("App:User")->findBy(["id"=>$iduser]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tbevents=[];
|
||||||
|
foreach($users as $user) {
|
||||||
|
if(in_array("ROLE_USER",$user->getRoles())) {
|
||||||
|
// Filtre par Service
|
||||||
|
if($this->get('session')->get('idservice')!="all") {
|
||||||
|
if($user->getService()->getId()!=$this->get('session')->get('idservice'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmp=[
|
||||||
|
"id" => $user->getId(),
|
||||||
|
"user" => $user,
|
||||||
|
"events" => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
// On formate le tableau de jour
|
||||||
|
$start=new \Datetime('first day of this month');
|
||||||
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->modify('previous monday');
|
||||||
|
$start->setTime(0,0,0);
|
||||||
|
$end = new \Datetime('first day of this month');
|
||||||
|
$end->add(new \DateInterval('P1M'));
|
||||||
|
$end->modify('next monday');
|
||||||
|
$end->setTime(23,59,0);
|
||||||
|
while($start<$end) {
|
||||||
|
$idday=$start->format("Ymd");
|
||||||
|
$idmonth=$start->format("Ym");
|
||||||
|
|
||||||
|
$tmp["events"][$idday] = [
|
||||||
|
"date"=>clone $start,
|
||||||
|
"allday"=>false,
|
||||||
|
"descriptionday"=>"",
|
||||||
|
"am"=>false,
|
||||||
|
"descriptionam"=>"",
|
||||||
|
"ap"=>false,
|
||||||
|
"descriptionap"=>"",
|
||||||
|
"astreinte"=>false,
|
||||||
|
"descriptionastreinte"=>"",
|
||||||
|
];
|
||||||
|
|
||||||
|
$start->add(new \DateInterval('P1D'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// On formate le tableau des event
|
||||||
|
$start=new \Datetime('first day of this month');
|
||||||
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->modify('previous monday');
|
||||||
|
$start->setTime(0,0,0);
|
||||||
|
$end = new \Datetime('first day of this month');
|
||||||
|
$end->add(new \DateInterval('P1M'));
|
||||||
|
$end->modify('next monday');
|
||||||
|
$end->setTime(23,59,0);
|
||||||
|
|
||||||
|
$events = $em
|
||||||
|
->createQueryBuilder('event')
|
||||||
|
->select('event')
|
||||||
|
->from('App:Event','event')
|
||||||
|
->Where('event.user=:user AND event.start>=:start AND event.end <:end')
|
||||||
|
->setParameter('user',$user->getId())
|
||||||
|
->setParameter('start',$start)
|
||||||
|
->setParameter('end',$end)
|
||||||
|
->getQuery()->getResult();
|
||||||
|
foreach($events as $event) {
|
||||||
|
$idproject=$event->getTask()->getProject()->getId();
|
||||||
|
|
||||||
|
// Filtre par project
|
||||||
|
if($this->get('session')->get('idproject')!="all") {
|
||||||
|
if($idproject!=$this->get('session')->get('idproject'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$isvac= $event->getTask()->getNature()->getIsvacation();
|
||||||
|
if($isvac) {continue;}
|
||||||
|
$st=clone $event->getStart();
|
||||||
|
while($st<$event->getEnd()) {
|
||||||
|
|
||||||
|
$idday=$st->format("Ymd");
|
||||||
|
if($event->getAllday()) {
|
||||||
|
$tmp["events"][$idday]["allday"]=true;
|
||||||
|
$tmp["events"][$idday]["descriptionday"]=strtoupper($event->getTask()->getDisplayname());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Matin ou après-midi ?
|
||||||
|
$time=$event->getStart()->format("H");
|
||||||
|
if($time==9) {
|
||||||
|
$tmp["events"][$idday]["am"]=true;
|
||||||
|
if(isset($tmp["events"][$idday]["ap"]) && $tmp["events"][$idday]["ap"]==true){$tmp["events"][$idday]["allday"]=true;}
|
||||||
|
$tmp["events"][$idday]["descriptionam"]=strtoupper($event->getTask()->getDisplayname());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$tmp["events"][$idday]["ap"]=true;
|
||||||
|
if(isset($tmp["events"][$idday]["am"]) && $tmp["events"][$idday]["am"] ==true){$tmp["events"][$idday]["allday"]=true;}
|
||||||
|
$tmp["events"][$idday]["descriptionap"]=strtoupper($event->getTask()->getDisplayname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$st->add(new \DateInterval('P1D'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// On formate le tableau des astreintes
|
||||||
|
$start=new \Datetime('first day of this month');
|
||||||
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->modify('previous monday');
|
||||||
|
$start->setTime(0,0,0);
|
||||||
|
$end = new \Datetime('first day of this month');
|
||||||
|
$end->add(new \DateInterval('P1M'));
|
||||||
|
$end->modify('next monday');
|
||||||
|
$end->setTime(23,59,0);
|
||||||
|
|
||||||
|
$penaltys = $em
|
||||||
|
->createQueryBuilder('penalty')
|
||||||
|
->select('penalty')
|
||||||
|
->from('App:Penalty','penalty')
|
||||||
|
->Where('penalty.user=:user AND penalty.start>=:start AND penalty.end <:end')
|
||||||
|
->setParameter('user',$user->getId())
|
||||||
|
->setParameter('start',$start)
|
||||||
|
->setParameter('end',$end)
|
||||||
|
->getQuery()->getResult();
|
||||||
|
foreach($penaltys as $penalty) {
|
||||||
|
$idproject=$penalty->getTask()->getProject()->getId();
|
||||||
|
|
||||||
|
// Filtre par project
|
||||||
|
if($this->get('session')->get('idproject')!="all") {
|
||||||
|
if($idproject!=$this->get('session')->get('idproject'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$st=clone $penalty->getStart();
|
||||||
|
while($st<$penalty->getEnd()) {
|
||||||
|
$idday=$st->format("Ymd");
|
||||||
|
if($penalty->getAllday()) {
|
||||||
|
$tmp["events"][$idday]["astreinte"]=true;
|
||||||
|
$tmp["events"][$idday]["descriptionastreinte"]=strtoupper($penalty->getTask()->getDisplayname());
|
||||||
|
}
|
||||||
|
|
||||||
|
$st->add(new \DateInterval('P1D'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array_push($tbevents,$tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$csv = $this->renderView('Export/export_full_worked_days.csv.twig', ["users" => $tbevents]);
|
||||||
|
$response = new Response($csv);
|
||||||
|
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
|
||||||
|
$response->headers->set('Content-Disposition', 'attachment; filename="export_full_worked_days.csv"');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function export_penalty_additional(Request $request,$access=null): Response
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$iduser = $this->get("session")->get("iduser");
|
||||||
|
$timers = $em->getRepository("App:Timer")->findBy(["user"=>$iduser]);
|
||||||
|
$tbtimers = [];
|
||||||
|
foreach ($timers as $timer) {
|
||||||
|
$isactive = $timer->getActivePenalty();
|
||||||
|
$isadditional = $timer->getAdditionalHour();
|
||||||
|
if ($isactive || $isadditional) {
|
||||||
|
$tbtimer["id"] = $timer->getId();
|
||||||
|
$tbtimer["taskname"] = $timer->getTask()->getDisplayname();
|
||||||
|
$tbtimer["user"] = $timer->getUser()->getUsername();
|
||||||
|
$tbtimer["start"] = $timer->getStart()->format("Y-m-d H:i");
|
||||||
|
$tbtimer["end"] = $timer->getEnd()->format("Y-m-d H:i");
|
||||||
|
$tbtimer["duration"] = $timer->getDuration();
|
||||||
|
$tbtimer["activepenalty"] = $timer->getActivePenalty();
|
||||||
|
$tbtimer["additionalhour"] = $timer->getAdditionalHour();
|
||||||
|
$tbtimer["description"] = $timer->getDescription();
|
||||||
|
array_push($tbtimers, $tbtimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$csv = $this->renderView('Export/export_penalty_additional.csv.twig', ["timers" => $tbtimers]);
|
||||||
|
$response = new Response($csv);
|
||||||
|
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
|
||||||
|
$response->headers->set('Content-Disposition', 'attachment; filename="export_penalty_additional.csv"');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function export_project_weekly(Request $request,$access=null): Response {
|
||||||
|
$nbmonth=$this->get("session")->get("nbmonth");
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$projects=$em->getRepository("App:Project")->findAll();
|
||||||
|
|
||||||
|
//Construction du tableau des projets
|
||||||
|
$tbprojects=[];
|
||||||
|
foreach($projects as $project) {
|
||||||
|
// Filtre par Customer
|
||||||
|
if($access=="customer") {
|
||||||
|
if($project->getCustomer()->getKeypass()!=$key)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filtre par Service
|
||||||
|
if($this->get('session')->get('idservice')!="all") {
|
||||||
|
if($project->getService()->getId()!=$this->get('session')->get('idservice'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filtre par project
|
||||||
|
if($this->get('session')->get('idproject')!="all") {
|
||||||
|
if($project->getId()!=$this->get('session')->get('idproject'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ne prendre que les projets actif/inactif
|
||||||
|
if($this->get('session')->get('activeproject')!=$project->getActive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$tbproject= [];
|
||||||
|
$tbproject["projectname"] = $project->getDisplayname();
|
||||||
|
$tbproject["name"] = $project->getname();
|
||||||
|
$tbproject["customer"] = $project->getCustomer()->getName();
|
||||||
|
// Somme event validé par semaine
|
||||||
|
$start=new \Datetime('first day of this month');
|
||||||
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->modify('previous monday');
|
||||||
|
$start->setTime(0,0,0);
|
||||||
|
$endmonth = new \Datetime('first day of this month');
|
||||||
|
$endmonth->add(new \DateInterval('P1M'));
|
||||||
|
$endmonth->modify('next monday');
|
||||||
|
$endmonth->setTime(23,59,0);
|
||||||
|
|
||||||
|
$eventsbyweek = $em
|
||||||
|
->createQueryBuilder('event')
|
||||||
|
->select('event')
|
||||||
|
->from('App:Task','task')
|
||||||
|
->from('App:Event','event')
|
||||||
|
->Where('task.project=:project')
|
||||||
|
->andWhere('event.task=task')
|
||||||
|
->andWhere('event.end >=:start')
|
||||||
|
->andWhere('event.end <:end')
|
||||||
|
->andWhere('event.validate=:validate')
|
||||||
|
->setParameter('project',$project)
|
||||||
|
->setParameter('validate',true)
|
||||||
|
->setParameter('start',$start)
|
||||||
|
->setParameter('end',$endmonth)
|
||||||
|
->orderBy('event.start')
|
||||||
|
->getQuery()->getResult();
|
||||||
|
|
||||||
|
// foreach($eventsbyweek as $event) {
|
||||||
|
// if(!isset($tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")])){
|
||||||
|
// $tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")] = [
|
||||||
|
// "weeknumber" => $event->getStart()->format("W"),
|
||||||
|
// "cumul" => 0,
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// $tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["cumul"] = $tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["cumul"]+$event->getDuration();
|
||||||
|
|
||||||
|
// }
|
||||||
|
// foreach($eventsbyweek as $event) {
|
||||||
|
// if(!isset($tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"])){
|
||||||
|
// $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")] = [
|
||||||
|
// "weeknumber" => $event->getStart()->format("W"),
|
||||||
|
// "users" => [],
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// if(!isset($tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()])){
|
||||||
|
// $tbuser= [
|
||||||
|
// "id"=>$event->getUser()->getId(),
|
||||||
|
// "displayname"=>$event->getUser()->getDisplayname(),
|
||||||
|
// "cumul"=>0
|
||||||
|
// ];
|
||||||
|
// $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()] = $tbuser;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()]["cumul"] = $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()]["cumul"]+$event->getDuration();
|
||||||
|
// }
|
||||||
|
foreach($eventsbyweek as $event) {
|
||||||
|
if(!isset($tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"])){
|
||||||
|
$tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")] = [
|
||||||
|
"weeknumber" => $event->getStart()->format("W"),
|
||||||
|
"tasks" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if(!isset($tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()])){
|
||||||
|
$tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()] = [
|
||||||
|
"taskname" => $event->getTask()->getName(),
|
||||||
|
"users" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if(!isset($tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()])){
|
||||||
|
$tbuser= [
|
||||||
|
"id"=>$event->getUser()->getId(),
|
||||||
|
"displayname"=>$event->getUser()->getDisplayname(),
|
||||||
|
"cumul"=>0
|
||||||
|
];
|
||||||
|
$tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()] = $tbuser;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()]["cumul"] = $tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()]["cumul"]+$event->getDuration();
|
||||||
|
}
|
||||||
|
// Somme astreintes validé par semaine
|
||||||
|
$start=new \Datetime('first day of this month');
|
||||||
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->modify('previous monday');
|
||||||
|
$start->setTime(0,0,0);
|
||||||
|
$endmonth = new \Datetime('first day of this month');
|
||||||
|
$endmonth->add(new \DateInterval('P1M'));
|
||||||
|
$endmonth->modify('next monday');
|
||||||
|
$endmonth->setTime(23,59,0);
|
||||||
|
|
||||||
|
$penaltybyweek = $em
|
||||||
|
|
||||||
|
->createQueryBuilder('penalty')
|
||||||
|
->select('penalty')
|
||||||
|
->from('App:Task','task')
|
||||||
|
->from('App:Penalty','penalty')
|
||||||
|
->Where('task.project=:project')
|
||||||
|
->andWhere('penalty.task=task')
|
||||||
|
->andWhere('penalty.end >=:start')
|
||||||
|
->andWhere('penalty.end <:end')
|
||||||
|
->andWhere('penalty.validate=:validate')
|
||||||
|
->setParameter('project',$project)
|
||||||
|
->setParameter('validate',true)
|
||||||
|
->setParameter('start',$start)
|
||||||
|
->setParameter('end',$endmonth)
|
||||||
|
->orderBy('penalty.start')
|
||||||
|
->getQuery()->getResult();
|
||||||
|
// foreach($penaltybyweek as $penalty) {
|
||||||
|
// if(!isset($tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")])){
|
||||||
|
// $tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")] = [
|
||||||
|
// "weeknumber" => $penalty->getStart()->format("W"),
|
||||||
|
// "cumul" => 0,
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// $tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["cumul"] = $tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["cumul"]+$penalty->getDuration();
|
||||||
|
// }
|
||||||
|
// foreach($penaltybyweek as $penalty) {
|
||||||
|
// if(!isset($tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"])){
|
||||||
|
// $tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")] = [
|
||||||
|
// "weeknumber" => $penalty->getStart()->format("W"),
|
||||||
|
// "users" => [],
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// if(!isset($tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()])){
|
||||||
|
// $tbuser= [
|
||||||
|
// "id"=>$penalty->getUser()->getId(),
|
||||||
|
// "displayname"=>$penalty->getUser()->getDisplayname(),
|
||||||
|
// "cumul"=>0
|
||||||
|
// ];
|
||||||
|
// $tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()] = $tbuser;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()]["cumul"] = $tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()]["cumul"]+$penalty->getDuration();
|
||||||
|
// }
|
||||||
|
foreach($penaltybyweek as $penalty) {
|
||||||
|
if(!isset($tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["tasks"])){
|
||||||
|
$tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")] = [
|
||||||
|
"weeknumber" => $penalty->getStart()->format("W"),
|
||||||
|
"tasks" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if(!isset($tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["tasks"][$penalty->getTask()->getId()])){
|
||||||
|
$tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["tasks"][$penalty->getTask()->getId()] = [
|
||||||
|
"taskname" => $penalty->getTask()->getName(),
|
||||||
|
"users" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if(!isset($tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["tasks"][$penalty->getTask()->getId()]["users"][$penalty->getUser()->getId()])){
|
||||||
|
$tbuser= [
|
||||||
|
"id"=>$penalty->getUser()->getId(),
|
||||||
|
"displayname"=>$penalty->getUser()->getDisplayname(),
|
||||||
|
"cumul"=>0
|
||||||
|
];
|
||||||
|
$tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["tasks"][$penalty->getTask()->getId()]["users"][$penalty->getUser()->getId()] = $tbuser;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["tasks"][$penalty->getTask()->getId()]["users"][$penalty->getUser()->getId()]["cumul"] = $tbproject["weeks_by_task_by_user"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["tasks"][$penalty->getTask()->getId()]["users"][$penalty->getUser()->getId()]["cumul"]+$penalty->getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
$tbprojects[$project->getId()]=$tbproject;
|
||||||
|
}
|
||||||
|
|
||||||
|
$csv = $this->renderView('Export/export_project_weekly.csv.twig', ["projects" => $tbprojects]);
|
||||||
|
$response = new Response($csv);
|
||||||
|
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
|
||||||
|
$response->headers->set('Content-Disposition', 'attachment; filename="export_project_weekly.csv"');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -36,7 +36,9 @@ class HomeController extends AbstractController
|
|||||||
public function selectuser(Request $request)
|
public function selectuser(Request $request)
|
||||||
{
|
{
|
||||||
$iduser = $request->request->get('iduser');
|
$iduser = $request->request->get('iduser');
|
||||||
|
$selectedusers = $request->request->get('selectedusers');
|
||||||
$this->get('session')->set('iduser',$iduser);
|
$this->get('session')->set('iduser',$iduser);
|
||||||
|
$this->get('session')->set('selectedusers',$selectedusers);
|
||||||
$output=["return"=>"OK"];
|
$output=["return"=>"OK"];
|
||||||
return new Response(json_encode($output));
|
return new Response(json_encode($output));
|
||||||
}
|
}
|
||||||
|
@@ -146,8 +146,15 @@ class JobController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
|
@@ -129,8 +129,15 @@ class NatureController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
|
@@ -146,8 +146,15 @@ class OfferController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
|
@@ -150,8 +150,16 @@ class ProjectController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
$this->refreshsession();
|
$this->refreshsession();
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
|
@@ -6,6 +6,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
|
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
|
|
||||||
class ReportController extends AbstractController
|
class ReportController extends AbstractController
|
||||||
{
|
{
|
||||||
@@ -15,7 +16,6 @@ class ReportController extends AbstractController
|
|||||||
public function synthese(Request $request)
|
public function synthese(Request $request)
|
||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
$nbmonth=$this->get("session")->get("nbmonth");
|
$nbmonth=$this->get("session")->get("nbmonth");
|
||||||
$iduser=$this->get("session")->get("iduser");
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
|
||||||
@@ -122,6 +122,7 @@ class ReportController extends AbstractController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// On formate le tableau des astreintes
|
// On formate le tableau des astreintes
|
||||||
$start=new \Datetime('first day of this month');
|
$start=new \Datetime('first day of this month');
|
||||||
$start->modify('last Monday');
|
$start->modify('last Monday');
|
||||||
@@ -205,6 +206,7 @@ class ReportController extends AbstractController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
return $this->render('Report/synthese.html.twig',[
|
return $this->render('Report/synthese.html.twig',[
|
||||||
"useheader" => true,
|
"useheader" => true,
|
||||||
"usesidebar" => ($this->getUser()),
|
"usesidebar" => ($this->getUser()),
|
||||||
@@ -513,11 +515,13 @@ class ReportController extends AbstractController
|
|||||||
"beforeastreinte"=>[],
|
"beforeastreinte"=>[],
|
||||||
"months"=>[],
|
"months"=>[],
|
||||||
"offers"=>[],
|
"offers"=>[],
|
||||||
|
"weeks"=>[],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Somme event validé avant la date
|
// Somme event validé avant la date
|
||||||
$end=new \Datetime('first day of this month');
|
$end=new \Datetime('first day of this month');
|
||||||
$end->sub(new \DateInterval('P'.$nbmonth.'M'));
|
$end->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$end->setTime(23,59,0);
|
||||||
$events = $em
|
$events = $em
|
||||||
->createQueryBuilder('event')
|
->createQueryBuilder('event')
|
||||||
->select('event')
|
->select('event')
|
||||||
@@ -533,19 +537,20 @@ class ReportController extends AbstractController
|
|||||||
->orderBy('event.start')
|
->orderBy('event.start')
|
||||||
->getQuery()->getResult();
|
->getQuery()->getResult();
|
||||||
foreach($events as $event) {
|
foreach($events as $event) {
|
||||||
if(!isset($tbproject["before"][$event->getStart()->format("Ym")])) {
|
if(!isset($tbproject["before"][$event->getStart()->format("Y")][$event->getStart()->format("Ym")])) {
|
||||||
$tbproject["before"][$event->getStart()->format("Ym")] = [
|
$tbproject["before"][$event->getStart()->format("Y")][$event->getStart()->format("Ym")] = [
|
||||||
"idmonth" => $event->getStart()->format("Ym"),
|
"idmonth" => $event->getStart()->format("Ym"),
|
||||||
"monthlabel"=>$event->getStart()->format("m/Y"),
|
"monthlabel"=>$event->getStart()->format("m/Y"),
|
||||||
"duration" => 0,
|
"duration" => 0,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$tbproject["before"][$event->getStart()->format("Ym")]["duration"]=$tbproject["before"][$event->getStart()->format("Ym")]["duration"]+$event->getDuration();
|
$tbproject["before"][$event->getStart()->format("Y")][$event->getStart()->format("Ym")]["duration"]=$tbproject["before"][$event->getStart()->format("Y")][$event->getStart()->format("Ym")]["duration"]+$event->getDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Somme astreinte validé avant la date
|
// Somme astreinte validé avant la date
|
||||||
$end=new \Datetime('first day of this month');
|
$end=new \Datetime('first day of this month');
|
||||||
$end->sub(new \DateInterval('P'.$nbmonth.'M'));
|
$end->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$end->setTime(23,59,0);
|
||||||
$penaltys = $em
|
$penaltys = $em
|
||||||
->createQueryBuilder('penalty')
|
->createQueryBuilder('penalty')
|
||||||
->select('penalty')
|
->select('penalty')
|
||||||
@@ -561,17 +566,150 @@ class ReportController extends AbstractController
|
|||||||
->orderBy('penalty.start')
|
->orderBy('penalty.start')
|
||||||
->getQuery()->getResult();
|
->getQuery()->getResult();
|
||||||
foreach($penaltys as $penalty) {
|
foreach($penaltys as $penalty) {
|
||||||
if(!isset($tbproject["beforeastreinte"][$penalty->getStart()->format("Ym")])) {
|
if(!isset($tbproject["beforeastreinte"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("Ym")])) {
|
||||||
$tbproject["beforeastreinte"][$penalty->getStart()->format("Ym")] = [
|
$tbproject["beforeastreinte"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("Ym")] = [
|
||||||
"idmonth" => $penalty->getStart()->format("Ym"),
|
"idmonth" => $penalty->getStart()->format("Ym"),
|
||||||
"monthlabel"=>$penalty->getStart()->format("m/Y"),
|
"monthlabel"=>$penalty->getStart()->format("m/Y"),
|
||||||
"duration" => 0,
|
"duration" => 0,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$tbproject["beforeastreinte"][$penalty->getStart()->format("Ym")]["duration"]=$tbproject["beforeastreinte"][$penalty->getStart()->format("Ym")]["duration"]+$penalty->getDuration();
|
$tbproject["beforeastreinte"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("Ym")]["duration"]=$tbproject["beforeastreinte"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("Ym")]["duration"]+$penalty->getDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recap des propositions
|
// Somme event validé par semaine
|
||||||
|
$start=new \Datetime('first day of this month');
|
||||||
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->modify('previous monday');
|
||||||
|
$start->setTime(0,0,0);
|
||||||
|
$endmonth = new \Datetime('first day of this month');
|
||||||
|
$endmonth->add(new \DateInterval('P1M'));
|
||||||
|
$endmonth->modify('next monday');
|
||||||
|
$end->setTime(23,59,0);
|
||||||
|
|
||||||
|
$eventsbyweek = $em
|
||||||
|
->createQueryBuilder('event')
|
||||||
|
->select('event')
|
||||||
|
->from('App:Task','task')
|
||||||
|
->from('App:Event','event')
|
||||||
|
->Where('task.project=:project')
|
||||||
|
->andWhere('event.task=task')
|
||||||
|
->andWhere('event.end >=:start')
|
||||||
|
->andWhere('event.end <:end')
|
||||||
|
->andWhere('event.validate=:validate')
|
||||||
|
->setParameter('project',$project)
|
||||||
|
->setParameter('validate',true)
|
||||||
|
->setParameter('start',$start)
|
||||||
|
->setParameter('end',$endmonth)
|
||||||
|
->orderBy('event.start')
|
||||||
|
->getQuery()->getResult();
|
||||||
|
foreach($eventsbyweek as $event) {
|
||||||
|
if(!isset($tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")])){
|
||||||
|
$tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")] = [
|
||||||
|
"weeknumber" => $event->getStart()->format("W"),
|
||||||
|
"cumul" => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["cumul"] = $tbproject["weeks"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["cumul"]+$event->getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
// foreach($eventsbyweek as $event) {
|
||||||
|
// if(!isset($tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"])){
|
||||||
|
// $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")] = [
|
||||||
|
// "weeknumber" => $event->getStart()->format("W"),
|
||||||
|
// "users" => [],
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// if(!isset($tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()])){
|
||||||
|
// $tbuser= [
|
||||||
|
// "id"=>$event->getUser()->getId(),
|
||||||
|
// "displayname"=>$event->getUser()->getDisplayname(),
|
||||||
|
// "cumul"=>0
|
||||||
|
// ];
|
||||||
|
// $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()] = $tbuser;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()]["cumul"] = $tbproject["weeks_by_name"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["users"][$event->getUser()->getId()]["cumul"]+$event->getDuration();
|
||||||
|
// }
|
||||||
|
// foreach($eventsbyweek as $event) {
|
||||||
|
// if(!isset($tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"])){
|
||||||
|
// $tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")] = [
|
||||||
|
// "weeknumber" => $event->getStart()->format("W"),
|
||||||
|
// "tasks" => [],
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// if(!isset($tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()])){
|
||||||
|
// $tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()] = [
|
||||||
|
// "taskname" => $event->getTask()->getName(),
|
||||||
|
// "users" => [],
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// if(!isset($tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()])){
|
||||||
|
// $tbuser= [
|
||||||
|
// "id"=>$event->getUser()->getId(),
|
||||||
|
// "displayname"=>$event->getUser()->getDisplayname(),
|
||||||
|
// "cumul"=>0
|
||||||
|
// ];
|
||||||
|
// $tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()] = $tbuser;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()]["cumul"] = $tbproject["weeks_by_task_by_user"][$event->getStart()->format("Y")][$event->getStart()->format("W")]["tasks"][$event->getTask()->getId()]["users"][$event->getUser()->getId()]["cumul"]+$event->getDuration();
|
||||||
|
// }
|
||||||
|
// Somme astreintes validé par semaine
|
||||||
|
$start=new \Datetime('first day of this month');
|
||||||
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->modify('previous monday');
|
||||||
|
$start->setTime(0,0,0);
|
||||||
|
$endmonth = new \Datetime('first day of this month');
|
||||||
|
$endmonth->add(new \DateInterval('P1M'));
|
||||||
|
$endmonth->modify('next monday');
|
||||||
|
$end->setTime(23,59,0);
|
||||||
|
|
||||||
|
$penaltybyweek = $em
|
||||||
|
|
||||||
|
->createQueryBuilder('penalty')
|
||||||
|
->select('penalty')
|
||||||
|
->from('App:Task','task')
|
||||||
|
->from('App:Penalty','penalty')
|
||||||
|
->Where('task.project=:project')
|
||||||
|
->andWhere('penalty.task=task')
|
||||||
|
->andWhere('penalty.end >=:start')
|
||||||
|
->andWhere('penalty.end <:end')
|
||||||
|
->andWhere('penalty.validate=:validate')
|
||||||
|
->setParameter('project',$project)
|
||||||
|
->setParameter('validate',true)
|
||||||
|
->setParameter('start',$start)
|
||||||
|
->setParameter('end',$endmonth)
|
||||||
|
->orderBy('penalty.start')
|
||||||
|
->getQuery()->getResult();
|
||||||
|
foreach($penaltybyweek as $penalty) {
|
||||||
|
if(!isset($tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")])){
|
||||||
|
$tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")] = [
|
||||||
|
"weeknumber" => $penalty->getStart()->format("W"),
|
||||||
|
"cumul" => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["cumul"] = $tbproject["weeks"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["cumul"]+$penalty->getDuration();
|
||||||
|
}
|
||||||
|
foreach($penaltybyweek as $penaltybyweek) {
|
||||||
|
if(!isset($tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"])){
|
||||||
|
$tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")] = [
|
||||||
|
"weeknumber" => $penalty->getStart()->format("W"),
|
||||||
|
"users" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if(!isset($tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()])){
|
||||||
|
$tbuser= [
|
||||||
|
"id"=>$penalty->getUser()->getId(),
|
||||||
|
"displayname"=>$penalty->getUser()->getDisplayname(),
|
||||||
|
"cumul"=>0
|
||||||
|
];
|
||||||
|
$tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()] = $tbuser;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()]["cumul"] = $tbproject["weeks_by_name"][$penalty->getStart()->format("Y")][$penalty->getStart()->format("W")]["users"][$penalty->getUser()->getId()]["cumul"]+$penalty->getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recap des Commandes
|
||||||
$offers=$em->getRepository("App:Offer")->findBy(["project"=>$project->getId()]);
|
$offers=$em->getRepository("App:Offer")->findBy(["project"=>$project->getId()]);
|
||||||
foreach($offers as $offer) {
|
foreach($offers as $offer) {
|
||||||
$tbproject["offers"][$offer->getId()] = [
|
$tbproject["offers"][$offer->getId()] = [
|
||||||
@@ -584,9 +722,11 @@ class ReportController extends AbstractController
|
|||||||
// Formater les mois
|
// Formater les mois
|
||||||
$start=new \Datetime('first day of this month');
|
$start=new \Datetime('first day of this month');
|
||||||
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->setTime(0,0,0);
|
||||||
$end=new \Datetime('first day of this month');
|
$end=new \Datetime('first day of this month');
|
||||||
$end->add(new \DateInterval('P'.$nbmonth.'M'));
|
$end->add(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
$end->sub(new \DateInterval('P1D'));
|
$end->sub(new \DateInterval('P1D'));
|
||||||
|
$end->setTime(23,59,0);
|
||||||
while($start<$end) {
|
while($start<$end) {
|
||||||
$tbproject["months"][$start->format("Ym")]=[
|
$tbproject["months"][$start->format("Ym")]=[
|
||||||
"monthid"=> $start->format("Ym"),
|
"monthid"=> $start->format("Ym"),
|
||||||
@@ -670,13 +810,14 @@ class ReportController extends AbstractController
|
|||||||
}
|
}
|
||||||
$tbprojects[$project->getId()]=$tbproject;
|
$tbprojects[$project->getId()]=$tbproject;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formater les utilisateurs
|
// Formater les utilisateurs
|
||||||
$start=new \Datetime('first day of this month');
|
$start=new \Datetime('first day of this month');
|
||||||
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
$start->sub(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
|
$start->setTime(0,0,0);
|
||||||
$end=new \Datetime('first day of this month');
|
$end=new \Datetime('first day of this month');
|
||||||
$end->add(new \DateInterval('P'.$nbmonth.'M'));
|
$end->add(new \DateInterval('P'.$nbmonth.'M'));
|
||||||
$end->sub(new \DateInterval('P1D'));
|
$end->sub(new \DateInterval('P1D'));
|
||||||
|
$end->setTime(23,59,0);
|
||||||
|
|
||||||
foreach($users as $user) {
|
foreach($users as $user) {
|
||||||
$tbevents = $this->getEventuser($user,$start,$end,true);
|
$tbevents = $this->getEventuser($user,$start,$end,true);
|
||||||
@@ -695,7 +836,6 @@ class ReportController extends AbstractController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cumule
|
// Cumule
|
||||||
foreach($tbprojects as $project) {
|
foreach($tbprojects as $project) {
|
||||||
foreach($project["months"] as $month) {
|
foreach($project["months"] as $month) {
|
||||||
@@ -761,7 +901,6 @@ class ReportController extends AbstractController
|
|||||||
private function getEventuser($user,$start,$end,$onlyvalidate) {
|
private function getEventuser($user,$start,$end,$onlyvalidate) {
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
$tbevents=[];
|
$tbevents=[];
|
||||||
|
|
||||||
// Récupération de event
|
// Récupération de event
|
||||||
$qb = $em
|
$qb = $em
|
||||||
->createQueryBuilder('event')
|
->createQueryBuilder('event')
|
||||||
@@ -954,9 +1093,9 @@ class ReportController extends AbstractController
|
|||||||
"usesidebar" => ($this->getUser()),
|
"usesidebar" => ($this->getUser()),
|
||||||
"users" => $tbevents
|
"users" => $tbevents
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function activeholiday() {
|
public function activeholiday() {
|
||||||
$this->get('session')->set('activeholiday',!$this->get('session')->get('activeholiday'));
|
$this->get('session')->set('activeholiday',!$this->get('session')->get('activeholiday'));
|
||||||
@@ -988,3 +1127,4 @@ class ReportController extends AbstractController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -97,7 +97,7 @@ class SecurityController extends AbstractController
|
|||||||
$user->setPassword("CASPWD-".$username);
|
$user->setPassword("CASPWD-".$username);
|
||||||
$user->setSalt("CASPWD-".$username);
|
$user->setSalt("CASPWD-".$username);
|
||||||
|
|
||||||
$user->setRoles(["ROLE_USER"]);
|
$user->setRole("ROLE_USER");
|
||||||
|
|
||||||
$em->persist($user);
|
$em->persist($user);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
@@ -132,26 +132,14 @@ class SecurityController extends AbstractController
|
|||||||
|
|
||||||
|
|
||||||
public function logout() {
|
public function logout() {
|
||||||
$auth_mode=$this->getParameter("appAuth");
|
|
||||||
switch($auth_mode) {
|
|
||||||
case "MYSQL":
|
|
||||||
return $this->logoutMYSQL();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "CAS":
|
|
||||||
return $this->logoutCAS();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function logoutMYSQL() {
|
|
||||||
$this->get('security.token_storage')->setToken(null);
|
$this->get('security.token_storage')->setToken(null);
|
||||||
$this->get('session')->invalidate();
|
$this->get('session')->invalidate();
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl("app_home"));
|
return $this->redirect($this->generateUrl("cnous_portal_homepage"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function logoutcas() {
|
public function logoutcas() {
|
||||||
// Init Client CAS
|
// Init Client CAS
|
||||||
\phpCAS::setDebug('/var/www/html/schedule/var/log/cas.log');
|
\phpCAS::setDebug('/var/www/html/schedule/var/log/cas.log');
|
||||||
@@ -162,7 +150,5 @@ class SecurityController extends AbstractController
|
|||||||
// Logout
|
// Logout
|
||||||
$url=$this->generateUrl('app_home', array(), UrlGeneratorInterface::ABSOLUTE_URL);
|
$url=$this->generateUrl('app_home', array(), UrlGeneratorInterface::ABSOLUTE_URL);
|
||||||
\phpCAS::logout(array("service"=>$url));
|
\phpCAS::logout(array("service"=>$url));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ use Symfony\Component\Form\FormError;
|
|||||||
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
|
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
|
||||||
|
|
||||||
use App\Entity\Service as Entity;
|
use App\Entity\Service as Entity;
|
||||||
|
use App\Entity\User as Fictiv;
|
||||||
use App\Form\ServiceType as Form;
|
use App\Form\ServiceType as Form;
|
||||||
|
|
||||||
class ServiceController extends AbstractController
|
class ServiceController extends AbstractController
|
||||||
@@ -69,6 +70,16 @@ class ServiceController extends AbstractController
|
|||||||
$em->persist($data);
|
$em->persist($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
|
$fictivuser = new Fictiv();
|
||||||
|
$fictivuser->setUsername($data->getName());
|
||||||
|
$fictivuser->setPassword(bin2hex(openssl_random_pseudo_bytes(4)));
|
||||||
|
$fictivuser->setLastname("Service");
|
||||||
|
$fictivuser->setFirstname($data->getName());
|
||||||
|
$fictivuser->setEmail($data->getName());
|
||||||
|
$fictivuser->setService($data->getId());
|
||||||
|
$fictivuser->setFictive(true);
|
||||||
|
$em->persist($fictivuser);
|
||||||
|
$em->flush();
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
}
|
}
|
||||||
@@ -146,9 +157,22 @@ class ServiceController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
|
$fictivuser = $em->getRepository("App:User")->findOneBy([
|
||||||
|
'service' => $data->getService(),
|
||||||
|
'fictive' => true,
|
||||||
|
]);
|
||||||
|
$em->remove($fictivuser);
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
}
|
}
|
||||||
|
@@ -146,8 +146,15 @@ class TaskController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
return $this->redirectToRoute($this->route);
|
return $this->redirectToRoute($this->route);
|
||||||
|
284
src/schedule-2.0/src/Controller/TimerController.php
Normal file
284
src/schedule-2.0/src/Controller/TimerController.php
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use App\Entity\Timer as Entity;
|
||||||
|
use App\Form\TimerType as Form;
|
||||||
|
|
||||||
|
class TimerController extends AbstractController
|
||||||
|
{
|
||||||
|
private $data = "timer";
|
||||||
|
private $route = "app_timer";
|
||||||
|
private $render = "Timer/";
|
||||||
|
private $entity = "App:Timer";
|
||||||
|
|
||||||
|
public function list(Request $request)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$iduser = $this->get("session")->get("iduser");
|
||||||
|
$user = $em->getRepository("App:User")->find($iduser);
|
||||||
|
$tasks = $em->getRepository("App:Task")->findAll();
|
||||||
|
$timers = $em->getRepository("App:Timer")->findBy(["user"=>$iduser]);
|
||||||
|
|
||||||
|
return $this->render($this->render.'list.html.twig',[
|
||||||
|
"useheader" => true,
|
||||||
|
"usesidebar" => true,
|
||||||
|
"user" => $user,
|
||||||
|
"tasks" => $tasks,
|
||||||
|
"timers" => $timers,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view(Request $request)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$iduser = $this->get("session")->get("iduser");
|
||||||
|
$user = $em->getRepository("App:User")->find($iduser);
|
||||||
|
$tasks = $em->getRepository("App:Task")->findAll();
|
||||||
|
$timers = $em->getRepository("App:Timer")->findBy(["user"=>$iduser]);
|
||||||
|
|
||||||
|
return $this->render($this->render.'list.cal.html.twig',[
|
||||||
|
"useheader" => true,
|
||||||
|
"usesidebar" => true,
|
||||||
|
"user" => $user,
|
||||||
|
"tasks" => $tasks,
|
||||||
|
"timers" => $timers,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load(Request $request)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$tbtimers=[];
|
||||||
|
|
||||||
|
// Evenements
|
||||||
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
if($iduser=="all")
|
||||||
|
$timers=$em->getRepository("App:Timer")->findAll();
|
||||||
|
else {
|
||||||
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
$user=$em->getRepository("App:User")->find($iduser);
|
||||||
|
$timers=$em->getRepository("App:Timer")->findBy(["user"=>$user]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($timers as $timer) {
|
||||||
|
$tmp=$this->formatTimer($timer);
|
||||||
|
array_push($tbtimers,$tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retour
|
||||||
|
return new Response(json_encode($tbtimers));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(Request $request)
|
||||||
|
{
|
||||||
|
// Initialisation de l'enregistrement
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$iduser = $this->get("session")->get("iduser");
|
||||||
|
$user = $em->getRepository("App:User")->find($iduser);
|
||||||
|
$taskid = $request->request->get('taskid');
|
||||||
|
$description = $request->request->get('description');
|
||||||
|
$task = $em->getRepository("App:Task")->find($taskid);
|
||||||
|
$start = \DateTime::createFromFormat('D M d Y H:i:s e+',$request->request->get('start'));
|
||||||
|
$end = \DateTime::createFromFormat('D M d Y H:i:s e+',$request->request->get('end'));
|
||||||
|
$duration = new \DateTime(date("H:i:s", ($request->request->get('duration')/1000)));
|
||||||
|
$duration->sub(new \DateInterval('PT1H'));
|
||||||
|
$activepenalty = $request->request->get('activepenalty');
|
||||||
|
$additionalhour= $request->request->get('additionalhour');
|
||||||
|
|
||||||
|
$officeworkstart = clone $start;
|
||||||
|
$officeworkend = clone $officeworkstart;
|
||||||
|
$officeworkstart->SetTime(9,0,0);
|
||||||
|
$officeworkend->SetTime(17,30,0);
|
||||||
|
if ($start < $officeworkstart || $end > $officeworkend) {
|
||||||
|
$timer->setAdditionalHour(true);
|
||||||
|
}else{
|
||||||
|
$timer->setAdditionalHour($additionalhour);
|
||||||
|
}
|
||||||
|
|
||||||
|
$timer = new Entity();
|
||||||
|
$timer->setUser($user);
|
||||||
|
$timer->setTask($task);
|
||||||
|
$timer->setStart($start);
|
||||||
|
$timer->setEnd($end);
|
||||||
|
$timer->setDuration($duration);
|
||||||
|
$timer->setDescription($description);
|
||||||
|
$timer->setActivePenalty($activepenalty);
|
||||||
|
$em->persist($timer);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$output=["return"=>"OK"];
|
||||||
|
return new Response(json_encode($output));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit(Request $request)
|
||||||
|
{
|
||||||
|
// Initialisation de l'enregistrement
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$data = new Entity();
|
||||||
|
|
||||||
|
$iduser = $this->get("session")->get("iduser");
|
||||||
|
$user = $em->getRepository("App:User")->find($iduser);
|
||||||
|
|
||||||
|
// Création du formulaire
|
||||||
|
$form = $this->createForm(Form::class,$data,array("mode"=>"submit"));
|
||||||
|
|
||||||
|
// Récupération des data du formulaire
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
// Sur erreur
|
||||||
|
$this->getErrorForm(null,$form,$request,$data,"submit");
|
||||||
|
|
||||||
|
// Sur validation
|
||||||
|
if ($form->get('submit')->isClicked() && $form->isValid()) {
|
||||||
|
$data = $form->getData();
|
||||||
|
$data->setUser($user);
|
||||||
|
|
||||||
|
$start = $data->getStart();
|
||||||
|
$end = $data->getEnd();
|
||||||
|
$additionalhour = $data->getAdditionalHour();
|
||||||
|
|
||||||
|
$officeworkstart = clone $start;
|
||||||
|
$officeworkend = clone $officeworkstart;
|
||||||
|
$uStart = explode(":",$this->getParameter('officeHourStart'));
|
||||||
|
$uEnd = explode(":",$this->getParameter('officeHourEnd'));
|
||||||
|
$officeworkstart->SetTime(intval($uStart[0]),intval($uStart[1]),0);
|
||||||
|
$officeworkend->SetTime(intval($uEnd[0]),intval($uEnd[1]),0);
|
||||||
|
if ($start < $officeworkstart || $end > $officeworkend) {
|
||||||
|
$data->setAdditionalHour(true);
|
||||||
|
}else{
|
||||||
|
$data->setAdditionalHour($additionalhour);
|
||||||
|
}
|
||||||
|
$em->persist($data);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
// Retour à la liste
|
||||||
|
return $this->redirectToRoute($this->route);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Affichage du formulaire
|
||||||
|
return $this->render($this->render.'edit.html.twig', [
|
||||||
|
'useheader' => true,
|
||||||
|
'usesidebar' => true,
|
||||||
|
$this->data => $data,
|
||||||
|
'mode' => 'submit',
|
||||||
|
'form' => $form->createView()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($id,Request $request)
|
||||||
|
{
|
||||||
|
// Initialisation de l'enregistrement
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$data=$em->getRepository($this->entity)->find($id);
|
||||||
|
|
||||||
|
// Création du formulaire
|
||||||
|
$form = $this->createForm(Form::class,$data,array("mode"=>"update"));
|
||||||
|
|
||||||
|
// Récupération des data du formulaire
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
// Sur erreur
|
||||||
|
$this->getErrorForm(null,$form,$request,$data,"update");
|
||||||
|
|
||||||
|
// Sur validation
|
||||||
|
if ($form->get('submit')->isClicked() && $form->isValid()) {
|
||||||
|
$data = $form->getData();
|
||||||
|
$em->persist($data);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
// Retour à la liste
|
||||||
|
return $this->redirectToRoute($this->route);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $this->render($this->render.'edit.html.twig', [
|
||||||
|
'useheader' => true,
|
||||||
|
'usesidebar' => true,
|
||||||
|
$this->data => $data,
|
||||||
|
'mode' => 'update',
|
||||||
|
'form' => $form->createView()
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
public function delete($id, Request $request)
|
||||||
|
{
|
||||||
|
// Initialisation de l'enregistrement
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$data=$em->getRepository($this->entity)->find($id);
|
||||||
|
|
||||||
|
// Controle avant suppression
|
||||||
|
$error=false;
|
||||||
|
if($error)
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
$em->remove($data);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retour à la liste
|
||||||
|
return $this->redirectToRoute($this->route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected function getErrorForm($id,$form,$request,$data,$mode) {
|
||||||
|
if ($form->get('submit')->isClicked()&&$mode=="delete") {
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->get('submit')->isClicked() && $mode=="submit") {
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->get('submit')->isClicked() && !$form->isValid()) {
|
||||||
|
$this->get('session')->getFlashBag()->clear();
|
||||||
|
|
||||||
|
$errors = $form->getErrors();
|
||||||
|
foreach( $errors as $error ) {
|
||||||
|
$request->getSession()->getFlashBag()->add("error", $error->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function formatTimer($timer) {
|
||||||
|
|
||||||
|
$tmp= [
|
||||||
|
"id"=> $timer->getId(),
|
||||||
|
"title" => $timer->getTask()->getDisplayname(),
|
||||||
|
"start" => $timer->getStart()->format("Y-m-d H:i"),
|
||||||
|
"end" => $timer->getEnd()->format("Y-m-d H:i"),
|
||||||
|
"backgroundColor" => $timer->getTask()->getColor(),
|
||||||
|
"borderColor" => $timer->getTask()->getColor(),
|
||||||
|
"textColor" => "#ffffff",
|
||||||
|
"allDay" => false,
|
||||||
|
"editable" => true,
|
||||||
|
"durationEditable" => false,
|
||||||
|
"extendedProps" => [
|
||||||
|
"fulldescription" => $timer->getTask()->getDisplayname()."\n\n".$timer->getDescription(),
|
||||||
|
"description" => $timer->getDescription(),
|
||||||
|
"userid" => $timer->getUser()->getId(),
|
||||||
|
"username" => $timer->getUser()->getUsername(),
|
||||||
|
"taskid" => $timer->getTask()->getId(),
|
||||||
|
"avatar" => "/".$this->getParameter("appAlias")."/uploads/avatar/".$timer->getUser()->getAvatar(),
|
||||||
|
"estimate" => $timer->getDuration()->format("H:i"),
|
||||||
|
"locked" => false,
|
||||||
|
"editable" => true,
|
||||||
|
"astreinte" => false
|
||||||
|
]
|
||||||
|
];
|
||||||
|
return $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -202,8 +202,16 @@ class UserController extends AbstractController
|
|||||||
if($error)
|
if($error)
|
||||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
else {
|
else {
|
||||||
|
try {
|
||||||
$em->remove($data);
|
$em->remove($data);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(\Doctrine\DBAL\DBALException $e) {
|
||||||
|
// Création du formulaire
|
||||||
|
$this->get('session')->getFlashBag()->add('error', 'Impossible de supprimer cet enregistrement');
|
||||||
|
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||||
|
}
|
||||||
|
|
||||||
$this->refreshsession();
|
$this->refreshsession();
|
||||||
|
|
||||||
// Retour à la liste
|
// Retour à la liste
|
||||||
|
@@ -10,7 +10,11 @@ use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
|
|||||||
class ValidationController extends AbstractController
|
class ValidationController extends AbstractController
|
||||||
{
|
{
|
||||||
private $knpSnappy;
|
private $knpSnappy;
|
||||||
public function __construct(\Knp\Snappy\Pdf $knpSnappy) { $this->knpSnappy = $knpSnappy; }
|
private $notificator;
|
||||||
|
public function __construct(\Knp\Snappy\Pdf $knpSnappy, \App\Service\notificationService $notificator) {
|
||||||
|
$this->knpSnappy = $knpSnappy;
|
||||||
|
$this->notificator = $notificator;
|
||||||
|
}
|
||||||
|
|
||||||
public function validation(Request $request)
|
public function validation(Request $request)
|
||||||
{
|
{
|
||||||
@@ -510,6 +514,9 @@ class ValidationController extends AbstractController
|
|||||||
$event->setValidateholiday(true);
|
$event->setValidateholiday(true);
|
||||||
$em->persist($event);
|
$em->persist($event);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
$idevent=$event->getId();
|
||||||
|
$this->notificator->sendNotifValid("Congé validé", $iduser, $event);
|
||||||
}
|
}
|
||||||
|
|
||||||
$output=[];
|
$output=[];
|
||||||
@@ -543,4 +550,126 @@ class ValidationController extends AbstractController
|
|||||||
return $this->redirectToRoute("app_validationholiday");
|
return $this->redirectToRoute("app_validationholiday");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function validationtimer(Request $request)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
|
||||||
|
if($iduser=="all") {
|
||||||
|
$users=$em->getRepository("App:User")->findAll();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$users=$em->getRepository("App:User")->findBy(["id"=>$iduser]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tbtimers=[];
|
||||||
|
foreach($users as $user) {
|
||||||
|
if(in_array("ROLE_USER",$user->getRoles())) {
|
||||||
|
// Filtre par Service
|
||||||
|
if($this->get('session')->get('idservice')!="all") {
|
||||||
|
if($user->getService()->getId()!=$this->get('session')->get('idservice'))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmp=[
|
||||||
|
"id" => $user->getId(),
|
||||||
|
"user" => $user,
|
||||||
|
"timers" => [],
|
||||||
|
"timerstodevalidate" => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Timers à valider ou à dévalider
|
||||||
|
$timers = $em
|
||||||
|
->createQueryBuilder('timer')
|
||||||
|
->select('timer')
|
||||||
|
->from('App:Timer','timer')
|
||||||
|
->from('App:Task','task')
|
||||||
|
->Where('timer.user=:user')
|
||||||
|
->andWhere('timer.validate=:validate')
|
||||||
|
->andWhere('task=timer.task')
|
||||||
|
->setParameter('user',$user->getId())
|
||||||
|
->setParameter('validate',!($this->get("session")->get("activetimer")))
|
||||||
|
->getQuery()->getResult();
|
||||||
|
foreach($timers as $timer) {
|
||||||
|
|
||||||
|
$tbtimer = [
|
||||||
|
"id"=>$timer->getId(),
|
||||||
|
"taskname"=>$timer->getTask()->getDisplayname(),
|
||||||
|
"user"=>$timer->getUser()->getUsername(),
|
||||||
|
"start"=>$timer->getStart()->format("Y-m-d H:i"),
|
||||||
|
"end"=>$timer->getEnd()->format("Y-m-d H:i"),
|
||||||
|
"duration"=>$timer->getDuration(),
|
||||||
|
"activepenalty"=>$timer->getActivePenalty(),
|
||||||
|
"additionalhour"=>$timer->getAdditionalHour(),
|
||||||
|
"description"=>$timer->getDescription(),
|
||||||
|
"validate"=>$timer->getValidate(),
|
||||||
|
];
|
||||||
|
|
||||||
|
array_push($tmp["timers"],$tbtimer);
|
||||||
|
}
|
||||||
|
array_push($tbtimers,$tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($request->query->get('fgprint')) {
|
||||||
|
$render = $this->renderView('Validation/validationtimer.html.twig',[
|
||||||
|
"useheader" => true,
|
||||||
|
"usesidebar" => ($this->getUser()),
|
||||||
|
"users" => $tbtimers,
|
||||||
|
"fgprint" => $request->query->get('fgprint'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return new PdfResponse(
|
||||||
|
$this->knpSnappy->getOutputFromHtml($render),
|
||||||
|
'validationhoraires.pdf'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $this->render('Validation/validationtimer.html.twig',[
|
||||||
|
"useheader" => true,
|
||||||
|
"usesidebar" => ($this->getUser()),
|
||||||
|
"users" => $tbtimers
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validatetimer(Request $request){
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
// Récupération des variables envoyées en post
|
||||||
|
$id = $request->request->get('id');
|
||||||
|
$timer=$em->getRepository("App:Timer")->find($id);
|
||||||
|
if($timer) {
|
||||||
|
$timer->setValidate(true);
|
||||||
|
$em->persist($timer);
|
||||||
|
$em->flush();
|
||||||
|
$iduser=$this->get("session")->get("iduser");
|
||||||
|
$idtimer=$timer->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$output=[];
|
||||||
|
return new Response(json_encode($output));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function devalidatetimer(Request $request){
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
// Récupération des variables envoyées en post
|
||||||
|
$id = $request->request->get('id');
|
||||||
|
$timer=$em->getRepository("App:Timer")->find($id);
|
||||||
|
if($timer) {
|
||||||
|
$timer->setValidate(false);
|
||||||
|
$em->persist($timer);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
$output=[];
|
||||||
|
return new Response(json_encode($output));
|
||||||
|
}
|
||||||
|
public function activetimer() {
|
||||||
|
$this->get('session')->set('activetimer',!$this->get('session')->get('activetimer'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute("app_validationtimer");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,6 +50,12 @@ class Event
|
|||||||
*/
|
*/
|
||||||
private $allday;
|
private $allday;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="externaltrip", type="boolean")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $externaltrip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(name="validate", type="boolean")
|
* @ORM\Column(name="validate", type="boolean")
|
||||||
*
|
*
|
||||||
@@ -96,24 +102,24 @@ class Event
|
|||||||
|
|
||||||
public function getStart(): ?\DateTimeInterface
|
public function getStart(): ?\DateTimeInterface
|
||||||
{
|
{
|
||||||
return $this->start;
|
return clone $this->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setStart(\DateTimeInterface $start): self
|
public function setStart(\DateTimeInterface $start): self
|
||||||
{
|
{
|
||||||
$this->start = $start;
|
$this->start = clone $start;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEnd(): ?\DateTimeInterface
|
public function getEnd(): ?\DateTimeInterface
|
||||||
{
|
{
|
||||||
return $this->end;
|
return clone $this->end;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setEnd(\DateTimeInterface $end): self
|
public function setEnd(\DateTimeInterface $end): self
|
||||||
{
|
{
|
||||||
$this->end = $end;
|
$this->end = clone $end;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -129,6 +135,17 @@ class Event
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
public function getExternalTrip(): ?bool
|
||||||
|
{
|
||||||
|
return $this->externaltrip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setExternalTrip(bool $externaltrip): self
|
||||||
|
{
|
||||||
|
$this->externaltrip = $externaltrip;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function getValidate(): ?bool
|
public function getValidate(): ?bool
|
||||||
{
|
{
|
||||||
|
@@ -61,6 +61,11 @@ class Task
|
|||||||
*/
|
*/
|
||||||
private $events;
|
private $events;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\OneToMany(targetEntity="Timer", mappedBy="task", cascade={"persist"}, orphanRemoval=false)
|
||||||
|
*/
|
||||||
|
private $timers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Penalty", mappedBy="task", cascade={"persist"}, orphanRemoval=false)
|
* @ORM\OneToMany(targetEntity="Penalty", mappedBy="task", cascade={"persist"}, orphanRemoval=false)
|
||||||
*/
|
*/
|
||||||
@@ -90,6 +95,7 @@ class Task
|
|||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->events = new ArrayCollection();
|
$this->events = new ArrayCollection();
|
||||||
|
$this->timers = new ArrayCollection();
|
||||||
$this->penaltys = new ArrayCollection();
|
$this->penaltys = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +197,24 @@ class Task
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection|Timer[]
|
||||||
|
*/
|
||||||
|
public function getTimers(): Collection
|
||||||
|
{
|
||||||
|
return $this->tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addTimer(Timer $timer): self
|
||||||
|
{
|
||||||
|
if (!$this->timers->contains($timer)) {
|
||||||
|
$this->timers[] = $timer;
|
||||||
|
$timer->setTask($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function removeEvent(Event $event): self
|
public function removeEvent(Event $event): self
|
||||||
{
|
{
|
||||||
if ($this->events->contains($event)) {
|
if ($this->events->contains($event)) {
|
||||||
@@ -235,4 +259,17 @@ class Task
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function removeTimer(Timer $timer): self
|
||||||
|
{
|
||||||
|
if ($this->timers->contains($timer)) {
|
||||||
|
$this->timers->removeElement($timer);
|
||||||
|
// set the owning side to null (unless already changed)
|
||||||
|
if ($timer->getTask() === $this) {
|
||||||
|
$timer->setTask(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
197
src/schedule-2.0/src/Entity/Timer.php
Normal file
197
src/schedule-2.0/src/Entity/Timer.php
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer
|
||||||
|
*
|
||||||
|
* @ORM\Table(name="timer")
|
||||||
|
* @ORM\Entity(repositoryClass="App\Repository\TimerRepository")
|
||||||
|
*/
|
||||||
|
class Timer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="id", type="integer")
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="start", type="datetime")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="end", type="datetime")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="duration", type="datetime")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="text", nullable=true)
|
||||||
|
*/
|
||||||
|
private $description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity="User")
|
||||||
|
*/
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity="Task", inversedBy="timers"))
|
||||||
|
*/
|
||||||
|
private $task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="activepenalty", type="boolean")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $activepenalty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="additionalhour", type="boolean")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $additionalhour;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="validate", type="boolean")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $validate;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->start = new \DateTime();
|
||||||
|
$this->end = new \DateTime();
|
||||||
|
$this->duration = new \DateTime();
|
||||||
|
$this->validate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStart(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStart(\DateTimeInterface $start): self
|
||||||
|
{
|
||||||
|
$this->start = $start;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEnd(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEnd(\DateTimeInterface $end): self
|
||||||
|
{
|
||||||
|
$this->end = $end;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDuration(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDuration(\DateTimeInterface $duration): self
|
||||||
|
{
|
||||||
|
$this->duration = $duration;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): ?string
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDescription(?string $description): self
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): ?User
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUser(?User $user): self
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTask(): ?Task
|
||||||
|
{
|
||||||
|
return $this->task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTask(?Task $task): self
|
||||||
|
{
|
||||||
|
$this->task = $task;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActivePenalty(): ?bool
|
||||||
|
{
|
||||||
|
return $this->activepenalty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setActivePenalty(bool $activepenalty): self
|
||||||
|
{
|
||||||
|
$this->activepenalty = $activepenalty;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAdditionalHour(): ?bool
|
||||||
|
{
|
||||||
|
return $this->additionalhour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAdditionalHour(bool $additionalhour): self
|
||||||
|
{
|
||||||
|
$this->additionalhour = $additionalhour;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValidate(): ?bool
|
||||||
|
{
|
||||||
|
return $this->validate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setValidate(bool $validate): self
|
||||||
|
{
|
||||||
|
$this->validate = $validate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -109,6 +109,11 @@ class User implements UserInterface, \Serializable
|
|||||||
* @ORM\OneToMany(targetEntity="Userproject", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
|
* @ORM\OneToMany(targetEntity="Userproject", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
|
||||||
*/
|
*/
|
||||||
private $userprojects;
|
private $userprojects;
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="fictive", type="boolean")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $fictive;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@@ -117,6 +122,7 @@ class User implements UserInterface, \Serializable
|
|||||||
$this->penaltys = new ArrayCollection();
|
$this->penaltys = new ArrayCollection();
|
||||||
$this->jobs = new ArrayCollection();
|
$this->jobs = new ArrayCollection();
|
||||||
$this->userprojects = new ArrayCollection();
|
$this->userprojects = new ArrayCollection();
|
||||||
|
$this->fictive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUsername(): ?string
|
public function getUsername(): ?string
|
||||||
@@ -408,5 +414,17 @@ class User implements UserInterface, \Serializable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFictive(): ?bool
|
||||||
|
{
|
||||||
|
return $this->fictive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFictive(bool $fictive): self
|
||||||
|
{
|
||||||
|
$this->fictive = $fictive;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
110
src/schedule-2.0/src/Form/TimerType.php
Normal file
110
src/schedule-2.0/src/Form/TimerType.php
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TimeType;
|
||||||
|
use Symfony\Component\Form\ChoiceList\ChoiceList;
|
||||||
|
|
||||||
|
use FOS\CKEditorBundle\Form\Type\CKEditorType;
|
||||||
|
use Tetranz\Select2EntityBundle\Form\Type\Select2EntityType;
|
||||||
|
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\ORM\EntityManager;
|
||||||
|
|
||||||
|
class TimerType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add('submit',
|
||||||
|
SubmitType::class, [
|
||||||
|
"label" => "Valider",
|
||||||
|
"attr" => ["class" => "btn btn-success no-print"],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$builder->add('task',
|
||||||
|
EntityType::class, [
|
||||||
|
"label" => "Tâche",
|
||||||
|
"class" => "App:Task",
|
||||||
|
"choice_label" => function ($task) {
|
||||||
|
return $task->getDisplayname();},
|
||||||
|
|
||||||
|
"disabled" => false,
|
||||||
|
"required" => true,
|
||||||
|
"multiple" => false,
|
||||||
|
"placeholder" => "Selectionner une Tâche",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add('description',
|
||||||
|
TextType::class, [
|
||||||
|
"label" => "Description",
|
||||||
|
"required" => false
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add("activepenalty",
|
||||||
|
ChoiceType::class,[
|
||||||
|
"label" => "Astreinte active",
|
||||||
|
"choices" => ["Non"=>false, "Oui"=>true]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$builder->add("additionalhour",
|
||||||
|
ChoiceType::class,[
|
||||||
|
"label" => "Heures supplémentaires",
|
||||||
|
"choices" => ["Non"=>false, "Oui"=>true]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add('start',
|
||||||
|
DateTimeType::class, [
|
||||||
|
"label" =>"Début",
|
||||||
|
"date_widget" => "single_text",
|
||||||
|
"time_widget" => "single_text",
|
||||||
|
"format" => "yyyy-MM-dd HH:mm",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add('end',
|
||||||
|
DateTimeType::class, [
|
||||||
|
"label" =>"Fin",
|
||||||
|
"date_widget" => "single_text",
|
||||||
|
"time_widget" => "single_text",
|
||||||
|
"format" => "yyyy-MM-dd HH:mm",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->add('duration',
|
||||||
|
TimeType::class, [
|
||||||
|
"label" =>"Durée",
|
||||||
|
"widget" => "single_text",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults(array(
|
||||||
|
'data_class' => 'App\Entity\Timer',
|
||||||
|
'mode' => 'string',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
98
src/schedule-2.0/src/Service/notificationService.php
Normal file
98
src/schedule-2.0/src/Service/notificationService.php
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
class notificationService
|
||||||
|
{
|
||||||
|
private $em;
|
||||||
|
protected $mailer;
|
||||||
|
protected $twig;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, \Swift_Mailer $mailer, \Twig\Environment $twig)
|
||||||
|
{
|
||||||
|
$this->mailer = $mailer;
|
||||||
|
$this->twig = $twig;
|
||||||
|
$this->em = $em;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendNotifAttenteValid($subject, $iduser, $idevent, $valid_url)
|
||||||
|
{
|
||||||
|
$template = $this->twig->load('Notif/attentevalidation.html.twig');
|
||||||
|
$user=$this->em->getRepository("App:User")->find($iduser);
|
||||||
|
$event=$this->em->getRepository("App:Event")->find($idevent);
|
||||||
|
$users=$this->em->getRepository("App:User")->findAll();
|
||||||
|
$tbemails=[];
|
||||||
|
foreach($users as $usr) {
|
||||||
|
if(in_array("ROLE_VALIDATOR",$usr->getRoles())) {
|
||||||
|
array_push($tbemails,$usr->getEmail());
|
||||||
|
}
|
||||||
|
// else{
|
||||||
|
// if(in_array("ROLE_MASTER",$usr->getRoles())) {
|
||||||
|
// if ($usr->getService() == $user->getService() ){
|
||||||
|
// $tmp=[
|
||||||
|
// "id"=>$usr->getId(),
|
||||||
|
// "email"=>$usr->getEmail()
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// array_push($tbemails,$tmp);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
$parameters=[
|
||||||
|
'date' => new \DateTime(),
|
||||||
|
'username' => $user->getUsername(),
|
||||||
|
'start' => $event->getStart(),
|
||||||
|
'end' => $event->getEnd(),
|
||||||
|
'duration' => $event->getDuration(),
|
||||||
|
'valid_link' => $valid_url,
|
||||||
|
];
|
||||||
|
$bodyHtml = $template->renderBlock('body', $parameters);
|
||||||
|
|
||||||
|
$message = (new \Swift_Message())
|
||||||
|
->setFrom('schedule@cadoles.com')
|
||||||
|
->setSubject($user->getUsername() . " = " . $subject)
|
||||||
|
//TODO envoyer à tt les users master associé au service de l'utilisateur et l'ensemble des user validator
|
||||||
|
->setTo($tbemails)
|
||||||
|
->setBody($bodyHtml, 'text/html');
|
||||||
|
|
||||||
|
$response = $this->mailer->send($message);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
public function sendNotifValid($subject, $iduser, $idevent)
|
||||||
|
{
|
||||||
|
$template = $this->twig->load('Notif/validation.html.twig');
|
||||||
|
$user=$this->em->getRepository("App:User")->find($iduser);
|
||||||
|
$event=$this->em->getRepository("App:Event")->find($idevent);
|
||||||
|
$users=$this->em->getRepository("App:User")->findAll();
|
||||||
|
$tbemails=[];
|
||||||
|
foreach($users as $usr) {
|
||||||
|
if(in_array("ROLE_VALIDATOR",$usr->getRoles())) {
|
||||||
|
array_push($tbemails,$usr->getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$parameters=[
|
||||||
|
'date' => new \DateTime(),
|
||||||
|
'username' => $user->getUsername(),
|
||||||
|
'start' => $event->getStart(),
|
||||||
|
'end' => $event->getEnd(),
|
||||||
|
'duration' => $event->getDuration(),
|
||||||
|
];
|
||||||
|
$bodyHtml = $template->renderBlock('body', $parameters);
|
||||||
|
|
||||||
|
$message = (new \Swift_Message())
|
||||||
|
->setFrom('schedule@cadoles.com')
|
||||||
|
->setSubject($user->getUsername() . " = " . $subject)
|
||||||
|
->setTo($this->container->getParameter('appMailnotif'))
|
||||||
|
->setCc($tbemails)
|
||||||
|
->setBody($bodyHtml, 'text/html');
|
||||||
|
|
||||||
|
$response = $this->mailer->send($message);
|
||||||
|
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
@@ -69,6 +69,7 @@ class sessionListener {
|
|||||||
$session->set('activeproject',true);
|
$session->set('activeproject',true);
|
||||||
$session->set('activeoffer',true);
|
$session->set('activeoffer',true);
|
||||||
$session->set('activeholiday',true);
|
$session->set('activeholiday',true);
|
||||||
|
$session->set('activetimer',true);
|
||||||
$session->set('nbmonth',3);
|
$session->set('nbmonth',3);
|
||||||
|
|
||||||
if($curentuser!="anon.") {
|
if($curentuser!="anon.") {
|
||||||
@@ -120,6 +121,9 @@ class sessionListener {
|
|||||||
array_push($tbservices,$tmp);
|
array_push($tbservices,$tmp);
|
||||||
}
|
}
|
||||||
$session->set('services',$tbservices);
|
$session->set('services',$tbservices);
|
||||||
|
|
||||||
|
$selectedusers=[];
|
||||||
|
$session->set('selectedusers',$selectedusers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,23 +21,31 @@
|
|||||||
|
|
||||||
.fc-title {
|
.fc-title {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventAvatar {
|
.eventAvatar {
|
||||||
width: 40px;
|
width: 20px;
|
||||||
margin: 0px 5px 0px 0px;
|
margin: 0px 5px 0px 0px;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventInfo{
|
.eventInfo{
|
||||||
margin: -18px 5px 0px 0px;
|
margin: -5px 5px 0px 0px;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventUser{
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventEstimate {
|
.eventEstimate {
|
||||||
margin: -3px 10px;
|
margin: -3px 10px;
|
||||||
}
|
}
|
||||||
|
.fictive{
|
||||||
|
height:10px!important;
|
||||||
|
background-color:#cdcdcd;
|
||||||
|
}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
@@ -105,6 +113,12 @@
|
|||||||
<label class="custom-control-label" for="astreinte">Astreinte</label>
|
<label class="custom-control-label" for="astreinte">Astreinte</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="externaltrip">
|
||||||
|
<label class="custom-control-label" for="externaltrip">Déplacement externe</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description" class="control-label">
|
<label for="description" class="control-label">
|
||||||
@@ -153,7 +167,6 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label required" for="taskupdate">
|
<label class="control-label required" for="taskupdate">
|
||||||
Project<span class="mandatory">*</span>
|
Project<span class="mandatory">*</span>
|
||||||
@@ -165,7 +178,25 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="amupdate">
|
||||||
|
<label class="custom-control-label" for="amupdate">Evènement sur la matinée</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="apupdate">
|
||||||
|
<label class="custom-control-label" for="apupdate">Evènement sur l'après-midi</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="externaltripupdate">
|
||||||
|
<label class="custom-control-label" for="externaltripupdate">Déplacement externe</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description" class="control-label">
|
<label for="description" class="control-label">
|
||||||
Description
|
Description
|
||||||
@@ -188,6 +219,7 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block localjavascript %}
|
{% block localjavascript %}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$("#modalsubmit #user").select2({
|
$("#modalsubmit #user").select2({
|
||||||
theme: 'bootstrap4',
|
theme: 'bootstrap4',
|
||||||
@@ -215,12 +247,16 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
// Rendu d'un évenement
|
// Rendu d'un évenement
|
||||||
function eventRender(info) {
|
function eventRender(info) {
|
||||||
|
console.log(info.event.extendedProps);
|
||||||
|
|
||||||
// Récupération des divers élements du rendu event
|
// Récupération des divers élements du rendu event
|
||||||
var content=$(info.el).children('.fc-content');
|
var content=$(info.el).children('.fc-content');
|
||||||
var title=$(content).children('.fc-title');
|
var title=$(content).children('.fc-title');
|
||||||
|
if(!info.event.extendedProps.fictivuser){
|
||||||
// Ajouter l'avatar
|
// Ajouter l'avatar
|
||||||
content.prepend("<img src="+info.event.extendedProps.avatar+" class='eventAvatar'>");
|
content.prepend("<img src="+info.event.extendedProps.avatar+" class='eventAvatar'>");
|
||||||
|
content.append("<span class='eventUser float-left small'>"+info.event.extendedProps.username+"</span>");
|
||||||
|
var eventInfo=$(content).children('.eventUser');
|
||||||
|
|
||||||
// Ajout container
|
// Ajout container
|
||||||
content.append("<span class='eventInfo float-right'></span>");
|
content.append("<span class='eventInfo float-right'></span>");
|
||||||
@@ -231,14 +267,30 @@ function eventRender(info) {
|
|||||||
eventInfo.append("<i class='fa fa-lock float-right'></i>");
|
eventInfo.append("<i class='fa fa-lock float-right'></i>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(info.event.extendedProps.externaltrip) {
|
||||||
|
eventInfo.append("<i class='fas fa-bed float-right'></i>");
|
||||||
|
}
|
||||||
|
if(info.event.extendedProps.holiday) {
|
||||||
|
eventInfo.append("<i class='fas fa-umbrella-beach float-right'></i>");
|
||||||
|
}
|
||||||
// Ajout estimation
|
// Ajout estimation
|
||||||
eventInfo.append("<span class='eventEstimate float-right'>"+info.event.extendedProps.estimate+"</span>");
|
eventInfo.append("<span class='eventEstimate float-right small'>"+info.event.extendedProps.estimate+"</span>");
|
||||||
|
|
||||||
// Description
|
}else{
|
||||||
content.attr("title",info.event.extendedProps.fulldescription);
|
$(content).addClass('fictive');
|
||||||
|
$(content).children('.fc-title').remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formulaire Création d'un évelement
|
// Description
|
||||||
|
|
||||||
|
content.attr("data-placement","top");
|
||||||
|
content.attr("data-html",true);
|
||||||
|
content.attr("data-toggle","tooltip");
|
||||||
|
content.attr("title",info.event.extendedProps.fulldescription);
|
||||||
|
content.tooltip()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formulaire Création d'un événement
|
||||||
var allDay;
|
var allDay;
|
||||||
function eventSelect(selectionInfo) {
|
function eventSelect(selectionInfo) {
|
||||||
var start=moment(selectionInfo.start);
|
var start=moment(selectionInfo.start);
|
||||||
@@ -284,6 +336,7 @@ function eventSelect(selectionInfo) {
|
|||||||
$('#modalsubmit #end').val(end.format("YYYY-MM-DD"));
|
$('#modalsubmit #end').val(end.format("YYYY-MM-DD"));
|
||||||
|
|
||||||
$('#modalsubmit #description').val("");
|
$('#modalsubmit #description').val("");
|
||||||
|
$('#modalsubmit #externaltrip').prop("checked",false);
|
||||||
|
|
||||||
$("#modalsubmit .alert").remove();
|
$("#modalsubmit .alert").remove();
|
||||||
|
|
||||||
@@ -291,24 +344,64 @@ function eventSelect(selectionInfo) {
|
|||||||
$('#modalsubmit').modal();
|
$('#modalsubmit').modal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formulaire Modification d'un évelement
|
// Formulaire Modification d'un événement
|
||||||
function eventClick(info) {
|
function eventClick(info) {
|
||||||
if(info.event.extendedProps.editable) {
|
if(info.event.extendedProps.editable) {
|
||||||
console.log(info.event.id);
|
console.log(info.event);
|
||||||
|
|
||||||
var id=info.event.id;
|
var id=info.event.id;
|
||||||
var description=info.event.extendedProps.description;
|
var description=info.event.extendedProps.description;
|
||||||
var userid=info.event.extendedProps.userid;
|
var userid=info.event.extendedProps.userid;
|
||||||
var taskid=info.event.extendedProps.taskid;
|
var taskid=info.event.extendedProps.taskid;
|
||||||
var fgastreinte=info.event.extendedProps.astreinte;
|
var fgastreinte=info.event.extendedProps.astreinte;
|
||||||
|
var eventallday = info.event.allDay;
|
||||||
|
var eventstart = info.event.start;
|
||||||
|
var eventend = info.event.end;
|
||||||
|
var externaltrip = info.event.extendedProps.externaltrip;
|
||||||
|
var holiday = info.event.extendedProps.holiday;
|
||||||
$('#userupdate').val(userid).trigger("change");
|
$('#userupdate').val(userid).trigger("change");
|
||||||
$('#taskupdate').val(taskid).trigger("change");
|
$('#taskupdate').val(taskid).trigger("change");
|
||||||
$('#modalupdate #idevent').val(id);
|
$('#modalupdate #idevent').val(id);
|
||||||
|
|
||||||
$('#modalupdate #fgastreinte').val(fgastreinte);
|
$('#modalupdate #fgastreinte').val(fgastreinte);
|
||||||
$('#modalupdate #description').val(description);
|
$('#modalupdate #description').val(description);
|
||||||
|
if (holiday) {
|
||||||
|
$('#modalupdate #externaltripupdate').prop("checked",false);
|
||||||
|
$('#modalupdate #externaltripupdate').prop("disabled",true);
|
||||||
|
}else{
|
||||||
|
$('#modalupdate #externaltripupdate').prop("disabled",false);
|
||||||
|
$('#modalupdate #externaltripupdate').prop("checked",externaltrip);
|
||||||
|
}
|
||||||
$("#modalupdate .alert").remove();
|
$("#modalupdate .alert").remove();
|
||||||
|
eDayStart=eventstart.toString().split(" ")[2]
|
||||||
|
eDayEnd=eventend.toString().split(" ")[2]
|
||||||
|
if ((eDayEnd - eDayStart) >1) {
|
||||||
|
$('#modalupdate #amupdate').prop("checked",true);
|
||||||
|
$('#modalupdate #apupdate').prop("checked",true);
|
||||||
|
$('#modalupdate #amupdate').prop("disabled",true);
|
||||||
|
$('#modalupdate #apupdate').prop("disabled",true);
|
||||||
|
}else{
|
||||||
|
$('#modalupdate #amupdate').prop("disabled",false);
|
||||||
|
$('#modalupdate #apupdate').prop("disabled",false);
|
||||||
|
if (!eventallday){
|
||||||
|
eStart = eventstart.toString().split(" ")[4].split(":")[0]
|
||||||
|
//eEnd = eventend.toString().split(" ")[4].split(":")[0]
|
||||||
|
|
||||||
|
//AM
|
||||||
|
if (eStart == 09){
|
||||||
|
$('#modalupdate #amupdate').prop("checked",true);
|
||||||
|
$('#modalupdate #apupdate').prop("checked",false);
|
||||||
|
}
|
||||||
|
//AP
|
||||||
|
if (eStart == 13){
|
||||||
|
$('#modalupdate #amupdate').prop("checked",false);
|
||||||
|
$('#modalupdate #apupdate').prop("checked",true);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$('#modalupdate #amupdate').prop("checked",true);
|
||||||
|
$('#modalupdate #apupdate').prop("checked",true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Formulaire de création d'un évènement
|
// Formulaire de création d'un évènement
|
||||||
$('#modalupdate').modal();
|
$('#modalupdate').modal();
|
||||||
@@ -343,6 +436,7 @@ function eventSubmit() {
|
|||||||
am: $("#modalsubmit #amsubmit").prop("checked"),
|
am: $("#modalsubmit #amsubmit").prop("checked"),
|
||||||
ap: $("#modalsubmit #apsubmit").prop("checked"),
|
ap: $("#modalsubmit #apsubmit").prop("checked"),
|
||||||
astreinte: $("#modalsubmit #astreinte").prop("checked"),
|
astreinte: $("#modalsubmit #astreinte").prop("checked"),
|
||||||
|
externaltrip: $("#modalsubmit #externaltrip").prop("checked"),
|
||||||
description: $("#modalsubmit #description").val()
|
description: $("#modalsubmit #description").val()
|
||||||
},
|
},
|
||||||
url: "{{ path('app_event_submit') }}",
|
url: "{{ path('app_event_submit') }}",
|
||||||
@@ -371,7 +465,10 @@ function eventUpdate() {
|
|||||||
idevent: $("#modalupdate #idevent").val(),
|
idevent: $("#modalupdate #idevent").val(),
|
||||||
iduser: $("#userupdate").val(),
|
iduser: $("#userupdate").val(),
|
||||||
idtask: $("#taskupdate").val(),
|
idtask: $("#taskupdate").val(),
|
||||||
|
am: $("#modalupdate #amupdate").prop("checked"),
|
||||||
|
ap: $("#modalupdate #apupdate").prop("checked"),
|
||||||
fgastreinte: $("#modalupdate #fgastreinte").val(),
|
fgastreinte: $("#modalupdate #fgastreinte").val(),
|
||||||
|
externaltrip: $("#modalupdate #externaltripupdate").prop("checked"),
|
||||||
description: $("#modalupdate #description").val()
|
description: $("#modalupdate #description").val()
|
||||||
},
|
},
|
||||||
url: "{{ path('app_event_update') }}",
|
url: "{{ path('app_event_update') }}",
|
||||||
@@ -419,7 +516,6 @@ function eventDelete() {
|
|||||||
|
|
||||||
// On change astreinte
|
// On change astreinte
|
||||||
$("#astreinte").change(function() {
|
$("#astreinte").change(function() {
|
||||||
console.log(allDay)
|
|
||||||
if(this.checked) {
|
if(this.checked) {
|
||||||
$("#amsubmit").prop("disabled",true);
|
$("#amsubmit").prop("disabled",true);
|
||||||
$("#apsubmit").prop("disabled",true);
|
$("#apsubmit").prop("disabled",true);
|
||||||
|
@@ -0,0 +1,8 @@
|
|||||||
|
{% block body %}
|
||||||
|
Utilisateur;Jour;Journée entière;Astreinte;AM;AP;Taches;AM;Tache AM;AP;Tache AP;Astreinte;Description Astreintes
|
||||||
|
{% for user in users %}
|
||||||
|
{% for day, event in user.events %}
|
||||||
|
{{ user.user.displayname }};{{day}};{{event.allday}};{{event.astreinte}};{{event.am}};{{event.ap}};{{event.descriptionday|trim}} {{event.descriptionam|trim}} {{event.descriptionap|trim}} {{event.descriptionastreinte|trim}}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,6 @@
|
|||||||
|
{% block body %}
|
||||||
|
Tâche;Astr.Act;H.Supp;Utilisateur;Début;Fin;Durée;Description;
|
||||||
|
{% for timer in timers %}
|
||||||
|
{{timer.taskname}};{{timer.activepenalty}};{{timer.additionalhour}};{{timer.user}};{{timer.start|date("d/m/Y H:i")}};{{timer.end|date("d/m/Y H:i")}};{{timer.duration|date("H:i")}};{{timer.description}};
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,16 @@
|
|||||||
|
{% block body %}
|
||||||
|
Client;Projet;Tâche;Utilisateur;Année;Semaine;Cumul;
|
||||||
|
{% for project in projects %}
|
||||||
|
{% if project.weeks_by_task_by_user is defined %}
|
||||||
|
{% for year,weeks in project.weeks_by_task_by_user %}
|
||||||
|
{% for week in weeks %}
|
||||||
|
{% for task in week.tasks%}
|
||||||
|
{% for user in task.users%}
|
||||||
|
{{project.customer}};{{project.name}};{{task.taskname}};{{user.displayname}};{{year}};S{{week.weeknumber}};{{user.cumul|replace({".": ","})}};
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
36
src/schedule-2.0/templates/Export/list.html.twig
Normal file
36
src/schedule-2.0/templates/Export/list.html.twig
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{% extends "base.html.twig" %}
|
||||||
|
{% block body %}
|
||||||
|
<h1 class="page-header">
|
||||||
|
EXPORTS DE DONNEES
|
||||||
|
</h1>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<a href="{{ path('export_project_weekly') }}" class="btn btn-success">Export des Projets par semaine par participant</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Exporter le cumul des points éffectués sur un/des projets, par tâche par utilisateur.</p>
|
||||||
|
<p>Filtres utiles : Nombres de mois, Projet, Service</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<a class="btn btn-success" href={{ path('app_export_penalty_additional') }}>Export des astreintes actives et heures supplémentaires</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Exporter la liste des astreintes actives réalisés, ainsi que les saisies en heure supplémentaires.</p>
|
||||||
|
<p>Filtres utiles : Intervenant (hors "Tout le monde")</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<a class="btn btn-success" href={{ path('export_full_worked_days') }}>Export des jours pleins travaillés</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Exporter la liste des jours travaillés pleinement éligibles aux tickets restaurants</p>
|
||||||
|
<p>Filtres utiles : Nombre de mois, Intervenant</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
{% endblock %}
|
25
src/schedule-2.0/templates/Notif/attentevalidation.html.twig
Normal file
25
src/schedule-2.0/templates/Notif/attentevalidation.html.twig
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{% block body %}
|
||||||
|
{% autoescape %}
|
||||||
|
<h2>Date de la demande : {{ date|date("d/m/Y H:i") }} </h2>
|
||||||
|
<p>
|
||||||
|
<b>Utilisateur =</b> {{ username }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Début =</b> {{ start|date("d/m/Y H:i") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Fin =</b> {{ end|date("d/m/Y H:i") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Durée =</b> {{ duration }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Type =</b> Congé
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Lien pour valider =</b> {{ valid_link }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endautoescape %}
|
||||||
|
{% endblock %}
|
||||||
|
|
23
src/schedule-2.0/templates/Notif/validation.html.twig
Normal file
23
src/schedule-2.0/templates/Notif/validation.html.twig
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{% block body %}
|
||||||
|
{% autoescape %}
|
||||||
|
<h2>VALIDATION</h2>
|
||||||
|
<p>
|
||||||
|
<b>Utilisateur =</b> {{ username }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Début =</b> {{ start|date("d/m/Y H:i") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Fin =</b> {{ end|date("d/m/Y H:i") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Durée =</b> {{ duration }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Type =</b> Congé
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
{% endautoescape %}
|
||||||
|
{% endblock %}
|
||||||
|
|
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1 class="page-header">
|
<h1 class="page-header">
|
||||||
PROPOSITIONS
|
COMMANDES
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<a class="btn btn-success" href={{ path('app_offer_submit') }}>Ajouter</a>
|
<a class="btn btn-success" href={{ path('app_offer_submit') }}>Ajouter</a>
|
||||||
|
@@ -69,7 +69,12 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="no-print">
|
<td class="no-print">
|
||||||
<a href="{{path("app_project_update",{id:project.id})}}"><i class="fa fa-file"></i></a>
|
<a href="{{path("app_project_update",{id:project.id})}}"><i class="fa fa-file"></i></a>
|
||||||
<a href="{{path("app_project_users",{id:project.id})}}"><i class="fa fa-users"></i></a>
|
<a href="{{path("app_project_users",{id:project.id})}}"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-placement="right"
|
||||||
|
data-html="true"
|
||||||
|
title="{% for user in project.userprojects %}<b>{{user.user.username}}:</b> {{user.job.name}} <br />{% endfor %}"
|
||||||
|
><i class="fa fa-users"></i></a>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>{{project.customer.name}}</td>
|
<td>{{project.customer.name}}</td>
|
||||||
@@ -89,7 +94,7 @@
|
|||||||
{% for task in project.tasks %}
|
{% for task in project.tasks %}
|
||||||
{% set tottask=tottask+task.quantity %}
|
{% set tottask=tottask+task.quantity %}
|
||||||
|
|
||||||
{% set totvalidate=totvalidate+task.validate %}
|
|
||||||
{% set totplanified=totplanified+task.validate %}
|
{% set totplanified=totplanified+task.validate %}
|
||||||
{% for event in task.events %}
|
{% for event in task.events %}
|
||||||
{% set totplanified=totplanified+event.duration %}
|
{% set totplanified=totplanified+event.duration %}
|
||||||
@@ -130,6 +135,9 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block localjavascript %}
|
{% block localjavascript %}
|
||||||
|
$(function () {
|
||||||
|
$('[data-toggle="tooltip"]').tooltip()
|
||||||
|
})
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
{% if not fgprint is defined or not fgprint %}
|
{% if not fgprint is defined or not fgprint %}
|
||||||
$('.table').DataTable({
|
$('.table').DataTable({
|
||||||
|
@@ -93,7 +93,6 @@
|
|||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% if fgprint is defined and fgprint %}<h1>Planning</h1>{%endif%}
|
{% if fgprint is defined and fgprint %}<h1>Planning</h1>{%endif%}
|
||||||
|
|
||||||
{% if access=="customer" and not app.user %}
|
{% if access=="customer" and not app.user %}
|
||||||
<div class="no-print" style="margin-top:10px;">
|
<div class="no-print" style="margin-top:10px;">
|
||||||
<style> .select2-container { display:inline-block} </style>
|
<style> .select2-container { display:inline-block} </style>
|
||||||
@@ -125,40 +124,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4>RAPPORT</h4>
|
<h3>RAPPORT</h3>
|
||||||
<div class="small">
|
<div class="small">
|
||||||
{% if project.hors!=0 %}
|
|
||||||
consommé avant = {{ project.hors }}<br>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% set bycolonne = max(10,((project.before|length)/3)|round) %}
|
|
||||||
|
|
||||||
{% set compteur = 0 %}
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
{% for month in project.before %}
|
|
||||||
{% set compteur = compteur + 1 %}
|
|
||||||
{% if compteur > bycolonne %}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
{% set compteur = 1 %}
|
|
||||||
{% endif %}
|
|
||||||
consommé le {{ month.monthlabel }} = {{ month.duration }}<br>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if not project.beforeastreinte is empty %}
|
|
||||||
<h4>ASTREINTE</h4>
|
|
||||||
{% set compteur = 0 %}
|
|
||||||
<div class="small">
|
|
||||||
{% for month in project.beforeastreinte %}
|
|
||||||
consommé le {{ month.monthlabel }} = {{ month.duration }}<br>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="new-page"> </div>
|
<div class="new-page"> </div>
|
||||||
|
|
||||||
{% for month in project.months %}
|
{% for month in project.months %}
|
||||||
@@ -221,10 +189,37 @@
|
|||||||
</table>
|
</table>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="new-page"> </div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4>CUMUL HEBDOMADAIRE</h4>
|
||||||
|
<table>
|
||||||
|
{% for year, weeks in project.weeks %}
|
||||||
|
<thead>
|
||||||
|
<th class="text-center day">
|
||||||
|
{{ year}}
|
||||||
|
</th>
|
||||||
|
{% for week in weeks %}
|
||||||
|
<th class="text-center">
|
||||||
|
S{{ week.weeknumber}}
|
||||||
|
</th>
|
||||||
|
{% endfor %}
|
||||||
|
</thead>
|
||||||
|
<tr class="text-center">
|
||||||
|
<td class="text-center">
|
||||||
|
|
||||||
|
</td>
|
||||||
|
{% for week in weeks %}
|
||||||
|
<td class="text-center">
|
||||||
|
{{ week.cumul}}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
<div class="new-page"> </div>
|
||||||
{% if not project.offers is empty %}
|
{% if not project.offers is empty %}
|
||||||
<h4>COMMANDES</h4>
|
<h4>COMMANDES</h4>
|
||||||
{% set count=(project.offers|length)-8 %}
|
{% set count=(project.offers|length)-8 %}
|
||||||
@@ -334,7 +329,64 @@
|
|||||||
|
|
||||||
<div class="new-page"> </div>
|
<div class="new-page"> </div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h4>CONSOMMATION PASSEE</h4>
|
||||||
|
{% if project.hors!=0 %}
|
||||||
|
Consommation précédente totale = {{ project.hors }}<br>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{% for year in project.before %}
|
||||||
|
<thead>
|
||||||
|
<th class="text-center day">
|
||||||
|
Date
|
||||||
|
</th>
|
||||||
|
{% for month in year %}
|
||||||
|
<th class="text-center">
|
||||||
|
{{ month.monthlabel }}
|
||||||
|
</th>
|
||||||
|
{% endfor %}
|
||||||
|
</thead>
|
||||||
|
<tr class="text-center">
|
||||||
|
<td class="text-center">
|
||||||
|
Consommé
|
||||||
|
</td>
|
||||||
|
{% for month in year %}
|
||||||
|
<td class="text-center">
|
||||||
|
{{ month.duration }}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
{% if not project.beforeastreinte is empty %}
|
||||||
|
<h4>ASTREINTES PASSEES</h4>
|
||||||
|
<table>
|
||||||
|
{% for year in project.beforeastreinte %}
|
||||||
|
<thead>
|
||||||
|
<th class="text-center day">
|
||||||
|
Date
|
||||||
|
</th>
|
||||||
|
{% for month in year %}
|
||||||
|
<th class="text-center">
|
||||||
|
{{ month.monthlabel }}
|
||||||
|
</th>
|
||||||
|
{% endfor %}
|
||||||
|
</thead>
|
||||||
|
<tr class=" text-center">
|
||||||
|
<td class="text-center">
|
||||||
|
Consommé
|
||||||
|
</td>
|
||||||
|
{% for month in year %}
|
||||||
|
<td class="text-center">
|
||||||
|
{{ month.duration }}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@@ -66,6 +66,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
<th>S</th>
|
||||||
<th>L</th>
|
<th>L</th>
|
||||||
<th>M</th>
|
<th>M</th>
|
||||||
<th>M</th>
|
<th>M</th>
|
||||||
@@ -78,8 +79,8 @@
|
|||||||
{% for event in user.events %}
|
{% for event in user.events %}
|
||||||
{% if nbday==1 %}
|
{% if nbday==1 %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td class="date" style="vertical-align:middle">{{event.date|date("W")}}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<div class="date">{{ event.date | date("d/m") }}</div>
|
<div class="date">{{ event.date | date("d/m") }}</div>
|
||||||
{% if event.allday %}
|
{% if event.allday %}
|
||||||
|
112
src/schedule-2.0/templates/Timer/edit.html.twig
Normal file
112
src/schedule-2.0/templates/Timer/edit.html.twig
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
{% extends "base.html.twig" %}
|
||||||
|
|
||||||
|
{% block localstyle %}
|
||||||
|
td {
|
||||||
|
padding:5px !important;
|
||||||
|
}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{{ form_start(form) }}
|
||||||
|
<h1 class="page-header">
|
||||||
|
{% if mode=="update" %}
|
||||||
|
Modification TIMER
|
||||||
|
{% elseif mode=="submit" %}
|
||||||
|
Création TIMER
|
||||||
|
{% endif %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
|
||||||
|
{{ form_widget(form.submit) }}
|
||||||
|
|
||||||
|
<a class="btn btn-secondary" href={{ path('app_timer') }}>Annuler</a>
|
||||||
|
|
||||||
|
{% if mode=="update" %}
|
||||||
|
|
||||||
|
<a href="{{ path('app_timer_delete',{'id':timer.id}) }}"
|
||||||
|
class="btn btn-danger float-right"
|
||||||
|
data-method="delete"
|
||||||
|
data-confirm="Êtes-vous sûr de vouloir supprimer cet entregistrement ?">
|
||||||
|
Supprimer
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
{% if app.session.flashbag.has('error') %}
|
||||||
|
<div class='alert alert-danger' style='margin: 5px 0px'>
|
||||||
|
<strong>Erreur</strong><br>
|
||||||
|
{% for flashMessage in app.session.flashbag.get('error') %}
|
||||||
|
{{ flashMessage }}<br>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if app.session.flashbag.has('notice') %}
|
||||||
|
<div class='alert alert-info' style='margin: 5px 0px'>
|
||||||
|
<strong>Information</strong><br>
|
||||||
|
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||||
|
{{ flashMessage }}<br>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fa fa-pencil-alt fa-fw"></i> Informations
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
{{ form_row(form.task) }}
|
||||||
|
{{ form_row(form.description) }}
|
||||||
|
{{ form_row(form.activepenalty) }}
|
||||||
|
{{ form_row(form.additionalhour) }}
|
||||||
|
{{ form_row(form.start) }}
|
||||||
|
{{ form_row(form.end) }}
|
||||||
|
{{ form_row(form.duration) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block localjavascript %}
|
||||||
|
$("#timer_task").addClass("select2entity");
|
||||||
|
/*
|
||||||
|
* Pads this string with another string on the left until the resulting string
|
||||||
|
* has specified length. If the padding string has more than one character, the
|
||||||
|
* resulting string may be longer than desired (the padding string is not
|
||||||
|
* truncated and it is only prepended as a whole). Bad API, I know, but it's
|
||||||
|
* good enough for me.
|
||||||
|
*/
|
||||||
|
String.prototype.pad = function(length, padding) {
|
||||||
|
var result = this;
|
||||||
|
while (result.length < length) {
|
||||||
|
result = padding + result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/* Some time constants. */
|
||||||
|
var MILISECONDS_IN_SECOND = 1000;
|
||||||
|
var MILISECONDS_IN_MINUTE = 60 * MILISECONDS_IN_SECOND;
|
||||||
|
var MINUTES_IN_HOUR = 60;
|
||||||
|
|
||||||
|
/* Formats the time in the H:MM format. */
|
||||||
|
function formatTime(time) {
|
||||||
|
var timeInMinutes = time / MILISECONDS_IN_MINUTE;
|
||||||
|
var hours = Math.floor(timeInMinutes / MINUTES_IN_HOUR);
|
||||||
|
var minutes = Math.floor(timeInMinutes - hours * MINUTES_IN_HOUR);
|
||||||
|
return String(hours).pad(2, "0") + ":" + String(minutes).pad(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#timer_start_time,#timer_end_time").on('input',function(){
|
||||||
|
console.log($("#timer_start_date").val() +"T"+$("#timer_start_time").val()+":00Z")
|
||||||
|
console.log($("#timer_end_date").val()+"T"+$("#timer_end_time").val()+":00Z")
|
||||||
|
var start = Date.parse($("#timer_start_date").val() +"T"+$("#timer_start_time").val()+":00Z");
|
||||||
|
var end = Date.parse($("#timer_end_date").val()+"T"+$("#timer_end_time").val()+":00Z");
|
||||||
|
var diff = end - start;
|
||||||
|
$("#timer_duration").val(formatTime(diff))
|
||||||
|
})
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
186
src/schedule-2.0/templates/Timer/list.cal.html.twig
Normal file
186
src/schedule-2.0/templates/Timer/list.cal.html.twig
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
{% extends "base.html.twig" %}
|
||||||
|
|
||||||
|
{% block head_style %}
|
||||||
|
{{ encore_entry_link_tags('app') }}
|
||||||
|
{{ encore_entry_link_tags('fullcalendar') }}
|
||||||
|
{% endblock head_style %}
|
||||||
|
|
||||||
|
{% block localstyle %}
|
||||||
|
.fc-header-toolbar h2 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-day-grid-event {
|
||||||
|
padding:0px;
|
||||||
|
border-radius:0px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.fc-content {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-title {
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventAvatar {
|
||||||
|
width: 20px;
|
||||||
|
margin: 0px 5px 0px 0px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventInfo{
|
||||||
|
margin: -5px 5px 0px 0px;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventUser{
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventEstimate {
|
||||||
|
margin: -3px 10px;
|
||||||
|
}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div id="fullcalendar" style="width:100%; margin-top:10px;"></div>
|
||||||
|
|
||||||
|
|
||||||
|
{{ encore_entry_script_tags('fullcalendar') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block localjavascript %}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("#modalsubmit #user").select2({
|
||||||
|
theme: 'bootstrap4',
|
||||||
|
language: "fr"
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#modalsubmit #task").select2({
|
||||||
|
placeholder: "Selectionnez un projet",
|
||||||
|
allowClear: true,
|
||||||
|
theme: 'bootstrap4',
|
||||||
|
language: "fr"
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#modalupdate #user").select2({
|
||||||
|
theme: 'bootstrap4',
|
||||||
|
language: "fr"
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#modalupdate #task").select2({
|
||||||
|
placeholder: "Selectionnez un projet",
|
||||||
|
theme: 'bootstrap4',
|
||||||
|
language: "fr"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rendu d'un évenement
|
||||||
|
function eventRender(info) {
|
||||||
|
console.log(info.event.extendedProps);
|
||||||
|
// Récupération des divers élements du rendu event
|
||||||
|
var content=$(info.el).children('.fc-content');
|
||||||
|
var title=$(content).children('.fc-title');
|
||||||
|
|
||||||
|
// Ajouter l'avatar
|
||||||
|
content.prepend("<img src="+info.event.extendedProps.avatar+" class='eventAvatar'>");
|
||||||
|
content.append("<span class='eventUser float-left small'>"+info.event.extendedProps.username+"</span>");
|
||||||
|
var eventInfo=$(content).children('.eventUser');
|
||||||
|
|
||||||
|
// Ajout container
|
||||||
|
content.append("<span class='eventInfo float-right'></span>");
|
||||||
|
var eventInfo=$(content).children('.eventInfo');
|
||||||
|
|
||||||
|
// Ajouter le verrou si event non editable
|
||||||
|
if(info.event.extendedProps.locked) {
|
||||||
|
eventInfo.append("<i class='fa fa-lock float-right'></i>");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajout estimation
|
||||||
|
eventInfo.append("<span class='eventEstimate float-right small'>"+info.event.extendedProps.estimate+"</span>");
|
||||||
|
|
||||||
|
// Description
|
||||||
|
content.attr("title",info.event.extendedProps.fulldescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formulaire Création d'un évelement
|
||||||
|
var allDay;
|
||||||
|
function eventSelect(selectionInfo) {
|
||||||
|
var start=moment(selectionInfo.start);
|
||||||
|
var end=moment(selectionInfo.end);
|
||||||
|
var end=end.subtract(1, 'd');
|
||||||
|
allDay=(start.format("DD/MM/YYYY") != end.format("DD/MM/YYYY"));
|
||||||
|
|
||||||
|
// Controle
|
||||||
|
if(start.month()!=end.month()) {
|
||||||
|
alert("Une tâche ne peut être sur deux mois différents");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(start.week()!=end.week()) {
|
||||||
|
alert("Une tâche ne peut être sur deux semaines différentes");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valeur par défaut
|
||||||
|
{% if (is_granted('ROLE_ADMIN') or is_granted('ROLE_VALIDATOR') or is_granted('ROLE_MASTER')) and app.session.get('iduser')!="all" %}
|
||||||
|
$('#usersubmit').val({{app.session.get('iduser')}}).trigger("change");
|
||||||
|
{% else %}
|
||||||
|
$('#usersubmit').val({{app.user.id}}).trigger("change");
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
// Si jour de fin un samedi ou un dimanche : on est forcement en astreinte
|
||||||
|
if(moment(end).day()==0||moment(end).day()==6) {
|
||||||
|
$("#modalsubmit #astreinte").prop("checked",true);
|
||||||
|
$("#modalsubmit #astreinte").attr("disabled",true);
|
||||||
|
allDay=true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#modalsubmit #astreinte").prop('checked', false);
|
||||||
|
$("#modalsubmit #astreinte").attr('disabled', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#modalsubmit #amsubmit').prop("checked",true);
|
||||||
|
$('#modalsubmit #apsubmit').prop("checked",true);
|
||||||
|
$('#modalsubmit #amsubmit').attr("disabled",allDay);
|
||||||
|
$('#modalsubmit #apsubmit').attr("disabled",allDay);
|
||||||
|
|
||||||
|
$('#modalsubmit #start').val(start.format("YYYY-MM-DD"));
|
||||||
|
$('#modalsubmit #end').val(end.format("YYYY-MM-DD"));
|
||||||
|
|
||||||
|
$('#modalsubmit #description').val("");
|
||||||
|
|
||||||
|
$("#modalsubmit .alert").remove();
|
||||||
|
|
||||||
|
// Formulaire de création d'un évènement
|
||||||
|
$('#modalsubmit').modal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// On change astreinte
|
||||||
|
$("#astreinte").change(function() {
|
||||||
|
console.log(allDay)
|
||||||
|
if(this.checked) {
|
||||||
|
$("#amsubmit").prop("disabled",true);
|
||||||
|
$("#apsubmit").prop("disabled",true);
|
||||||
|
|
||||||
|
$('#modalsubmit #amsubmit').prop("checked",true);
|
||||||
|
$('#modalsubmit #apsubmit').prop("checked",true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#amsubmit").prop("disabled",allDay);
|
||||||
|
$("#apsubmit").prop("disabled",allDay);
|
||||||
|
|
||||||
|
$('#modalsubmit #amsubmit').prop("checked",true);
|
||||||
|
$('#modalsubmit #apsubmit').prop("checked",true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
{% endblock %}
|
703
src/schedule-2.0/templates/Timer/list.html.twig
Normal file
703
src/schedule-2.0/templates/Timer/list.html.twig
Normal file
@@ -0,0 +1,703 @@
|
|||||||
|
{% extends "base.html.twig" %}
|
||||||
|
|
||||||
|
{% block localstyle %}
|
||||||
|
#timer-task {
|
||||||
|
width:300px;
|
||||||
|
}
|
||||||
|
#timer-desc {
|
||||||
|
width:300px;
|
||||||
|
}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1 class="page-header">
|
||||||
|
SUIVI HORAIRE
|
||||||
|
</h1>
|
||||||
|
<div id="timer" class="card">
|
||||||
|
|
||||||
|
<div class="card-header">
|
||||||
|
<a class="btn btn-success" style="float:right" href={{ path('app_timer_submit') }}>Créer un Timer</a>
|
||||||
|
Lancer un Timer :
|
||||||
|
<select class="select2entity" id="timer-task" name="timer-task">
|
||||||
|
<option> Tâche </option>
|
||||||
|
{% for task in tasks %}
|
||||||
|
<option value="{{task.id}}">{{task.displayname}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<input id="timer-desc" name="timer-desc" placeholder="Description" />
|
||||||
|
<a href='#' title='Add' id='addtimer'>
|
||||||
|
<i class='fas fa-plus-circle'></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<table id="task-table" class="table table-striped table-hover" >
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="btn btn-success" href={{ path('app_timer_view') }}>Voir le calendrier</a>
|
||||||
|
<p></p>
|
||||||
|
<div class="dataTable_wrapper">
|
||||||
|
<table class="table table-striped table-bordered table-hover small" id="dataTables" style="width:100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="70px" class="no-sort">Tâche</th>
|
||||||
|
<th width="150px" class="no-sort">Description</th>
|
||||||
|
<th width="150px">Début</th>
|
||||||
|
<th width="100px">Fin</th>
|
||||||
|
<th width="100px">Durée</th>
|
||||||
|
<th width="100px" class="text-center no-string">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{%for timer in timers %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ timer.task.displayname }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="font-weight-bold">
|
||||||
|
|
||||||
|
{{ timer.activepenalty ? "<i class='fa fa-exclamation' style='color:red;opacity: 0.33;'></i> Astreinte active" : "" }}
|
||||||
|
</span>
|
||||||
|
<span class="font-weight-bold">
|
||||||
|
{{ timer.additionalhour ? "<i class='fa fa-exclamation-triangle' style='color:red;opacity: 0.33;'></i> Heures supplémentaires" : "" }}
|
||||||
|
</span>
|
||||||
|
<p>{{ timer.description }}</p>
|
||||||
|
</td>
|
||||||
|
<td>{{ timer.start|date("d/m/Y H:i") }}</td>
|
||||||
|
<td>{{ timer.end|date("d/m/Y H:i") }}</td>
|
||||||
|
<td>{{ timer.duration|date("H:i") }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{path("app_timer_update",{id:timer.id})}}">
|
||||||
|
<i class="fa fa-file"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ path('app_timer_delete',{'id':timer.id}) }}"
|
||||||
|
data-method="delete"
|
||||||
|
data-confirm="Êtes-vous sûr de vouloir supprimer cet entregistrement ?">
|
||||||
|
<i class="fa fa-trash-alt"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block localjavascript %}
|
||||||
|
|
||||||
|
|
||||||
|
/* Creates a new Task object. */
|
||||||
|
function Task(id ,name, description) {
|
||||||
|
this._name = name;
|
||||||
|
this._taskid = id;
|
||||||
|
this._description = description;
|
||||||
|
this._state = Task.State.STOPPED;
|
||||||
|
this._timeSpentInPreviousIterations = 0;
|
||||||
|
this._startDate = 0;
|
||||||
|
this._endDate = 0;
|
||||||
|
this._currentIterationStartTime = 0;
|
||||||
|
this._customTimeSpent = 0;
|
||||||
|
this._onChange = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Possible task states. */
|
||||||
|
Task.State = {
|
||||||
|
STOPPED: "stopped",
|
||||||
|
RUNNING: "running"
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.prototype = {
|
||||||
|
/* Returns the task name. */
|
||||||
|
getName: function() {
|
||||||
|
return this._name;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Returns the task description. */
|
||||||
|
getDescription: function() {
|
||||||
|
if (this._description == "NaN") {
|
||||||
|
this._description = ""
|
||||||
|
}
|
||||||
|
return this._description;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Returns the task state. */
|
||||||
|
getState: function() {
|
||||||
|
return this._state;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Is the task stopped? */
|
||||||
|
isStopped: function() {
|
||||||
|
return this._state == Task.State.STOPPED;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Is the task running? */
|
||||||
|
isRunning: function() {
|
||||||
|
return this._state == Task.State.RUNNING;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the "onChange" event handler. The "onChange" event is fired when the
|
||||||
|
* task is started, stopped, or reset.
|
||||||
|
*/
|
||||||
|
setOnChange: function(onChange) {
|
||||||
|
this._onChange = onChange;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the time spent on the task in the current work iteration. Works
|
||||||
|
* correctly only when the task is running.
|
||||||
|
*/
|
||||||
|
_getCurrentIterationTime: function() {
|
||||||
|
return (new Date).getTime() - this._currentIterationStartTime;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the total time spent on the task. This includes time spent in
|
||||||
|
* the current work iteration if the task is running.
|
||||||
|
*/
|
||||||
|
getTimeSpent: function() {
|
||||||
|
var result = this._timeSpentInPreviousIterations;
|
||||||
|
if (this._state == Task.State.RUNNING) {
|
||||||
|
result += this._getCurrentIterationTime();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Calls the "onChange" event handler if set. */
|
||||||
|
_callOnChange: function() {
|
||||||
|
if (typeof this._onChange == "function") {
|
||||||
|
this._onChange();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Starts a new task work iteration. */
|
||||||
|
start: function() {
|
||||||
|
if (this._state == Task.State.RUNNING) { return };
|
||||||
|
if (this._startDate == 0) {this._startDate = new Date()}
|
||||||
|
this._state = Task.State.RUNNING;
|
||||||
|
this._currentIterationStartTime = (new Date).getTime();
|
||||||
|
this._callOnChange();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Stops the current task work iteration. */
|
||||||
|
stop: function() {
|
||||||
|
if (this._state == Task.State.STOPPED) { return };
|
||||||
|
|
||||||
|
this._state = Task.State.STOPPED;
|
||||||
|
this._timeSpentInPreviousIterations += this._getCurrentIterationTime();
|
||||||
|
this._currentIterationStartTime = 0;
|
||||||
|
this._endDate = new Date();
|
||||||
|
this._callOnChange();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Stops the current task work iteration and resets the time data. */
|
||||||
|
reset: function() {
|
||||||
|
this.stop();
|
||||||
|
this._timeSpentInPreviousIterations = 0;
|
||||||
|
this._callOnChange();
|
||||||
|
},
|
||||||
|
save: function(task){
|
||||||
|
console.log(task)
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
data: {
|
||||||
|
taskname: task._name,
|
||||||
|
taskid: task._taskid,
|
||||||
|
description: task._description,
|
||||||
|
start: task._startDate,
|
||||||
|
end: task._endDate,
|
||||||
|
duration: task._timeSpentInPreviousIterations,
|
||||||
|
},
|
||||||
|
url: "{{ path('app_timer_create') }}",
|
||||||
|
success: function (response) {
|
||||||
|
response=JSON.parse(response);
|
||||||
|
if(response.return=="KO") {
|
||||||
|
$("#dataTable_wrapper").append("<div class='alert alert-danger' style='margin: 5px 0px'>"+response.error+"</div>");
|
||||||
|
}else{
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/* Serializes the task into a string. */
|
||||||
|
serialize: function() {
|
||||||
|
/*
|
||||||
|
* Originally, I wanted to use "toSource" and "eval" for serialization and
|
||||||
|
* deserialization, but "toSource" is not supported by WebKit, so I resorted
|
||||||
|
* to ugly hackery...
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
encodeURIComponent(this._name),
|
||||||
|
this._state,
|
||||||
|
this._timeSpentInPreviousIterations,
|
||||||
|
this._currentIterationStartTime,
|
||||||
|
this._startDate,
|
||||||
|
this._endDate,
|
||||||
|
this._taskid,
|
||||||
|
this._description,
|
||||||
|
].join("&");
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Deserializes the task from a string. */
|
||||||
|
deserialize: function(serialized) {
|
||||||
|
var parts = serialized.split("&");
|
||||||
|
this._name = decodeURIComponent(parts[0]);
|
||||||
|
this._state = parts[1];
|
||||||
|
this._timeSpentInPreviousIterations = parseInt(parts[2]);
|
||||||
|
this._currentIterationStartTime = parseInt(parts[3]);
|
||||||
|
this._startDate = parseInt(parts[4]);
|
||||||
|
this._endDate = parseInt(parts[5]);
|
||||||
|
this._taskid = parseInt(parts[6]);
|
||||||
|
this._description = parseInt(parts[7]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tasks ===== */
|
||||||
|
|
||||||
|
/* The Tasks class represents a list of tasks. */
|
||||||
|
|
||||||
|
/* Creates a new Tasks object. */
|
||||||
|
function Tasks() {
|
||||||
|
this._tasks = [];
|
||||||
|
|
||||||
|
this._onAdd = null;
|
||||||
|
this._onRemove = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tasks.prototype = {
|
||||||
|
/*
|
||||||
|
* Sets the "onAdd" event handler. The "onAdd" event is fired when a task
|
||||||
|
* is added to the list.
|
||||||
|
*/
|
||||||
|
setOnAdd: function(onAdd) {
|
||||||
|
this._onAdd = onAdd;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the "onRemove" event handler. The "onRemove" event is fired when a
|
||||||
|
* task is removed from the list.
|
||||||
|
*/
|
||||||
|
setOnRemove: function(onRemove) {
|
||||||
|
this._onRemove = onRemove;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Returns the length of the task list. */
|
||||||
|
length: function() {
|
||||||
|
return this._tasks.length
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns index-th task in the list, or "undefined" if the index is out of
|
||||||
|
* bounds.
|
||||||
|
*/
|
||||||
|
get: function(index) {
|
||||||
|
return this._tasks[index];
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls the callback function for each task in the list. The function is
|
||||||
|
* called with three parameters - the task, its index and the task list
|
||||||
|
* object. This is modeled after "Array.forEach" in JavaScript 1.6.
|
||||||
|
*/
|
||||||
|
forEach: function(callback) {
|
||||||
|
for (var i = 0; i < this._tasks.length; i++) {
|
||||||
|
callback(this._tasks[i], i, this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Calls the "onAdd" event handler if set. */
|
||||||
|
_callOnAdd: function(task) {
|
||||||
|
if (typeof this._onAdd == "function") {
|
||||||
|
this._onAdd(task);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Adds a new task to the end of the list. */
|
||||||
|
add: function(task) {
|
||||||
|
this._tasks.push(task);
|
||||||
|
this._callOnAdd(task);
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Calls the "onRemove" event handler if set. */
|
||||||
|
_callOnRemove: function(index) {
|
||||||
|
if (typeof this._onRemove == "function") {
|
||||||
|
this._onRemove(index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes index-th task from the list. Does not do anything if the index
|
||||||
|
* is out of bounds.
|
||||||
|
*/
|
||||||
|
remove: function(index) {
|
||||||
|
this._callOnRemove(index);
|
||||||
|
this._tasks.splice(index, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Serializes the list of tasks into a string. */
|
||||||
|
serialize: function() {
|
||||||
|
var serializedTasks = [];
|
||||||
|
this.forEach(function(task) {
|
||||||
|
serializedTasks.push(task.serialize());
|
||||||
|
});
|
||||||
|
return serializedTasks.join("|");
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Deserializes the list of tasks from a string. */
|
||||||
|
deserialize: function(serialized) {
|
||||||
|
/*
|
||||||
|
* Repeatedly use "remove" so the "onRemove" event is triggered. Do the same
|
||||||
|
* with the "add" method below.
|
||||||
|
*/
|
||||||
|
while (this._tasks.length > 0) {
|
||||||
|
this.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var serializedTasks = serialized.split("|");
|
||||||
|
for (var i = 0; i < serializedTasks.length; i++) {
|
||||||
|
var task = new Task(0 ,"", "");
|
||||||
|
task.deserialize(serializedTasks[i]);
|
||||||
|
this.add(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Extensions ===== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pads this string with another string on the left until the resulting string
|
||||||
|
* has specified length. If the padding string has more than one character, the
|
||||||
|
* resulting string may be longer than desired (the padding string is not
|
||||||
|
* truncated and it is only prepended as a whole). Bad API, I know, but it's
|
||||||
|
* good enough for me.
|
||||||
|
*/
|
||||||
|
String.prototype.pad = function(length, padding) {
|
||||||
|
var result = this;
|
||||||
|
while (result.length < length) {
|
||||||
|
result = padding + result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Task List + DOM Storage ===== */
|
||||||
|
|
||||||
|
/* The list of tasks. */
|
||||||
|
var tasks = new Tasks();
|
||||||
|
|
||||||
|
/* The last value of the serialized task list string. */
|
||||||
|
var lastSerializedTasksString;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The key under which the serialized task list string is stored in the DOM
|
||||||
|
* Storage.
|
||||||
|
*/
|
||||||
|
var TASKS_DOM_STORAGE_KEY = "timerTasks";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns DOM Storage used by the application, or "null" if the browser does
|
||||||
|
* not support DOM Storage.
|
||||||
|
*/
|
||||||
|
function getStorage() {
|
||||||
|
/*
|
||||||
|
* HTML 5 says that the persistent storage is available in the
|
||||||
|
* "window.localStorage" attribute, however Firefox implements older version
|
||||||
|
* of the proposal, which uses "window.globalStorage" indexed by the domain
|
||||||
|
* name. We deal with this situation here as gracefully as possible (i.e.
|
||||||
|
* without concrete browser detection and with forward compatibility).
|
||||||
|
*
|
||||||
|
* For more information, see:
|
||||||
|
*
|
||||||
|
* http://www.whatwg.org/specs/web-apps/current-work/#storage
|
||||||
|
* https://developer.mozilla.org/En/DOM/Storage
|
||||||
|
*/
|
||||||
|
if (window.localStorage !== undefined) {
|
||||||
|
return window.localStorage;
|
||||||
|
} else if (window.globalStorage !== undefined) {
|
||||||
|
return window.globalStorage[location.hostname];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Saves the task list into a DOM Storage. Also updates the value of the
|
||||||
|
* "lastSerializedTasksString" variable.
|
||||||
|
*/
|
||||||
|
function saveTasks() {
|
||||||
|
var serializedTasksString = tasks.serialize();
|
||||||
|
getStorage()[TASKS_DOM_STORAGE_KEY] = serializedTasksString;
|
||||||
|
lastSerializedTasksString = serializedTasksString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads the serialized task list string from the DOM Storage. Returns
|
||||||
|
* "undefined" if the storage does not contain the string (this happens when
|
||||||
|
* running the application for the first time).
|
||||||
|
*/
|
||||||
|
function loadSerializedTasksString() {
|
||||||
|
var storedValue = getStorage()[TASKS_DOM_STORAGE_KEY];
|
||||||
|
/*
|
||||||
|
* The spec says "null" should be returned when the key is not found, but some
|
||||||
|
* browsers return "undefined" instead. Maybe it was in some earlier version
|
||||||
|
* of the spec (I didn't bother to check).
|
||||||
|
*/
|
||||||
|
if (storedValue !== null && storedValue !== undefined && storedValue.length > 0) {
|
||||||
|
/*
|
||||||
|
* The values retrieved from "globalStorage" use one more level of
|
||||||
|
* indirection.
|
||||||
|
*/
|
||||||
|
return (window.localStorage === undefined) ? storedValue.value : storedValue;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads the task list from the DOM Storage. Also updates the value of the
|
||||||
|
* "lastSerializedTasksString" variable.
|
||||||
|
*/
|
||||||
|
function loadTasks() {
|
||||||
|
var serializedTasksString = loadSerializedTasksString();
|
||||||
|
if (serializedTasksString !== undefined) {
|
||||||
|
tasks.deserialize(serializedTasksString);
|
||||||
|
lastSerializedTasksString = serializedTasksString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Was the task list changed outside of the application? Detects the change
|
||||||
|
* by comparing the current serialized task list string in the DOM Storage
|
||||||
|
* with a kept old value.
|
||||||
|
*/
|
||||||
|
function tasksHaveChangedOutsideApplication() {
|
||||||
|
var serializedTasksString = loadSerializedTasksString();
|
||||||
|
if (serializedTasksString != lastSerializedTasksString) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== View ===== */
|
||||||
|
|
||||||
|
/* Some time constants. */
|
||||||
|
var MILISECONDS_IN_SECOND = 1000;
|
||||||
|
var MILISECONDS_IN_MINUTE = 60 * MILISECONDS_IN_SECOND;
|
||||||
|
var MINUTES_IN_HOUR = 60;
|
||||||
|
|
||||||
|
/* Formats the time in the H:MM format. */
|
||||||
|
function formatTime(time) {
|
||||||
|
var timeInMinutes = time / MILISECONDS_IN_MINUTE;
|
||||||
|
var hours = Math.floor(timeInMinutes / MINUTES_IN_HOUR);
|
||||||
|
var minutes = Math.floor(timeInMinutes - hours * MINUTES_IN_HOUR);
|
||||||
|
return hours + ":" + String(minutes).pad(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Computes the URL of the image in the start/stop link according to the task
|
||||||
|
* state.
|
||||||
|
*/
|
||||||
|
function computeStartStopLinkImageUrl(state) {
|
||||||
|
switch (state) {
|
||||||
|
case Task.State.STOPPED:
|
||||||
|
return "fa-play";
|
||||||
|
case Task.State.RUNNING:
|
||||||
|
return "fa-stop";
|
||||||
|
default:
|
||||||
|
throw "Invalid task state."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the HTML element of the row in the task table corresponding to the
|
||||||
|
* specified task and index.
|
||||||
|
*/
|
||||||
|
function buildTaskRow(task, index) {
|
||||||
|
var result = $("<tr />");
|
||||||
|
|
||||||
|
var startStopLink = $(
|
||||||
|
"<a href='#' class='start-stop-link' title='Start/stop'>"
|
||||||
|
+ "<i class='fa " + computeStartStopLinkImageUrl(task.getState()) + "'></i>"
|
||||||
|
|
||||||
|
);
|
||||||
|
startStopLink.click(function() {
|
||||||
|
switch (task.getState()) {
|
||||||
|
case Task.State.STOPPED:
|
||||||
|
task.start();
|
||||||
|
break;
|
||||||
|
case Task.State.RUNNING:
|
||||||
|
task.stop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw "Invalid task state."
|
||||||
|
}
|
||||||
|
saveTasks();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var resetLink = $(
|
||||||
|
"<a href='#' title='Reset'>"
|
||||||
|
+ "<i class='fa fa-undo'></i>"
|
||||||
|
);
|
||||||
|
resetLink.click(function() {
|
||||||
|
task.reset();
|
||||||
|
saveTasks();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var deleteLink = $(
|
||||||
|
"<a href='#' title='Delete' class='deletetask'>"
|
||||||
|
+ "<i class='fa fa-trash-alt' class='deletetask'></i>"
|
||||||
|
|
||||||
|
);
|
||||||
|
deleteLink.click(function() {
|
||||||
|
if (confirm("Do you really want to delete task \"" + task.getName() + "\"?")) {
|
||||||
|
tasks.remove(index);
|
||||||
|
saveTasks();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var saveLink = $(
|
||||||
|
"<a href='#' title='Save' class='savetask'>"
|
||||||
|
+ "<i class='fa fa-download' class='savetask'></i>"
|
||||||
|
);
|
||||||
|
saveLink.click(function() {
|
||||||
|
tasks.remove(index);
|
||||||
|
saveTasks();
|
||||||
|
task.save(task);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
result
|
||||||
|
.addClass("state-" + task.getState())
|
||||||
|
.append($("<td class='task-name' />").text(task.getName()))
|
||||||
|
.append($("<td class='task-description' />").text(task.getDescription()))
|
||||||
|
.append($("<td class='task-time' />").text(formatTime(task.getTimeSpent())))
|
||||||
|
.append($("<td class='task-actions' />")
|
||||||
|
.append(startStopLink)
|
||||||
|
.append(" ")
|
||||||
|
.append(resetLink)
|
||||||
|
.append(" ")
|
||||||
|
.append(saveLink)
|
||||||
|
.append(" ")
|
||||||
|
.append(deleteLink)
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finds row with the specified index in the task table. */
|
||||||
|
function findRowWithIndex(index) {
|
||||||
|
return $("#task-table").find("tr").slice(1).eq(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the row in the task table corresponding to a task according to
|
||||||
|
* its state.
|
||||||
|
*/
|
||||||
|
function updateTaskRow(row, task) {
|
||||||
|
if (task.isStopped()) {
|
||||||
|
row.removeClass("state-running");
|
||||||
|
row.addClass("state-stopped");
|
||||||
|
} else if (task.isRunning()) {
|
||||||
|
row.removeClass("state-stopped");
|
||||||
|
row.addClass("state-running");
|
||||||
|
}
|
||||||
|
|
||||||
|
row.find(".task-time").text(formatTime(task.getTimeSpent()))
|
||||||
|
|
||||||
|
row.find(".start-stop-link i").removeClass();
|
||||||
|
row.find(".start-stop-link i").addClass("fa "+computeStartStopLinkImageUrl(task.getState()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Initialization ===== */
|
||||||
|
|
||||||
|
/* Initializes event handlers on the task list. */
|
||||||
|
function initializeTasksEventHandlers() {
|
||||||
|
tasks.setOnAdd(function(task) {
|
||||||
|
var row = buildTaskRow(task, tasks.length() - 1);
|
||||||
|
$("#task-table").append(row);
|
||||||
|
task.setOnChange(function() {
|
||||||
|
updateTaskRow(row, task);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tasks.setOnRemove(function(index) {
|
||||||
|
findRowWithIndex(index).remove();
|
||||||
|
if (tasks.length() == 1 ) {
|
||||||
|
$( "#task-table" ).css({"display":"none"});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes GUI event handlers. */
|
||||||
|
function initializeGuiEventHandlers() {
|
||||||
|
$( "#addtimer" ).click(function() {
|
||||||
|
displayTaskAdd();
|
||||||
|
});
|
||||||
|
|
||||||
|
$( "#timer-desc" ).keypress(function( event ) {
|
||||||
|
if ( event.which == 13 ) {
|
||||||
|
event.preventDefault();
|
||||||
|
displayTaskAdd();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
function displayTaskAdd() {
|
||||||
|
$( "#task-table" ).css({"display":"inline"});
|
||||||
|
var taskName = $("#timer-task option:selected").text();
|
||||||
|
var taskId = $("#timer-task option:selected").val();
|
||||||
|
var taskDesc = $("#timer-desc").val();
|
||||||
|
|
||||||
|
var task = new Task(taskId, taskName, taskDesc);
|
||||||
|
tasks.add(task);
|
||||||
|
saveTasks();
|
||||||
|
$("#timer-desc").val("");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Initializes a timer used to update task times and detect changes in the
|
||||||
|
* data stored in the DOM Storage.
|
||||||
|
*/
|
||||||
|
function initializeTimer() {
|
||||||
|
setInterval(function() {
|
||||||
|
tasks.forEach(function(task, index) {
|
||||||
|
updateTaskRow(findRowWithIndex(index), task);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tasksHaveChangedOutsideApplication()) {
|
||||||
|
loadTasks();
|
||||||
|
}
|
||||||
|
}, 10 * MILISECONDS_IN_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes the application. */
|
||||||
|
$(document).ready(function(){
|
||||||
|
try {
|
||||||
|
if (!getStorage()) {
|
||||||
|
alert("Timer requires a browser with DOM Storage support, such as Firefox 3+ or Safari 4+.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert("Timer does not work with file: URLs in Firefox.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTasksEventHandlers();
|
||||||
|
loadTasks();
|
||||||
|
initializeGuiEventHandlers();
|
||||||
|
initializeTimer();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
@@ -95,6 +95,32 @@
|
|||||||
{%endif%}
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fas fa-list-ul"></i> Affectations
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Projet</th>
|
||||||
|
<th>Rôle</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for userproject in user.userprojects %}
|
||||||
|
<tr>
|
||||||
|
<td>{{userproject.project.displayname}}</td>
|
||||||
|
<td>{{userproject.job.name}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
@@ -68,6 +68,7 @@
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<th class="no-print"></th>
|
<th class="no-print"></th>
|
||||||
|
<th>S</th>
|
||||||
<th>L</th>
|
<th>L</th>
|
||||||
<th>M</th>
|
<th>M</th>
|
||||||
<th>M</th>
|
<th>M</th>
|
||||||
@@ -89,6 +90,7 @@
|
|||||||
{% set btnvalidate=true %}
|
{% set btnvalidate=true %}
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</td>
|
</td>
|
||||||
|
<td class="date" style="vertical-align:middle">{{event.date|date("W")}}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
163
src/schedule-2.0/templates/Validation/validationtimer.html.twig
Normal file
163
src/schedule-2.0/templates/Validation/validationtimer.html.twig
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
{% extends "base.html.twig" %}
|
||||||
|
|
||||||
|
{% block localstyle %}
|
||||||
|
{% if fgprint is defined and fgprint %}
|
||||||
|
table { font-size:10px;}
|
||||||
|
th,td {
|
||||||
|
border: 1px solid #37474F;
|
||||||
|
}
|
||||||
|
thead {
|
||||||
|
display: table-header-group;
|
||||||
|
}
|
||||||
|
tr { page-break-inside: avoid; }
|
||||||
|
.homecard {width: 100% }
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1 class="page-header">
|
||||||
|
VALIDATION HORAIRES
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="custom-control custom-switch float-right">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="switchactive" {% if app.session.get('activetimer') %} checked {% endif %}>
|
||||||
|
<label class="custom-control-label" for="switchactive">Horaires à Valider</label>
|
||||||
|
</div>
|
||||||
|
<div style="height:30px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="card homecard">
|
||||||
|
<div class="card-header">
|
||||||
|
{% if not app.session.get('activetimer') %}
|
||||||
|
Horaires à Dévalider
|
||||||
|
{% else %}
|
||||||
|
Horaires à Valider
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="dataTable_wrapper">
|
||||||
|
<table class="table table-striped table-bordered table-hover small" id="dataTables" style="width:100%">
|
||||||
|
<thead>
|
||||||
|
<th class="no-print"></th>
|
||||||
|
<th width="150px">Utilisateur</th>
|
||||||
|
<th>Tâche</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Début</th>
|
||||||
|
<th>Fin</th>
|
||||||
|
<th>Durée</th>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
{% for user in users %}
|
||||||
|
{% for timer in user.timers %}
|
||||||
|
<tr id="row-{{timer.id}}">
|
||||||
|
<td class="no-print" style="vertical-align:middle">
|
||||||
|
{% if timer.validate %}
|
||||||
|
<i class="fa fa-thumbs-down validate-{{user.user.id}}" onClick="devalidate({{timer.id}})" style="cursor:pointer; color:red;"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="fa fa-thumbs-up validate-{{user.user.id}}" onClick="validate({{timer.id}})" style="cursor:pointer; color:green;"></i>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ user.user.displayname }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ timer.taskname }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="font-weight-bold">
|
||||||
|
{{ timer.activepenalty ? "<i class='fa fa-exclamation' style='color:red;opacity: 0.33;'></i> Astreinte active" : "" }}
|
||||||
|
</span>
|
||||||
|
<span class="font-weight-bold">
|
||||||
|
{{ timer.additionalhour ? "<i class='fa fa-exclamation-triangle' style='color:red;opacity: 0.33;'></i> Heures supplémentaires" : "" }}
|
||||||
|
</span>
|
||||||
|
<p>{{ timer.description }}</p>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ timer.start|date("d/m/Y H:i") }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ timer.end|date("d/m/Y H:i") }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ timer.duration|date("H:i") }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block localjavascript %}
|
||||||
|
$(document).ready(function() {
|
||||||
|
{% if not fgprint is defined or not fgprint %}
|
||||||
|
$('.table ').DataTable({
|
||||||
|
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
|
||||||
|
responsive: true,
|
||||||
|
iDisplayLength: 100,
|
||||||
|
order: [[ 1, "asc" ]]
|
||||||
|
});
|
||||||
|
{%else%}
|
||||||
|
$('#dataTables').removeClass("table table-striped table-bordered table-hover small dataTable no-footer");
|
||||||
|
{% endif %}
|
||||||
|
});
|
||||||
|
|
||||||
|
function myprint() {
|
||||||
|
href=document.location.href;
|
||||||
|
document.location.href=href+"?fgprint=true";
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate(id) {
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
data: {
|
||||||
|
id: id,
|
||||||
|
},
|
||||||
|
url: "{{ path('app_validationtimer_validate') }}",
|
||||||
|
success: function (response) {
|
||||||
|
response=JSON.parse(response);
|
||||||
|
if(response.return=="KO") {
|
||||||
|
alert(response.error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#row-"+id).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function devalidate(id) {
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
data: {
|
||||||
|
id: id,
|
||||||
|
},
|
||||||
|
url: "{{ path('app_validationtimer_devalidate') }}",
|
||||||
|
success: function (response) {
|
||||||
|
response=JSON.parse(response);
|
||||||
|
if(response.return=="KO") {
|
||||||
|
alert(response.error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#row-"+id).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#switchactive').change(function() {
|
||||||
|
window.location="{{ path('app_validationtimer_activetimer' )}}";
|
||||||
|
});
|
||||||
|
|
||||||
|
{% endblock %}
|
@@ -256,7 +256,7 @@
|
|||||||
{% set contentsidebar="contentsidebar" %}
|
{% set contentsidebar="contentsidebar" %}
|
||||||
|
|
||||||
<div id="sidebar" class="collapse">
|
<div id="sidebar" class="collapse">
|
||||||
<ul class="nav">
|
<ul style="padding-bottom:70px" class="nav">
|
||||||
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_VALIDATOR') or is_granted('ROLE_MASTER') or is_granted('ROLE_USER') %}
|
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_VALIDATOR') or is_granted('ROLE_MASTER') or is_granted('ROLE_USER') %}
|
||||||
<p></p>
|
<p></p>
|
||||||
<li>
|
<li>
|
||||||
@@ -284,13 +284,21 @@
|
|||||||
</label>
|
</label>
|
||||||
</a>
|
</a>
|
||||||
<div class="select-control">
|
<div class="select-control">
|
||||||
<select class="form-control select2entity" id="sideuser" name="sideuser">
|
<select class="form-control select2entity" id="sideuser" name="sideuser" multiple>
|
||||||
<option value="all" selected>Tout le monde</option>
|
<option value="all" {%if app.session.get('iduser')=="all" %}selected{% endif %}>Tout le monde</option>
|
||||||
{% for user in app.session.get('users') %}
|
{% for user in app.session.get('users') %}
|
||||||
{% set selected="" %}
|
{% set selected="" %}
|
||||||
|
{% if app.session.get('selectedusers')|length > 1 %}
|
||||||
|
{% for suser in app.session.get('selectedusers') %}
|
||||||
|
{%if user.id == suser %}
|
||||||
|
{% set selected="selected" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
{%if user.id==app.session.get('iduser') %}
|
{%if user.id==app.session.get('iduser') %}
|
||||||
{% set selected="selected" %}
|
{% set selected="selected" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
<option value="{{user.id}}" {{selected}}>{{user.displayname}}</option>
|
<option value="{{user.id}}" {{selected}}>{{user.displayname}}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
@@ -359,9 +367,21 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="last">
|
<li>
|
||||||
|
<a href="{{path("app_timer")}}">
|
||||||
|
<i class="fa fa-stopwatch"></i>Suivi Horaire
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
<a href="{{path("app_holiday")}}">
|
<a href="{{path("app_holiday")}}">
|
||||||
<i class="fa fa-cocktail"></i>Mes Congés
|
<i class="fa fa-umbrella-beach"></i>Mes Congés
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="last">
|
||||||
|
<a href="{{path("app_export_view")}}">
|
||||||
|
<i class="fa fa-file-download"></i>Exports
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -372,13 +392,19 @@
|
|||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{path("app_validation")}}">
|
<a href="{{path("app_validation")}}">
|
||||||
<i class="fa fa-user"></i>Validation
|
<i class="fa fa-user-check"></i>Validation Calendrier
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="{{path("app_validationholiday")}}">
|
||||||
|
<i class="fa fa-user-tag"></i>Validation Congés
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="last">
|
<li class="last">
|
||||||
<a href="{{path("app_validationholiday")}}">
|
<a href="{{path("app_validationtimer")}}">
|
||||||
<i class="fa fa-suitcase"></i>Validation Congés
|
<i class="fa fa-user-clock"></i>Validation Horaires
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -401,7 +427,7 @@
|
|||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{path("app_offer")}}">
|
<a href="{{path("app_offer")}}">
|
||||||
<i class="fa fa-euro-sign"></i>Propositions
|
<i class="fa fa-euro-sign"></i>Commandes
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -494,10 +520,13 @@
|
|||||||
|
|
||||||
$('#sideuser').on('select2:select', function (e) {
|
$('#sideuser').on('select2:select', function (e) {
|
||||||
var data = e.params.data;
|
var data = e.params.data;
|
||||||
|
var selectedusers = $('#sideuser').val();
|
||||||
|
console.log(selectedusers)
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: {
|
data: {
|
||||||
iduser: data.id,
|
iduser: data.id,
|
||||||
|
selectedusers: selectedusers,
|
||||||
},
|
},
|
||||||
url: "{{ path('app_home_selectuser') }}",
|
url: "{{ path('app_home_selectuser') }}",
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
|
@@ -4,6 +4,12 @@ APP_SECRET=%%pwdreader("","/var/www/html/schedule/.key")
|
|||||||
APP_AUTH=CAS
|
APP_AUTH=CAS
|
||||||
|
|
||||||
|
|
||||||
|
# MAIL sendmail / smtp
|
||||||
|
MAILER_METHOD=sendmail
|
||||||
|
MAILER_URL=
|
||||||
|
MAILER_NOREPLY=noreply@noreply.fr
|
||||||
|
MAILER_DEFAULT_NOTIF=%%getVar('schedule_email_global_notif', '')
|
||||||
|
|
||||||
# Bdd = Redefine local
|
# Bdd = Redefine local
|
||||||
DATABASE_NAME=schedule
|
DATABASE_NAME=schedule
|
||||||
DATABASE_USER=schedule
|
DATABASE_USER=schedule
|
||||||
|
Reference in New Issue
Block a user