This commit is contained in:
2025-09-30 21:24:37 +02:00
parent d603fb452a
commit b7b9cebacb
258 changed files with 416 additions and 601 deletions

View File

@@ -0,0 +1,62 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if mode=="update" %}
Modification JOUR FERIE
{% elseif mode=="submit" %}
Création JOUR FERIE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_breakday') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_breakday_delete',{'id':breakday.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.start) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#breakday_name").focus();
});
{% endblock %}

View File

@@ -0,0 +1,78 @@
{% extends "base.html.twig" %}
{% block localstyle %}
td {
padding:5px !important;
}
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
JOURS FERIES
</h1>
<p><a class="btn btn-success" href={{ path('app_breakday_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Jours Fériés
</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>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th>Ordre</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{% for breakday in breakdays %}
<tr>
<td class="no-print">
<a href="{{path("app_breakday_update",{id:breakday.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{breakday.start|date("Ymd")}}</td>
<td>{{breakday.start|date("d/m/Y")}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').DataTable({
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
responsive: true,
iDisplayLength: 100,
order: [[ 2, "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";
}
{% endblock %}

65
templates/Budget/edit.html.twig Executable file
View File

@@ -0,0 +1,65 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
EXERCICE
{% elseif mode=="update" %}
Modification EXERCICE
{% elseif mode=="submit" %}
Création EXERCICE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
{% if returnto is empty %}
<a class="btn btn-secondary" href={{ path('app_budget',{id:year.id}) }}>Annuler</a>
{% else %}
<a class="btn btn-secondary" href={{ path('app_budget',{id:returnto}) }}>Annuler</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.nbdaybudget) }}
{{ form_row(form.cabudget) }}
{{ form_row(form.careal) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#year_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,373 @@
{% 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; }
{%endif%}
.group td, .tbsynthese .tdtotalgene {
font-size:120%;
text-transform: uppercase;
background-color:#212529;
color:#ffffff;
}
.total td{
font-size:120%;
background-color:#cdcdcd;
font-weight: bold;
}
.tbsynthese .tbhide {display:none}
{% endblock %}
{% block body %}
<h1 class="page-header">
BUDGET
</h1>
<div class="form-group ">
<label class="control-label" for="project_active">Exercice</label>
<select id="exercice" class="form-control">
{% for year in years %}
{% set selected=""%}
{% if year.id==n2.id%}
{% set selected="selected" %}
{% endif %}
<option value="{{year.id}}" {{selected}}>{{year.start|date("m/Y")}}</option>
{% endfor %}
</select>
</div>
<div class="card mb-3">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Budget Synthèse
</div>
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-bordered tbsynthese" id="dataTables" style="width:100%; zoom:70%">
<thead>
<tr>
<th rowspan=2>Domaine</th>
<th rowspan=2 class="tbhide">Projet</th>
<th class="text-center" style="width:150px" colspan=2>{{n1.start|date("m/Y")}}</th>
<th class="text-center" style="width:150px" colspan=2>{{n2.start|date("m/Y")}}</th>
</tr>
<tr>
<th width="20px" class="no-sort no-print tbhide"></th>
<th class="text-center" style="width:150px">Réel</th>
<th class="text-center" style="width:150px">Budget</th>
<th width="20px" class="no-sort no-print tbhide"></th>
<th class="text-center" style="width:150px">Réel</th>
<th class="text-center" style="width:150px">Budget</th>
</tr>
</thead>
<tbody id="tbsynthesebody">
<tbody>
</table>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Budget
</div>
{% set totdayrealn1 = 0 %}
{% set totetprealn1 = 0 %}
{% set totcaarealn1 = 0 %}
{% set totdaybudgn1 = 0 %}
{% set totetpbudgn1 = 0 %}
{% set totcaabudgn1 = 0 %}
{% set totdayrealn2 = 0 %}
{% set totetprealn2 = 0 %}
{% set totcaarealn2 = 0 %}
{% set totdaybudgn2 = 0 %}
{% set totetpbudgn2 = 0 %}
{% set totcaabudgn2 = 0 %}
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-bordered tbdetail" id="dataTables" style="width:100%">
<thead>
<tr>
<th rowspan=2>Domaine</th>
<th rowspan=2 class="tbhide">Projet</th>
<th class="text-center" style="width:150px" colspan=3>{{n1.start|date("m/Y")}}</th>
<th class="text-center" style="width:150px" colspan=3>{{n2.start|date("m/Y")}}</th>
</tr>
<tr>
<th width="20px" class="no-sort no-print tbhide"></th>
<th class="text-center" style="width:150px">Réel</th>
<th class="text-center" style="width:150px">Budget</th>
<th width="20px" class="no-sort no-print tbhide"></th>
<th class="text-center" style="width:150px">Réel</th>
<th class="text-center" style="width:150px">Budget</th>
</tr>
</thead>
<tbody>
{% for domaine in domaines %}
{% set nbdayrealn1 = 0 %}
{% set nbetprealn1 = 0 %}
{% set nbcaarealn1 = 0 %}
{% set nbdaybudgn1 = 0 %}
{% set nbetpbudgn1 = 0 %}
{% set nbcaabudgn1 = 0 %}
{% set nbdayrealn2 = 0 %}
{% set nbetprealn2 = 0 %}
{% set nbcaarealn2 = 0 %}
{% set nbdaybudgn2 = 0 %}
{% set nbetpbudgn2 = 0 %}
{% set nbcaabudgn2 = 0 %}
{% for project in domaine.projects %}
{% set nbdayrealn1 = nbdayrealn1+project.nbdayrealn1 %}
{% set nbetprealn1 = nbetprealn1+project.nbetprealn1 %}
{% set nbcaarealn1 = nbcaarealn1+project.nbcaarealn1 %}
{% set nbdaybudgn1 = nbdaybudgn1+project.nbdaybudgn1 %}
{% set nbetpbudgn1 = nbetpbudgn1+project.nbetpbudgn1 %}
{% set nbcaabudgn1 = nbcaabudgn1+project.nbcaabudgn1 %}
{% set nbdayrealn2 = nbdayrealn2+project.nbdayrealn2 %}
{% set nbetprealn2 = nbetprealn2+project.nbetprealn2 %}
{% set nbcaarealn2 = nbcaarealn2+project.nbcaarealn2 %}
{% set nbdaybudgn2 = nbdaybudgn2+project.nbdaybudgn2 %}
{% set nbetpbudgn2 = nbetpbudgn2+project.nbetpbudgn2 %}
{% set nbcaabudgn2 = nbcaabudgn2+project.nbcaabudgn2 %}
<tr>
<td>{{domaine.name}}</td>
<td class="tbhide">{{project.name}}</td>
<td class="text-center tbhide">
<a href="{{path("app_budget_update",{type:"project",id:project.id,year:n1.id,returnto:n2.id})}}"><i class="fa fa-file"></i></a>
</td>
<td class="text-center">
{{project.nbdayrealn1}} jours<br>
<small>
{{project.nbetprealn1|number_format(2)}}ETP / {{project.nbcaarealn1}}
</small>
</td>
<td class="text-center">
{{project.nbdaybudgn1}} jours<br>
<small>
{{project.nbetpbudgn1|number_format(2)}}ETP / {{project.nbcaabudgn1}}
</small>
</td>
<td class="text-center tbhide">
<a href="{{path("app_budget_update",{type:"project",id:project.id,year:n2.id})}}"><i class="fa fa-file"></i></a>
</td>
<td class="text-center">
{{project.nbdayrealn2}} jours<br>
<small>
{{project.nbetprealn2|number_format(2)}}ETP / {{project.nbcaarealn2}}
</small>
</td>
<td class="text-center">
{{project.nbdaybudgn2}} jours<br>
<small>
{{project.nbetpbudgn2|number_format(2)}}ETP / {{project.nbcaabudgn2}}
</small>
</td>
</tr>
{% endfor %}
<tr>
<td>{{domaine.name}}</td>
<td>Hors Projet</td>
<td class="text-center">
<a href="{{path("app_budget_update",{type:"budget",id:domaine.id,year:n1.id,returnto:n2.id})}}"><i class="fa fa-file"></i></a>
</td>
<td class="text-center">
{{(domaine.nbdayrealn1-nbdayrealn1)}} jours<br>
<small>
{{(domaine.nbetprealn1-nbetprealn1)|number_format(2)}}ETP / {{domaine.nbcaarealn1}}
</small>
</td>
<td class="text-center">
{{(domaine.nbdaybudgn1)}} jours<br>
<small>
{{domaine.nbetpbudgn1|number_format(2)}}ETP / {{(domaine.nbcaabudgn1)}}
</small>
</td>
<td class="text-center">
<a href="{{path("app_budget_update",{type:"budget",id:domaine.id,year:n2.id,returnto:n2.id})}}"><i class="fa fa-file"></i></a>
</td>
<td class="text-center">
{{(domaine.nbdayrealn2-nbdayrealn2)}} jours<br>
<small>
{{(domaine.nbetprealn2-nbetprealn2)|number_format(2)}}ETP / {{domaine.nbcaarealn2}}
</small>
</td>
<td class="text-center">
{{(domaine.nbdaybudgn2)}} jours<br>
<small>
{{domaine.nbetpbudgn2|number_format(2)}}ETP / {{(domaine.nbcaabudgn2)}}
</small>
</td>
</tr>
<tr class="total" data-domaine="{{domaine.name}}">
<td>{{domaine.name}}</td>
<td class="tbhide" >TOTAL</td>
<td class="no-print tbhide"> </td>
<td class="text-center">
{{domaine.nbdayrealn1}} jours<br>
<small>
{{domaine.nbetprealn1|number_format(2)}}ETP / {{domaine.nbcaarealn1+nbcaarealn1}}
</small>
{% set totdayrealn1 = totdayrealn1 + domaine.nbdayrealn1 %}
{% set totetprealn1 = totetprealn1 + domaine.nbetprealn1 %}
{% set totcaarealn1 = totcaarealn1 + domaine.nbcaarealn1+nbcaarealn1 %}
</td>
<td class="text-center">
{{domaine.nbdaybudgn1+nbdaybudgn1}} jours<br>
<small>
{{(domaine.nbetpbudgn1+nbetpbudgn1)|number_format(2)}}ETP / {{domaine.nbcaabudgn1+nbcaabudgn1}}
</small>
{% set totdaybudgn1 = totdaybudgn1 + domaine.nbdaybudgn1+nbdaybudgn1 %}
{% set totetpbudgn1 = totetpbudgn1 + domaine.nbetpbudgn1+nbetpbudgn1 %}
{% set totcaabudgn1 = totcaabudgn1 + domaine.nbcaabudgn1+nbcaabudgn1 %}
</td>
<td class="no-print tbhide"> </td>
<td class="text-center">
{{domaine.nbdayrealn2}} jours<br>
<small>
{{domaine.nbetprealn2|number_format(2)}}ETP / {{domaine.nbcaarealn2+nbcaarealn2}}
</small>
{% set totdayrealn2 = totdayrealn2 + domaine.nbdayrealn2 %}
{% set totetprealn2 = totetprealn2 + domaine.nbetprealn2 %}
{% set totcaarealn2 = totcaarealn2 + domaine.nbcaarealn2+nbcaarealn2 %}
</td>
<td class="text-center">
{{domaine.nbdaybudgn2+nbdaybudgn2}} jours<br>
<small>
{{(domaine.nbetpbudgn2+nbetpbudgn2)|number_format(2)}}ETP / {{domaine.nbcaabudgn2+nbcaabudgn2}}
</small>
{% set totdaybudgn2 = totdaybudgn2 + domaine.nbdaybudgn2+nbdaybudgn2 %}
{% set totetpbudgn2 = totetpbudgn2 + domaine.nbetpbudgn2+nbetpbudgn2 %}
{% set totcaabudgn2 = totcaabudgn2 + domaine.nbcaabudgn2+nbcaabudgn2 %}
</td>
</tr>
{% endfor %}
<tr class="total totalgene" data-domaine="TOTAL">
<td class="tdtotalgene" >RESULTAT</td>
<td class="tdtotalgene tbhide">RESULTAT</td>
<td class="no-print tbhide tdtotalgene"> </td>
<td class="text-center tdtotalgene">
{{totdayrealn1}} jours<br>
<small>
{{totetprealn1|number_format(2)}}ETP / {{totcaarealn1}}
</small>
</td>
<td class="text-center tdtotalgene">
{{totdaybudgn1}} jours<br>
<small>
{{totetpbudgn1|number_format(2)}}ETP / {{totcaabudgn1}}
</small>
</td>
<td class="no-print tbhide tdtotalgene"> </td>
<td class="text-center tdtotalgene">
{{totdayrealn2}} jours<br>
<small>
{{totetprealn2|number_format(2)}}ETP / {{totcaarealn2}}
</small>
</td>
<td class="text-center tdtotalgene">
{{totdaybudgn2}} jours<br>
<small>
{{totetpbudgn2|number_format(2)}}ETP / {{totcaabudgn2}}
</small>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
var groupColumn = 0;
html="";
$('.total').each(function() {
html+="<tr>"+$(this).html()+"</tr>";
});
$("#tbsynthesebody").html(html);
var table = $('.tbdetail').DataTable({
"columnDefs": [
{ "visible": false, "targets": groupColumn }
],
"order": [[ groupColumn, 'asc' ]],
"displayLength": 1500,
"drawCallback": function ( settings ) {
var api = this.api();
var rows = api.rows( {page:'current'} ).nodes();
var last=null;
api.column(groupColumn, {page:'current'} ).data().each( function ( group, i ) {
if ( last !== group ) {
$(rows).eq( i ).before(
'<tr class="group"><td colspan="7">'+group+'</td></tr>'
);
last = group;
}
} );
}
} );
// Order by the grouping
$('.tbdetail tbody').on( 'click', 'tr.group', function () {
var currentOrder = table.order()[0];
if ( currentOrder[0] === groupColumn && currentOrder[1] === 'asc' ) {
table.order( [ groupColumn, 'desc' ] ).draw();
}
else {
table.order( [ groupColumn, 'asc' ] ).draw();
}
} );
$('#exercice').change(function() {
id=$(this).val();
url="{{ path('app_budget',{id:'xxx'}) }}";
url=url.replace("xxx",id);
document.location=url;
});
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,59 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if mode=="update" %}
Modification JOB
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_cron') }}>Annuler</a>
<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.command) }}
{{ form_row(form.jsonargument) }}
{{ form_row(form.statut) }}
{{ form_row(form.repeatcall) }}
{{ form_row(form.repeatinterval) }}
{{ form_row(form.nextexecdate) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#command").focus();
});
{% endblock %}

View File

@@ -0,0 +1,54 @@
{% extends "base.html.twig" %}
{% block body %}
<h1 class="page-header">
JOBS
</h1>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Jobs
</div>
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
<thead>
<tr>
<th width="70px" class="no-sort">Action</th>
<th>Prochaine exécution</th>
<th>Command</th>
<th>Description</th>
<th>Statut</th>
</tr>
</thead>
<tbody>
{% for cron in crons %}
<tr>
<td>
<a href="{{path("app_cron_update",{id:cron.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{cron.nextexecdate|date("d/m/Y H:i")}}</td>
<td>{{cron.command}}</td>
<td>{{cron.description}}</td>
<td>{{cron.statutlabel}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$('#dataTables').DataTable({
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
responsive: true,
iDisplayLength: 100,
order: [[ 1, "asc" ]]
});
});
{% endblock %}

View File

@@ -0,0 +1,16 @@
{% extends 'base.html.twig' %}
{% block body %}
<h1 class="page-header">
Télécharger les logs
</h1>
{% if appCron %}
<a class="btn btn-secondary" href={{ path("app_cron_getlog",{"id":"cron"}) }}>Log CRON</a>
{% endif %}
<a class="btn btn-secondary" href={{ path("app_cron_getlog",{"id":"prod"}) }}>Log PROD</a>
<a class="btn btn-secondary" href={{ path("app_cron_getlog",{"id":"dev"}) }}>Log DEV</a>
{% if appCron %}
<a class="btn btn-secondary" href={{ path("app_cron_getlog",{"id":"dump"}) }}>Dump de la Base</a>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,35 @@
{% extends 'base.html.twig' %}
{% block head_style %}
{{ encore_entry_link_tags('app') }}
{{ encore_entry_link_tags('dropzone') }}
{% endblock head_style %}
{% block body %}
<h3 class="page-header"></h3>
<button class="btn btn-secondary" onClick="closeModal();">Annuler</button>
<form action="{{ oneup_uploader_endpoint('avatar') }}" class="dropzone" id="MyDropZone" style="margin-top:10px">
{{ encore_entry_script_tags('dropzone') }}
{% endblock %}
{% block localjavascript %}
window.parent.$(".modal-title").html("ETAPE 1 - Téléchargez votre image");
Dropzone.options.MyDropZone = {
maxFiles: 1,
acceptedMimeTypes: 'image/*',
//renameFilename: false,
success: function(file, response){
$(location).attr('href',"{{ path('app_crop02') }}");
}
}
function closeModal() {
window.parent.$("#extraLargeModal").modal('hide');
}
{% endblock %}

View File

@@ -0,0 +1,71 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
{{ form_widget(form.submit) }}
<button class="btn btn-secondary" onClick="closeModal();">Annuler</button>
<div id='preview' style='overflow:hidden; width:90px; height:90px; position: absolute; top: 0px; right: 10px;'>
<img src="/{{ appAlias }}/uploads/avatar/{{ app.session.get('uploadavatar') }}" style='position: relative;' alt='Thumbnail Preview' />
</div>
<div style="width:800px; height:590px; overflow:hidden; margin:65px auto 0px auto;">
<div id="largeimg" class="crop-select-js" style="width:800px;">
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
function move(data) {
$('#form_x').val(data.xScaledToImage);
$('#form_y').val(data.yScaledToImage);
preview();
}
function resize(data) {
$('#form_w').val(data.widthScaledToImage);
$('#form_h').val(data.heightScaledToImage);
preview();
}
function preview(data) {
var scaleX = 90 / $('#form_w').val();
var scaleY = 90 / $('#form_h').val();
$('#preview img').css({
width: Math.round(scaleX * $('#largeimg').width()) + 'px',
height: Math.round(scaleY * $('#largeimg').height()) + 'px',
marginLeft: '-' + Math.round(scaleX * $('#form_x').val()) + 'px',
marginTop: '-' + Math.round(scaleY * $('#form_y').val()) + 'px'
});
}
function reportThumb() {
window.parent.$("#user_avatar").val("thumb_{{ app.session.get('uploadavatar') }}");
window.parent.$("#user_avatar_img").attr("src","/{{ appAlias }}/uploads/avatar/thumb_{{ app.session.get('uploadavatar') }}");
closeModal();
}
function closeModal() {
window.parent.$("#extraLargeModal").modal('hide');
}
$(document).ready(function() {
window.parent.$(".modal-title").html("ETAPE 2 - Découper votre image");
$('#largeimg').CropSelectJs({
imageSrc: "/{{ appAlias }}/uploads/avatar/{{ app.session.get('uploadavatar') }}",
selectionResize: function(data) { resize(data); },
selectionMove: function(data) { move(data); },
});
$('#largeimg').CropSelectJs('setSelectionAspectRatio',1);
});
{% endblock %}

View File

@@ -0,0 +1,71 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
CLIENT
{% elseif mode=="update" %}
Modification CLIENT
{% elseif mode=="submit" %}
Création CLIENT
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_customer') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_customer_delete',{'id':customer.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.name) }}
{{ form_row(form.keypass) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#customer_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,81 @@
{% extends "base.html.twig" %}
{% block localstyle %}
td {
padding:5px !important;
}
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
CLIENTS
</h1>
<p><a class="btn btn-success" href={{ path('app_customer_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Clients
</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>
<tr>
<th width="70px" class="no-print no-sort">Action</th>
<th>Nom</th>
<th>Clé</th>
</tr>
</thead>
<tbody>
{% for customer in customers %}
<tr>
<td class="no-print">
<a href="{{path("app_customer_update",{id:customer.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{customer.name}}</td>
<td>
{% if customer.keypass %}
<a href="{{path("app_customer_report",{"key":customer.keypass})}}">{{customer.keypass}}</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').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";
}
{% endblock %}

View File

@@ -0,0 +1,71 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
DOMAINE
{% elseif mode=="update" %}
Modification DOMAINE
{% elseif mode=="submit" %}
Création DOMAINE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_domaine') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_domaine_delete',{'id':domaine.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.category) }}
{{ form_row(form.name) }}
{{ form_row(form.description) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#domaine_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,72 @@
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
DOMAINES
</h1>
<p><a class="btn btn-success" href={{ path('app_domaine_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Domaines
</div>
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
<thead>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th>Catégorie</th>
<th>Nom</th>
</tr>
</thead>
<tbody>
{% for domaine in domaines %}
<tr>
<td class="no-print">
<a href="{{path("app_domaine_update",{id:domaine.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{domaine.category}}</td>
<td>{{domaine.name}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').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";
}
{% endblock %}

View File

@@ -0,0 +1,537 @@
{% 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;
}
.select2-results__group {
font-size:12px !important;
}
.select2-results__option{
font-size: 14px;
padding-left:15px
}
{% endblock %}
{% block body %}
<div id="fullcalendar" style="width:100%; margin-top:10px;"></div>
<div id="modalsubmit" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Création Evènement</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<button onClick="eventSubmit()" class="btn btn-success">Valider</button>
<button onClick="" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
<p></p>
<div class="form-group">
<label class="control-label required" for="usersubmit">
Intervenant<span class="mandatory">*</span>
</label>
<select class="select2entity" id="usersubmit" name="usersubmit">
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_MASTER') or is_granted('ROLE_VALIDATOR')%}
{% for user in app.session.get('users') %}
{% set selected="" %}
{%if user.id==app.session.get('iduser') %}
{% set selected="selected" %}
{% endif %}
<option value="{{user.id}}" {{selected}}>{{user.displayname}}</option>
{% endfor %}
{% else %}
<option value="{{app.user.id}}">{{app.user.displayname}}</option>
{% endif %}
</select>
</div>
<div class="form-group">
<label class="control-label required" for="tasksubmit">
Project<span class="mandatory">*</span>
</label>
<select class="select2entity" id="tasksubmit" name="tasksubmit">
<option></option>
{% for project in projects|sort((a, b) => a.displayname <=> b.displayname) %}
<optgroup label="{{project.displayname}}">
{% for task in project.tasks|sort((a, b) => a.displayname <=> b.displayname) %}
{% if task.active %}
<option value="{{task.id}}">{{task.displayname}}</option>
{% endif %}
{% endfor %}
</optgroup>
{% endfor %}
</select>
</div>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="amsubmit">
<label class="custom-control-label" for="amsubmit">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="apsubmit">
<label class="custom-control-label" for="apsubmit">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="astreinte">
<label class="custom-control-label" for="astreinte">Astreinte</label>
</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">
<label for="description" class="control-label">
Description
</label>
<textarea id="description" id="description" class="form-control" placeholder="Description" style="height:200px">
</textarea>
</div>
<input type="hidden" id="start" name="start" class="form-control" value="">
<input type="hidden" id="end" name="end" class="form-control" value="">
</div>
</div>
</div>
</div>
<div id="modalupdate" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modification Evènement</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<button onClick="eventUpdate()" class="btn btn-success">Valider</button>
<button onClick="" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
<button onClick="eventDelete()" class="btn btn-danger float-right">Supprimer</button>
<p></p>
<div class="form-group">
<label class="control-label required" for="service_name">
Intervenant<span class="mandatory">*</span>
</label>
<select class="select2entity" id="userupdate" name="userupdate">
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_MASTER') or is_granted('ROLE_VALIDATOR')%}
{% for user in users %}
<option value="{{user.id}}">{{user.displayname}}</option>
{% endfor %}
{% else %}
<option value="{{app.user.id}}">{{app.user.displayname}}</option>
{% endif %}
</select>
</div>
<div class="form-group">
<label class="control-label required" for="taskupdate">
Project<span class="mandatory">*</span>
</label>
<select class="select2entity" id="taskupdate" name="taskupdate">
<option></option>
{% for project in projects|sort((a, b) => a.displayname <=> b.displayname) %}
<optgroup label="{{project.displayname}}">
{% for task in project.tasks|sort((a, b) => a.displayname <=> b.displayname) %}
<option value="{{task.id}}">{{task.displayname}}</option>
{% endfor %}
</optgroup>
{% endfor %}
</select>
</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">
<label for="description" class="control-label">
Description
</label>
<textarea id="description" id="description" class="form-control" placeholder="Description" style="height:200px">
</textarea>
</div>
<input type="hidden" id="idevent" name="idevent" class="form-control" value="">
<input type="hidden" id="fgastreinte" name="fgastreinte" class="form-control" value="">
</div>
</div>
</div>
</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) {
// 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 style='margin-top:-12px' 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>");
}
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
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 événement
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 #externaltrip').prop("checked",false);
$("#modalsubmit .alert").remove();
// Formulaire de création d'un évènement
$('#modalsubmit').modal();
}
// Formulaire Modification d'un événement
function eventClick(info) {
if(info.event.extendedProps.editable) {
var id=info.event.id;
var description=info.event.extendedProps.description;
var userid=info.event.extendedProps.userid;
var taskid=info.event.extendedProps.taskid;
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");
$('#taskupdate').val(taskid).trigger("change");
$('#modalupdate #idevent').val(id);
$('#modalupdate #fgastreinte').val(fgastreinte);
$('#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();
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
$('#modalupdate').modal();
}
}
// Création de l'évènement
function eventSubmit() {
$("#modalsubmit .alert").remove();
var error=false;
// Tache obligatoire
if($("#modalsubmit #task").val()=="") {
error=true;
$("#modalsubmit .modal-body").append("<div class='alert alert-danger' style='margin: 5px 0px'>Tâche obligatoire</div>");
}
// AM ou PM obligatoire
if(!$("#modalsubmit #amsubmit").prop("checked")&&!$("#modalsubmit #apsubmit").prop("checked")) {
error=true;
$("#modalsubmit .modal-body").append("<div class='alert alert-danger' style='margin: 5px 0px'>Vous devez choisir un moment de la journée</div>");
}
if(!error) {
$.ajax({
type: "POST",
data: {
iduser: $("#usersubmit").val(),
idtask: $("#tasksubmit").val(),
start: $("#modalsubmit #start").val(),
end: $("#modalsubmit #end").val(),
am: $("#modalsubmit #amsubmit").prop("checked"),
ap: $("#modalsubmit #apsubmit").prop("checked"),
astreinte: $("#modalsubmit #astreinte").prop("checked"),
externaltrip: $("#modalsubmit #externaltrip").prop("checked"),
description: $("#modalsubmit #description").val()
},
url: "{{ path('app_event_submit') }}",
success: function (response) {
response=JSON.parse(response);
if(response.return=="KO") {
$("#modalsubmit .modal-body").append("<div class='alert alert-danger' style='margin: 5px 0px'>"+response.error+"</div>");
}
else {
calendar.refetchEvents();
$('#modalsubmit').modal('hide');
}
}
});
}
}
// Modification de l'évènement
function eventUpdate() {
$("#modalupdate .alert").remove();
$.ajax({
type: "POST",
data: {
idevent: $("#modalupdate #idevent").val(),
iduser: $("#userupdate").val(),
idtask: $("#taskupdate").val(),
am: $("#modalupdate #amupdate").prop("checked"),
ap: $("#modalupdate #apupdate").prop("checked"),
fgastreinte: $("#modalupdate #fgastreinte").val(),
externaltrip: $("#modalupdate #externaltripupdate").prop("checked"),
description: $("#modalupdate #description").val()
},
url: "{{ path('app_event_update') }}",
success: function (response) {
response=JSON.parse(response);
if(response.return=="KO") {
$("#modalupdate .modal-body").append("<div class='alert alert-danger' style='margin: 5px 0px'>"+response.error+"</div>");
}
else {
var event = calendar.getEventById($("#modalupdate #idevent").val());
event.remove();
calendar.addEvent(response);
calendar.render;
$('#modalupdate').modal('hide');
}
}
});
}
// Suppression de l'évènement
function eventDelete() {
$("#modalupdate .alert").remove();
$.ajax({
type: "POST",
data: {
idevent: $("#modalupdate #idevent").val(),
fgastreinte: $("#modalupdate #fgastreinte").val()
},
url: "{{ path('app_event_delete') }}",
success: function (response) {
response=JSON.parse(response);
if(response.return=="KO") {
$("#modalupdate .modal-body").append("<div class='alert alert-danger' style='margin: 5px 0px'>"+response.error+"</div>");
}
else {
var event = calendar.getEventById($("#modalupdate #idevent").val());
event.remove();
$('#modalupdate').modal('hide');
}
}
});
}
// On change astreinte
$("#astreinte").change(function() {
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 %}

View File

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

View File

@@ -0,0 +1,6 @@
{% block body %}
Mois;Jours_facturés;Jour_non_facturés
{% for month, event in events %}
{{month}};{{event.f}};{{event.nf}}
{% endfor %}
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% block body %}
Client;Projet;Proposition;Ref;Qt;PU;Total;
{% for project in projects %}
{% for offer in project.offers %}
{{ project.customer }};{{project.name}};{{offer.name}};{{offer.ref}};{{offer.quantity}};{{offer.pu}};{{offer.total}}
{% endfor %}
{% endfor %}
{% endblock %}

View File

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

View File

@@ -0,0 +1,16 @@
{% block body %}
Client;Projet;Tâche;Activité;Domaine;Nature;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|replace({"&": "et"})}};{{project.service}};{{project.domaine}};{{task.nature}};{{user.displayname}};{{week.isoyear}};{{week.isoweek}};{{user.cumul|replace({".": ","})}};
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
{% endblock %}

View File

@@ -0,0 +1,56 @@
{% 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>
<div class="card">
<div class="card-header">
<a class="btn btn-success" href={{ path('export_offers') }}>Export des commandes</a>
</div>
<div class="card-body">
<p>Exporter la liste des commandes</p>
<p>Filtres utiles : Projet, Service</p>
</div>
</div>
<p></p>
<div class="card">
<div class="card-header">
<a class="btn btn-success" href={{ path('export_month_charged_days') }}>Export des jours facturés/non-facturés</a>
</div>
<div class="card-body">
<p>Exporter la liste du nombre de jours facturés et non-facturés par mois</p>
<p>Filtres utiles : Nombre de mois</p>
</div>
</div>
<p></p>
{% endblock %}

View File

@@ -0,0 +1,175 @@
{% extends 'form_div_layout.html.twig' %}
{# Voir https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig #}
{# On commence par simplement ajouter le form-group au row de nos formulaires #}
{% block form_row -%}
{% set attr = attr|merge({'help': (attr.help|default(true)) }) %}
<div class="form-group {{ errors|length > 0 ? 'has-error' : '' }}">
{{- form_label(form) }}
{{- form_widget(form) }}
{{ form_errors(form) }}
</div>
{%- endblock form_row %}
{# Puis on modifie très simplement nos input et textarea
les plus importants pour y ajouter le class imposée par Bootstrap 3 #}
{% block textarea_widget %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' form-control'}) %}
{{ parent() }}
{% endblock textarea_widget %}
{% block form_widget_simple %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' form-control'}) %}
{{ parent() }}
{% endblock form_widget_simple %}
{% block form_label -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' control-label')|trim}) %}
{% if 'checkbox' not in block_prefixes %}
{% if label is not same as(false) -%}
{% if not compound -%}
{% set label_attr = label_attr|merge({'for': id}) %}
{%- endif %}
{% if required -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif %}
{% if label is empty -%}
{% set label = name|humanize %}
{%- endif -%}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ label|trans({}, translation_domain)|raw }}
<span class="mandatory">{% if required %}*{% endif %}</span>
</label>
{%- endif %}
{% endif %}
{%- endblock form_label %}
{# et enfin les erreurs #}
{% block form_errors %}
{% if errors|length > 0 %}
{% if attr.help is defined and attr.help %}
<p class="help-block text-danger">
{% for error in errors %}
{{ error.message }}<br />
{% endfor %}
</p>
{% else %}
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
{% for error in errors %}
{{ error.message|raw }}<br />
{% endfor %}
</div>
{% endif %}
{% endif %}
{% endblock form_errors %}
{# Personnalisation des boutons #}
{% block button_widget -%}
{% if label is empty -%}
{% set label = name|humanize %}
{%- endif -%}
{% set attr = attr|merge({'class': (attr.class|default('') ~ '')|trim}) %}
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{
label|trans({}, translation_domain) }}
{% if type is defined and type == 'submit' -%}
{% endif %}
</button>
{%- endblock button_widget %}
{# Personnalisation des attributs des boutons #}
{% block button_attributes -%}
{% if type is defined and type == 'submit' -%}
{% set class = 'btn-primary' %}
{% else %}
{% set class = 'btn-default' %}
{%- endif -%}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' btn ' ~ class)|trim}) %}
{{ parent() }}
{%- endblock button_attributes %}
{# Personnalisation des select #}
{% block choice_widget_collapsed %}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control')|trim}) %}
{{ parent() }}
{%- endblock choice_widget_collapsed %}
{% block choice_widget %}
{% if expanded %}
<ul {{ block('widget_container_attributes') }} style="list-style: none; padding-left: 0">
{% for child in form %}
<li>
{{ form_widget(child) }}
{{ form_label(child) }}
</li>
{% endfor %}
</ul>
{% else %}
{{ parent() }}
{% endif %}
{% endblock choice_widget %}
{% block checkbox_widget %}
<label for="{{ id }}">
<input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
{{ label|trans({}, translation_domain) }}</label>
{% endblock checkbox_widget %}
{% block radio_widget %}
<label for="{{ id }}">
<input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
{{ label|trans({}, translation_domain) }}
</label>&nbsp;&nbsp;
{% endblock radio_widget %}
{# Inline date marcro #}
{% macro date_form_widget(form) %}
<div class="col col-xs-4">
{{ form_widget(form) }}
</div>
{% endmacro %}
{# Inline date #}
{% block date_widget %}
{% if widget == 'single_text' %}
{{ block('form_widget_simple') }}
{% else %}
{% import _self as self %}
<div class="row">
{{ date_pattern|replace({
'{{ year }}': self.date_form_widget(form.year),
'{{ month }}': self.date_form_widget(form.month),
'{{ day }}': self.date_form_widget(form.day),
})|raw }}
</div>
{% endif %}
{% endblock date_widget %}
{# Inline date_time
{% block time_widget %}
{% if widget == 'single_text' %}
{{ block('form_widget_simple') }}
{% else %}
{% import _self as self %}
<div class="row">
{{ time_pattern|replace({
'{{ hour }}': self.date_form_widget(form.hour),
'{{ minute }}': self.date_form_widget(form.minute),
})|raw }}
</div>
{% endif %}
{% endblock time_widget %}
#}
{% block file_widget %}
{% set type = type|default('file') %}
<input type="{{ type }}" {{ block('widget_attributes') }} />
{% endblock file_widget %}

View File

@@ -0,0 +1,7 @@
{% extends "CRWhizBundle::base.html.twig" %}
{% block body %}
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% extends "base.html.twig" %}
{% block body %}
<center>Merci d'utiliser l'URL qui vous a été communiquée pour visualiser votre rapport.</center>
{% endblock %}

View File

@@ -0,0 +1,16 @@
{% extends "base.html.twig" %}
{% block localstyle %}
body {
background-color: #efefef;
}
.homecard {
padding-top: 20px;
}
{% endblock %}
{% block body %}
{% endblock %}

36
templates/Home/login.html.twig Executable file
View File

@@ -0,0 +1,36 @@
{% extends "base.html.twig" %}
{% block localstyle %}
body {
background-color: #efefef;
}
.homecard {
padding-top: 20px;
}
{% endblock %}
{% block body %}
<div style="text-align:center">
<img src="/{{appAlias}}/images/logo.png" style="height:120px;margin-top:10px;"><br>
<h1>{{appName}}</h1>
<form action="{{ path('app_login') }}" method="post">
<div class="card homecard" style="width:400px; margin:auto">
<div class="card-body">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<label for="username">Login</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" class="form-control" style="margin-bottom:15px;" />
<label for="password">Password</label>
<input type="password" id="password" name="_password" class="form-control" style="margin-bottom:15px;" />
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<input type="submit" name="login" class="btn btn-success form-control" />
</div>
</div>
</form>
</div>
{% endblock %}

72
templates/Job/edit.html.twig Executable file
View File

@@ -0,0 +1,72 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
METIER
{% elseif mode=="update" %}
Modification METIER
{% elseif mode=="submit" %}
Création METIER
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_job') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_job_delete',{'id':job.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.name) }}
{{ form_row(form.type) }}
{{ form_row(form.description) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#job_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,77 @@
{% extends "base.html.twig" %}
{% block localstyle %}
td {
padding:5px !important;
}
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
METIERS
</h1>
<p><a class="btn btn-success" href={{ path('app_job_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Métiers
</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>
<tr>
<th width="70px" class="no-print no-sort">Action</th>
<th>Type</th>
<th>Nom</th>
</tr>
</thead>
<tbody>
{% for job in jobs %}
<tr>
<td class="no-print">
<a href="{{path("app_job_update",{id:job.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{job.type}}</td>
<td>{{job.name}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').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";
}
{% endblock %}

62
templates/Nature/edit.html.twig Executable file
View File

@@ -0,0 +1,62 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if mode=="update" %}
Modification NATURE
{% elseif mode=="submit" %}
Création NATURE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_nature') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_nature_delete',{'id':nature.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.name) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#nature_name").focus();
});
{% endblock %}

View File

@@ -0,0 +1,70 @@
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
NATURES
</h1>
<p><a class="btn btn-success" href={{ path('app_nature_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Natures
</div>
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
<thead>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th>Nom</th>
</tr>
</thead>
<tbody>
{% for nature in natures %}
<tr>
<td class="no-print">
<a href="{{path("app_nature_update",{id:nature.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{nature.name}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').DataTable({
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
responsive: true,
iDisplayLength: 100,
order: [[ 2, "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";
}
{% endblock %}

View 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> <a href="{{ valid_link }}">{{ valid_link }}</a>
</p>
{% endautoescape %}
{% endblock %}

View 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 %}

View File

@@ -0,0 +1,116 @@
{% extends 'base.html.twig' %}
{% block body %}
<h1 class="page-header">
Récupération Commande Client Dolibarr
</h1>
<a class="btn btn-secondary" href={{ path('app_offer') }}>Annuler</a>
<br><br>
<div class="card">
<div class="card-header">
<i class="fa fa-pencil-alt fa-fw"></i> Informations
</div>
<div class="card-body">
<div class="form-group ">
<label class="control-label required" for="id">ID Proposition<span class="mandatory">*</span></label>
<input type="text" id="ref" name="ref" required="required" class=" form-control" value="CO2311-0222">
<button id="search" class="btn btn-success mt-1" style="width:100%">Rechercher</span>
</div>
</div>
</div>
<div id="card-propal" class="card mt-3" style="display:none">
<div class="card-header">
<i class="fa fa-pencil-alt fa-fw"></i> Lignes propositions
</div>
<div class="card-body" id="propal">
</div>
</div>
<div id="card-offer" class="card mt-3 mb-3" style="display:none">
<div class="card-header">
<i class="fa fa-pencil-alt fa-fw"></i> Importer dans Schedule
</div>
<div class="card-body" id="propal">
{{ form_start(form) }}
{{ form_row(form.name) }}
{{ form_row(form.project) }}
{{ form_widget(form.submit) }}
{{ form_end(form) }}
</div>
</div>
{% endblock %}
{% block localjavascript %}
$("#search").click(function() {
console.log("search propositions = "+$("#ref").val());
$.ajax({
type: "POST",
data: {
ref: $("#ref").val(),
},
url: "{{ path('app_offer_getdolibarr') }}",
success: function (datas) {
console.log(datas);
console.log("-----------");
if(datas.error||Object.keys(datas).length === 0) {
$("#propal").html("");
$("#card-propal").hide();
$("#card-offer").hide();
}
else {
html ="<h3>"+$("#ref").val()+"</h3>";
if(datas.note_public) html+="<strong>Note public</strong><br><small style='display: block;line-height: 14px;'>"+datas.note_public.replace(/(\r\n|\r|\n)/g, '<br>')+"</small><br><br>";
if(datas.note_private) html+="<strong>Note privée</strong><br><small style='display: block;line-height: 14px;'>"+datas.note_private.replace(/(\r\n|\r|\n)/g, '<br>')+"</small><br><br>";
tbtask={};
datas.lines.forEach(function(line){
console.log(line);
if(!tbtask[line.product_ref]) tbtask[line.product_ref]={idoffer:"", idline: "", ref: "", label: "", qty: 0, price:0 };
tbtask[line.product_ref]["idoffer"]=$("#ref").val();
tbtask[line.product_ref]["idline"]=line.id;
tbtask[line.product_ref]["ref"]=line.product_ref;
tbtask[line.product_ref]["label"]=line.product_label;
tbtask[line.product_ref]["qty"]=parseInt(line.qty)+tbtask[line.product_ref]["qty"];
tbtask[line.product_ref]["price"]=parseInt(line.price);
});
html+="<table style='width:100%;'>";
html+="<thead><tr>";
html+="<th>Ref</th>";
html+="<th>Designation</th>";
html+="<th>Qte</th>";
html+="<th>PU</th>";
html+="<th>Total</th>";
html+="</tr></thead>";
Object.values(tbtask).forEach(task => {
html+="<tr>";
html+="<td>"+task.ref+"</td>";
html+="<td>"+task.label+"</td>";
html+="<td>"+task.qty+"</td>";
html+="<td>"+task.price+"</td>";
html+="<td>"+(task.qty*task.price)+"</td>";
html+="</tr>";
});
html+="</table>";
$("#propal").html(html);
$("#card-propal").show();
$("#card-offer").show();
$("#offerdolibarr_tasks").val(JSON.stringify(tbtask));
}
}
});
});
{% endblock %}

78
templates/Offer/edit.html.twig Executable file
View File

@@ -0,0 +1,78 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
COMMANDE
{% elseif mode=="update" %}
Modification COMMANDE
{% elseif mode=="submit" %}
Création COMMANDE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_offer') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_offer_delete',{'id':offer.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.name) }}
{{ form_row(form.ref) }}
{{ form_row(form.service) }}
{{ form_row(form.project) }}
{{ form_row(form.quantity) }}
{{ form_row(form.pu) }}
{{ form_row(form.validate) }}
{{ form_row(form.cost) }}
{{ form_row(form.active) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#offer_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,187 @@
{% extends "base.html.twig" %}
{% block localstyle %}
td {
padding:5px !important;
}
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
COMMANDES {% if app.session.get('viewservice') %}PAR ACTVITE{%else%}PAR DOMAINE{%endif%}
</h1>
<a class="btn btn-success" href={{ path('app_offer_submit') }}>Ajouter</a>
{% if doliactive == "true" %}
<a class="btn btn-success" href={{ path('app_offer_dolibarr') }}>Récupérer les commandes de Dolibarr</a>
{% endif %}
<div class="custom-control custom-switch float-right">
<input type="checkbox" class="custom-control-input" id="switchactiveproject" {% if app.session.get('activeproject') %} checked {% endif %}>
<label class="custom-control-label" for="switchactiveproject">Projet Actif</label>
</div>
<div class="custom-control custom-switch float-right" style="margin-right:10px">
<input type="checkbox" class="custom-control-input" id="switchactiveoffer" {% if app.session.get('activeoffer') %} checked {% endif %}>
<label class="custom-control-label" for="switchactiveoffer">Proposition Active</label>
</div>
<div class="custom-control custom-switch float-right mr-3">
<input type="checkbox" class="custom-control-input" id="switchservice" {% if app.session.get('viewservice') %} checked {% endif %}>
{% if app.session.get('viewservice') %}
<label class="custom-control-label" for="switchservice">Vue par Activité</label>
{% else %}
<label class="custom-control-label" for="switchservice">Vue par Domaine</label>
{% endif %}
</div>
<p></p>
{% if app.session.get('viewservice') %}
{% set loop01s=services %}
{% else %}
{% set loop01s=domaines %}
{% endif %}
{%for loop01 in loop01s %}
{% if not loop01.projects is empty %}
{% set haveoffer=false %}
{% set haveproject=false %}
{% for offer in loop01.offers %}
{% if app.session.get('activeoffer')==offer.active and app.session.get('activeproject')==offer.project.active and (app.session.get('idproject')=="all" or app.session.get('idproject')==offer.project.id) %}
{% set haveoffer=true %}
{% set haveproject=true %}
{% endif %}
{% endfor %}
{% if haveoffer and haveproject %}
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> {{ loop01.name }}
</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>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th width="200px">Client</th>
<th>Projet</th>
<th width="100px">Proposition</th>
<th width="100px">Ref</th>
<th width="70px" class="text-center no-string">Validé hors</th>
<th width="70px" class="text-center no-string">Frais</th>
<th width="70px" class="text-center no-string">Qt</th>
<th width="70px" class="text-center no-string">PU</th>
<th width="100px" class="text-center no-string">Total</th>
</tr>
</thead>
<tbody>
{% if loop01.offers is defined %}
{% for offer in loop01.offers %}
{% if app.session.get('activeoffer')==offer.active and app.session.get('activeproject')==offer.project.active and (app.session.get('idproject')=="all" or app.session.get('idproject')==offer.project.id) %}
<tr>
<td class="no-print">
<a href="{{path("app_offer_update",{id:offer.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{offer.project.customer.name}}</td>
<td>{{offer.project.name}}</td>
<td>{{offer.name}}</td>
{% if offer.iddolibarr %}
<td><a href="{{doliUri}}/commande/card.php?ref={{offer.ref}}" target="_blank">{{offer.ref}}</td>
{% else %}
<td>{{offer.ref}}</td>
{% endif %}
<td class="text-right">{{offer.validate|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.cost|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.quantity|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.pu|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.total|number_format(2, '.', ' ')}}</td>
</tr>
{%endif%}
{% endfor %}
{% else %}
{% for project in loop01.projects %}
{% for offer in project.offers %}
{% if app.session.get('activeoffer')==offer.active and app.session.get('activeproject')==offer.project.active and (app.session.get('idproject')=="all" or app.session.get('idproject')==offer.project.id) %}
<tr>
<td class="no-print">
<a href="{{path("app_offer_update",{id:offer.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{offer.project.customer.name}}</td>
<td>{{offer.project.name}}</td>
<td>{{offer.name}}</td>
{% if offer.iddolibarr %}
<td><a href="{{doliUri}}/commande/card.php?ref={{offer.ref}}" target="_blank">{{offer.ref}}</td>
{% else %}
<td>{{offer.ref}}</td>
{% endif %}
<td class="text-right">{{offer.validate|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.cost|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.quantity|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.pu|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{offer.total|number_format(2, '.', ' ')}}</td>
</tr>
{%endif%}
{% endfor %}
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
<br>
{% endif %}
{% endif %}
{% endfor %}
{% 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";
}
$('#switchactiveproject').change(function() {
window.location="{{ path('app_offer_activeproject' )}}";
});
$('#switchactiveoffer').change(function() {
window.location="{{ path('app_offer_activeoffer' )}}";
});
$('#switchservice').change(function() {
window.location="{{ path('app_offer_viewservice' )}}";
});
{% endblock %}

View File

@@ -0,0 +1,76 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
PROJET
{% elseif mode=="update" %}
Modification PROJET
{% elseif mode=="submit" %}
Création PROJET
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_project') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_project_delete',{'id':project.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.name) }}
{{ form_row(form.active) }}
{{ form_row(form.customer) }}
{{ form_row(form.visible) }}
{{ form_row(form.service) }}
{{ form_row(form.domaine) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$("#project_customer").addClass("select2entity");
$(document).ready(function() {
$("#project_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,182 @@
{% extends "base.html.twig" %}
{% block localstyle %}
td {
padding:5px !important;
}
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
PROJETS {% if app.session.get('viewservice') %} PAR ACTVITE{%else%} PAR DOMAINE{%endif%}
</h1>
<a class="btn btn-success" href={{ path('app_project_submit') }}>Ajouter</a>
<div class="custom-control custom-switch float-right">
<input type="checkbox" class="custom-control-input" id="switchactive" {% if app.session.get('activeproject') %} checked {% endif %}>
<label class="custom-control-label" for="switchactive">Projet Actif</label>
</div>
<div class="custom-control custom-switch float-right mr-3">
<input type="checkbox" class="custom-control-input" id="switchservice" {% if app.session.get('viewservice') %} checked {% endif %}>
{% if app.session.get('viewservice') %}
<label class="custom-control-label" for="switchservice">Vue par Activité</label>
{% else %}
<label class="custom-control-label" for="switchservice">Vue par Domaine</label>
{% endif %}
</div>
<p></p>
{% if app.session.get('viewservice') %}
{% set loop01s=services %}
{% else %}
{% set loop01s=domaines %}
{% endif %}
{%for loop01 in loop01s %}
{% if not loop01.projects is empty %}
{% set haveproject=false %}
{% for project in loop01.projects %}
{% if app.session.get('activeproject')==project.active and (app.session.get('idproject')=="all" or app.session.get('idproject')==project.id) %}
{% set haveproject=true %}
{% endif %}
{% endfor %}
{% if haveproject %}
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> {{ loop01.name }}
</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>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th width="200px">Client</th>
<th>Nom</th>
<th width="200px">{% if app.session.get('viewservice') %}Domaine{%else%}Activité{%endif%}</th>
<th width="100px" class="text-center no-string">Estimé</th>
<th width="100px" class="text-center no-string">Commandé</th>
<th width="100px" class="text-center no-string">Validé</th>
<th width="100px" class="text-center no-string">Solde Validé</th>
<th width="100px" class="text-center no-string">Plannifié</th>
<th width="100px" class="text-center no-string">Solde</th>
</tr>
</thead>
<tbody>
{% for project in loop01.projects %}
{% if app.session.get('activeproject')==project.active and (app.session.get('idproject')=="all" or app.session.get('idproject')==project.id) %}
<tr>
<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_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>{{project.customer.name}}</td>
<td>{{project.name}}</td>
<td>{% if app.session.get('viewservice') %}{{project.domaine.name}}{%else%}{{project.service.name}}{%endif%}</td>
<td class="text-right">
{% set tottask=0 %}
{% set totvalidate=0 %}
{% set totplanified=0 %}
{% set totoffer=0 %}
{% for offer in project.offers %}
{% set totoffer=(totoffer+offer.quantity) %}
{% set totvalidate=totvalidate+offer.validate %}
{% set totplanified=totplanified+offer.validate %}
{% endfor %}
{% for task in project.tasks %}
{% set tottask=tottask+task.quantity %}
{% for event in task.events %}
{% set totplanified=totplanified+event.duration %}
{% if event.validate %}
{% set totvalidate=totvalidate+event.duration %}
{% endif %}
{% endfor %}
{% for penalty in task.penaltys %}
{% set totplanified=totplanified+penalty.duration %}
{% if penalty.validate %}
{% set totvalidate=totvalidate+penalty.duration %}
{% endif %}
{% endfor %}
{% endfor %}
{{ tottask|number_format(2, '.', ' ') }}
</td>
<td class="text-right">
{{ totoffer|number_format(2, '.', ' ') }}
</td>
<td class="text-right">{{ (totvalidate*-1)|number_format(2, '.', ' ') }}</td>
<td class="text-right">{{ (totoffer-totvalidate)|number_format(2, '.', ' ') }}</td>
<td class="text-right">{{ ((totplanified-totvalidate)*-1)|number_format(2, '.', ' ') }}</td>
<td class="text-right">{{ (totoffer-totplanified)|number_format(2, '.', ' ') }}</td>
</tr>
{%endif%}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<br>
{% endif %}
{% endif %}
{% endfor %}
{% endblock %}
{% block localjavascript %}
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
$(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 %}
});
$('#switchactive').change(function() {
window.location="{{ path('app_project_activeproject' )}}";
});
$('#switchservice').change(function() {
window.location="{{ path('app_project_viewservice' )}}";
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,210 @@
{% extends "base.html.twig" %}
{% block localstyle %}
td {
padding:5px !important;
}
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
PROJET METIERS<br>
{{project.displayname}}
</h1>
<a class="btn btn-secondary" href={{ path('app_project') }}>Fermer</a>
<p></p>
<div class="row" style="margin: 0px">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Utilisateurs
</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>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th>Nom</th>
</tr>
</thead>
<tbody>
{%for user in users %}
{% if "ROLE_USER" in user.roles %}
<tr>
<td class="no-print">
<button class="btn btn-link" onClick="modalJob({{user.id}})"><i class="fa fa-plus"></i></a>
</td>
<td>{{user.displayname}}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="col-md-6">
{% for userproject in userprojects %}
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> {{ userproject.name }}
</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>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th>Nom</th>
</tr>
</thead>
<tbody>
{%for user in userproject.users %}
<tr>
<td class="no-print">
<button class="btn btn-link" onClick="delJob({{user.id}})"><i class="fa fa-minus"></i></a>
</td>
<td>{{user.user.displayname}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<br>
{% endfor %}
</div>
</div>
<div id="modaljob" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Métier</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<button onClick="addJob()" class="btn btn-success">Valider</button>
<button onClick="" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
<p></p>
<div class="form-group">
<label class="control-label required" for="idjob">
Métier<span class="mandatory">*</span>
</label>
<select class="select2entity" id="idjob" name="idjob">
<option></option>
{% for job in jobs %}
<option value="{{job.id}}">{{job.name}}</option>
{% endfor %}
</select>
</div>
<input type="hidden" id="iduser" name="iduser" class="form-control" value="">
</div>
</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" ]],
searching: false,
paging: false,
info: false
});
{%else%}
$('#dataTables').removeClass("table table-striped table-bordered table-hover small dataTable no-footer");
{% endif %}
});
function modalJob(iduser) {
$("#iduser").val(iduser);
$("#modaljob .alert").remove();
$("#modaljob").modal('show');
}
function addJob() {
$("#modaljob .alert").remove();
iduser=$("#iduser").val();
idjob=$("#idjob").val();
if(idjob) {
$.ajax({
type: "POST",
data: {
idproject: {{project.id}},
idjob: idjob,
iduser: iduser,
},
url: "{{ path('app_project_users_add') }}",
success: function (response) {
response=JSON.parse(response);
if(response.return=="KO") {
$("#modaljob .modal-body").append("<div class='alert alert-danger' style='margin: 5px 0px'>"+response.error+"</div>");
}
else {
location.reload();
}
}
});
}
}
function delJob(iduser) {
$.ajax({
type: "POST",
data: {
iduser: iduser,
},
url: "{{ path('app_project_users_del') }}",
success: function (response) {
response=JSON.parse(response);
if(response.return=="KO") {
}
else {
location.reload();
}
}
});
}
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,103 @@
{% 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">
MES CONGES
</h1>
<div class="custom-control custom-switch float-right">
<input type="checkbox" class="custom-control-input" id="switchactive" {% if app.session.get('activeholiday') %} checked {% endif %}>
<label class="custom-control-label" for="switchactive">Congès à Valider</label>
</div>
<div style="height:30px;">
</div>
<div class="card homecard">
<div class="card-header">
Mes Congés
</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>Utilisateur</th>
<th>Tâche</th>
<th>Début</th>
<th>Fin</th>
<th>Durée</th>
</thead>
{% for user in users %}
{% for event in user.holidays %}
<tr id="row-{{event.id}}">
<td>
{{ user.user.displayname }}
</td>
<td>
{{ event.task }}
</td>
<td>
{{ event.start|date("d/m/Y H:i") }}
</td>
<td>
{{ event.end|date("d/m/Y H:i") }}
</td>
<td>
{{ event.duration }}
</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: [[ 0, "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";
}
$('#switchactive').change(function() {
window.location="{{ path('app_holiday_activeholiday' )}}";
});
{% endblock %}

View File

@@ -0,0 +1,192 @@
{% extends "base.html.twig" %}
{% block localstyle %}
.card {
margin: 20px 20px 0px 0px;
}
.card-body .month {
margin: 20px 0px 0px 0px;
}
.card-body .month:first-child {
margin: 0px;
}
.card-header h2 {
float:left;
}
.card-header .synthese {
float:right;
font-size:12px;
text-align: right;
}
th,td {
border: 1px solid #37474F;
color: #000000;
background-color:#cccccc;
}
.intervenant {
width:200px;
padding-left:5px;
}
.total {
text-align:center;
width:70px;
background-color:#888888;
}
.day {
text-align:center;
width: 40px;
height:40px;
}
.astreinte {
height: 12px;
font-size: 10px;
}
{% if fgprint is defined and fgprint %}
h2, h3 {
display:block !important;
float:none !important;
}
table { width:100%; font-size:10px;}
.card-header .synthese {
float:none !important;
text-align:left !important;
}
.day {
height:auto !important;
}
{% endif %}
{% endblock %}
{% block body %}
{% if fgprint is defined and fgprint %}<h1>Planning</h1>{%endif%}
{% if access=="customer" and not app.user %}
<div class="no-print" style="margin-top:10px;">
<style> .select2-container { display:inline-block} </style>
<a class="btn btn-info" href="{{ path("app_customer_report",{"key":key})}}">Rapport</a>
<a class="btn btn-success" href="{{ path("app_customer_planning",{"key":key})}}">Planning</a>
&nbsp;&nbsp;Nombre de mois
<select class="form-control select2entity" id="sidemonth" name="sidemonth" style="width:auto; display:inline-block">
{% set selected="" %}
{% for i in 1..48 %}
{% set selected="" %}
{%if i==app.session.get('nbmonth') %}
{% set selected="selected" %}
{% endif %}
<option value="{{i}}" {{selected}}>{{i}}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% for project in projects %}
{% if not project.months is empty %}
<div class="card">
<div class="card-header">
<h2>{{ project.displayname }}</h2>
<div class="synthese">
Estimé = {{ project.estimate }}<br>
Commandé = {{ project.proposed }}<br>
Validé = {{ project.validate }}<br>
Planifié = {{ project.planified }}<br>
<b>RESTE = {{ ( project.proposed - project.validate - project.planified) }}</b>
</div>
</div>
<div class="card-body">
{% set month="" %}
{% for month in project.months %}
<h3 class="month">{{ month.monthlabel }}</h3>
<table>
<thead>
<th class="intervenant">Intervenant</th>
{% for day in month.days %}
<th class="day" style="background-color: {{ day.daycolor }}">
{{ day.daylabel }}<br>
{{ day.daynumber }}
</th>
{% endfor %}
<th class="total">Total</th>
</thead>
{% for user in month.users %}
<tr>
<td class="intervenant">{{ user.displayname }}</td>
{% for day in user.days %}
<td class="day" style="background-color: {{ day.daycolor }}">
{% if day.duration > 0 %}
{{ day.duration }}
{% endif %}
{% if day.astreinte > 0 %}
<div class="astreinte">A</div>
{% endif %}
</td>
{% endfor %}
<td class="total">{{user.total}}</td>
</tr>
{% endfor %}
</table>
{% if month.total > 0 %}
<br>
<table class="recaptask small">
{% for task in month.tasks %}
<tr>
<td>{{ task.displayname }}</td>
<td class="text-right">{{ task.duration|number_format(2, '.', ' ') }}</td>
</tr>
{% endfor %}
{% if month.totala > 0 %}
<tr>
<td>Astreinte</td>
<td class="text-right">{{ month.totala|number_format(2, '.', ' ') }}</td>
</tr>
{% endif %}
<tfoot>
<tr>
<td style="min-width:200px">TOTAL</td>
<td class="text-right" style="min-width:100px">{{ (month.total + month.totala)|number_format(2, '.', ' ') }}</td>
</tr>
</tfoot>
</table>
{% endif %}
{% if month.total > 0 %}
<i>Total = {{ month.total }}</i>
{% endif %}
{% if month.totala > 0 %}
<i>Total Astreinte = {{ month.totala }}</i>
{% endif %}
<div class="new-page">&nbsp;</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
<br>
{% endblock %}
{% block localjavascript %}
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,391 @@
{% extends "base.html.twig" %}
{% block localstyle %}
.card {
margin: 20px 20px 0px 0px;
}
.card-body .month {
margin: 20px 0px 0px 0px;
}
.card-body .month:first-child {
margin: 0px;
}
.card-header h2 {
float:left;
}
.card-header .synthese {
float:right;
font-size:12px;
text-align: right;
}
.card-body h4 { margin: 20px 0px 0px 0px;}
.card-body h4:first-child { margin: 0px;}
th,td, tfoot {
border: 1px solid #37474F;
color: #000000;
background-color:#cccccc;
}
.recaptask td, .recapoffer td {
background-color:#ffffff;
color: #212529;
padding: 3px;
}
.recaptask tfoot td, .recapoffer thead td, .recapoffer tfoot td {
background-color:#cccccc;
font-weight: bold;
}
.intervenant {
width:200px;
padding-left:5px;
}
.total {
text-align:center;
width:70px;
background-color:#888888;
}
.day {
text-align:center;
width: 40px;
height:40px;
}
.astreinte {
height: 12px;
font-size: 10px;
}
{% if fgprint is defined and fgprint %}
h2, h3 {
display:block !important;
float:none !important;
margin:0px;
}
table { width:100%; font-size:10px;}
.card-header .synthese {
float:none !important;
text-align:left !important;
}
.day {
height:auto !important;
}
.small { font-size:10px;}
h4 {
padding-top: 20px;
}
{% endif %}
{% endblock %}
{% block body %}
{% if fgprint is defined and fgprint %}<h1>Planning</h1>{%endif%}
{% if access=="customer" and not app.user %}
<div class="no-print" style="margin-top:10px;">
<style> .select2-container { display:inline-block} </style>
<a class="btn btn-success" href="{{ path("app_customer_report",{"key":key})}}">Rapport</a>
<a class="btn btn-info" href="{{ path("app_customer_planning",{"key":key})}}">Planning</a>
&nbsp;&nbsp;Nombre de mois
<select class="form-control select2entity" id="sidemonth" name="sidemonth" style="width:auto; display:inline-block">
{% set selected="" %}
{% for i in 1..48 %}
{% set selected="" %}
{%if i==app.session.get('nbmonth') %}
{% set selected="selected" %}
{% endif %}
<option value="{{i}}" {{selected}}>{{i}}</option>
{% endfor %}
</select>
</div>
{% endif %}
{% for project in projects %}
{% if not project.months is empty or project.hors!=0 or not project.before is empty or not project.beforeastreinte is empty %}
<div class="card">
<div class="card-header">
<h2>{{ project.displayname }}</h2>
<div class="synthese">
Commandé = {{ project.proposed|number_format(2, '.', ' ') }}<br>
Consommé = {{ project.validate|number_format(2, '.', ' ') }}<br>
<b>RESTE = {{ (project.proposed - project.validate)|number_format(2, '.', ' ') }}</b>
</div>
</div>
<div class="card-body">
<h3>RAPPORT</h3>
<div class="small">
{% for month in project.months %}
<h3 class="month">{{ month.monthlabel }}</h3>
<table>
<thead>
<th class="intervenant">Intervenant</th>
{% for day in month.days %}
<th class="day" style="background-color: {{ day.daycolor }}">
{{ day.daylabel }}<br>
{{ day.daynumber }}
</th>
{% endfor %}
<th class="total">Total</th>
</thead>
{% for user in month.users %}
<tr>
<td class="intervenant">{{ user.displayname }}</td>
{% for day in user.days %}
<td class="day" style="background-color: {{ day.daycolor }}">
{% if day.duration > 0 %}
{{ day.duration }}
{% endif %}
{% if day.astreinte > 0 %}
<div class="astreinte">A</div>
{% endif %}
</td>
{% endfor %}
<td class="total">{{user.total}}</td>
</tr>
{% endfor %}
</table>
{% if month.total > 0 %}
<br>
<table class="recaptask small">
{% for task in month.tasks %}
<tr>
<td>{{ task.displayname }}</td>
<td class="text-right">{{ task.duration|number_format(2, '.', ' ') }}</td>
</tr>
{% endfor %}
{% if month.totala > 0 %}
<tr>
<td>Astreinte</td>
<td class="text-right">{{ month.totala|number_format(2, '.', ' ') }}</td>
</tr>
{% endif %}
<tfoot>
<tr>
<td style="min-width:200px">TOTAL</td>
<td class="text-right" style="min-width:100px">{{ (month.total + month.totala)|number_format(2, '.', ' ') }}</td>
</tr>
</tfoot>
</table>
{% endif %}
{% 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>
{% if not project.offers is empty %}
<h4>COMMANDES</h4>
{% set count=(project.offers|length)-8 %}
{% set totbefore10=0 %}
{% set decoproposed=project.proposed %}
{% set decovalidate=project.validate %}
<table class="recapoffer small">
<thead>
<td width="200px">Libellé</td>
<td width="200px">Référence</td>
<td width="100px" class="text-center">Commandé</td>
<td width="100px" class="text-center">Consommé</td>
<td width="100px" class="text-center">Reste</td>
</thead>
{% set tot=0 %}
{% for offer in project.offers %}
{% if loop.index<count %}
{% set totbefore10=totbefore10+offer.quantity %}
{% if loop.index+1==count %}
<tr>
<td colspan="2">Précédente</td>
<td class="text-right">{{ totbefore10|number_format(2, '.', ' ') }}</td>
<td class="text-right">
{% if decovalidate >= totbefore10 %}
{{ totbefore10|number_format(2, '.', ' ') }}
{% set todel=totbefore10 %}
{% else %}
{% if decovalidate >= 0 %}
{{ decovalidate|number_format(2, '.', ' ') }}
{% set todel=decovalidate %}
{% else %}
0.00
{% set todel=0 %}
{% endif %}
{% endif %}
{% set decovalidate=decovalidate-totbefore10 %}
</td>
<td class="text-right">
{{ (totbefore10-todel)|number_format(2, '.', ' ') }}
{% set decoproposed=decoproposed-totbefore10 %}
</td>
</tr>
{% endif %}
{% else %}
{% if not loop.last %}
<tr>
<td>{{ offer.name }}</td>
<td>{{ offer.ref }}</td>
<td class="text-right">{{ offer.quantity|number_format(2, '.', ' ') }}</td>
<td class="text-right">
{% if decovalidate >= offer.quantity %}
{{ offer.quantity|number_format(2, '.', ' ') }}
{% set todel=offer.quantity %}
{% else %}
{% if decovalidate >= 0 %}
{{ decovalidate|number_format(2, '.', ' ') }}
{% set todel=decovalidate %}
{% else %}
0.00
{% set todel=0 %}
{% endif %}
{% endif %}
{% set decovalidate=decovalidate-offer.quantity %}
</td>
<td class="text-right">
{{ (offer.quantity-todel)|number_format(2, '.', ' ') }}
{% set decoproposed=decoproposed-totbefore10 %}
</td>
</tr>
{% else %}
<tr>
<td>{{ offer.name }}</td>
<td>{{ offer.ref }}</td>
<td class="text-right">{{ offer.quantity|number_format(2, '.', ' ') }}</td>
<td class="text-right">
{% if decovalidate >= 0 %}
{{ decovalidate|number_format(2, '.', ' ') }}
{% set todel=decovalidate %}
{% else %}
0.00
{% set todel=0 %}
{% endif %}
{% set decovalidate=decovalidate-offer.quantity %}
</td>
<td class="text-right">
{{ (offer.quantity-todel)|number_format(2, '.', ' ') }}
{% set decoproposed=decoproposed-totbefore10 %}
</td>
</tr>
{% endif %}
{% endif %}
{% endfor %}
<tfoot>
<td colspan="2">TOTAL</td>
<td class="text-right">{{ project.proposed|number_format(2, '.', ' ') }}</td>
<td class="text-right">{{ project.validate|number_format(2, '.', ' ') }}</td>
<td class="text-right">{{ (project.proposed - project.validate)|number_format(2, '.', ' ') }}</td>
</tfoot>
</table>
{% 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 class="new-page">&nbsp;</div>
{% endif %}
{% endfor %}
<br>
{% endblock %}
{% block localjavascript %}
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,144 @@
{% extends "base.html.twig" %}
{% block localstyle %}
.homecard {
margin: 20px 20px 0px 0px;
float:left;
}
table {
}
th,td {
border: 1px solid #37474F;
color: #ffffff;
background-color:#37474F;
text-align:center;
width: 70px;
}
td {
background-color:#e8ecf1;
cursor: help;
height: 44px;
vertical-align: top;
color: #ffffff;
}
.date {
font-size: 9px;
color: #37474F;
}
.allday {
font-size: 12px;
float:left;
width:100%;
height: 18px;
flex: 0 0 auto;
}
.am, .ap {
font-size: 12px;
float:left;
width:50%;
height: 18px;
flex: 0 0 auto;
}
.astreinte {
font-size: 11px;
float:left;
width:100%;
height:12px;
}
{% endblock %}
{% block body %}
{% if fgprint is defined and fgprint %}<h1>Synthèse</h1>{%endif%}
{% for user in users %}
{% set nbday=1 %}
<div class="card homecard" style="width:380px;">
<div class="card-header">
<img src="\{{appAlias}}\uploads\avatar\{{user.user.avatar}}" class='avatar no-print'>
{{ user.user.displayname }}
</div>
<div class="card-body">
<table>
<thead>
<th>S</th>
<th>L</th>
<th>M</th>
<th>M</th>
<th>J</th>
<th>V</th>
<th>S</th>
<th>D</th>
</thead>
{% for event in user.events %}
{% if nbday==1 %}
<tr>
<td class="date" style="vertical-align:middle">{{event.date|date("W")}}</td>
{% endif %}
<td>
<div class="date">{{ event.date | date("d/m") }}</div>
<div class="d-flex flex-wrap">
{% set haveam=false %}
{% for detail in event.events %}
{% if detail.allday %}
<div class='allday' style='background-color:{{ detail.colorday }};' title='{{ detail.descriptionday }}'>1</div>
{% else %}
{%if detail.am %}
{% set haveam=true %}
<div class='am' style='background-color:{{ detail.coloram }};' title='{{ detail.descriptionam }}'>0.5</div>
{% endif %}
{%if detail.ap %}
{% if not haveam %}<div class='am'></div>{%endif%}
<div class='ap ml-auto' style='background-color:{{ detail.colorap }};' title='{{ detail.descriptionap }}'>0.5</div>
{% endif %}
{% endif %}
{% endfor %}
{% if event.astreinte %}
<div class='astreinte' style='background-color:{{ event.colorastreinte }};' title='{{ event.descriptionastreinte }}'>*</div>
{% else %}
<div class='astreinte'></div>
{% endif %}
</div>
</td>
{% set nbday=nbday+1 %}
{% if nbday==8 %}
</tr>
{% set nbday=1 %}
{% endif %}
{% endfor %}
</table>
</div>
</div>
{% if (loop.index % 2) == 0 %} <div class="new-page">&nbsp;</div> {% endif %}
{% endfor %}
{% endblock %}
{% block localjavascript %}
function myprint() {
document.location.href="{{path(app.request.attributes.get('_route'),{fgprint:true})}}";
}
$(document).ready(function() {
maxheight=0;
$( ".card" ).each(function( index ) {
if($(this).height()>maxheight)
maxheight=$(this).height();
});
$( ".card" ).height(maxheight);
});
{% endblock %}

View File

@@ -0,0 +1,71 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
SERVICE
{% elseif mode=="update" %}
Modification SERVICE
{% elseif mode=="submit" %}
Création SERVICE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_service') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_service_delete',{'id':service.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.name) }}
{% if form.dolibarrcode is defined %} {{ form_row(form.dolibarrcode) }} {% endif %}
{{ form_row(form.description) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#service_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,72 @@
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
SERVICES
</h1>
<p><a class="btn btn-success" href={{ path('app_service_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Services
</div>
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
<thead>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th>Nom</th>
{% if doliActive %}<th>Code Dolibarr</th>{% endif %}
</tr>
</thead>
<tbody>
{% for service in services %}
<tr>
<td class="no-print">
<a href="{{path("app_service_update",{id:service.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{service.name}}</td>
{% if doliActive %}<td>{{service.dolibarrcode}}</td>{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').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";
}
{% endblock %}

View File

@@ -0,0 +1,161 @@
{% extends 'base.html.twig' %}
{% block body %}
<h1 class="page-header">
STATISTIQUES
</h1>
<div class="row">
<div class="col-md-12 mb-4">
<div class="card homecard" style="width: 100%; height: 520px;">
<div class="card-header">
CADOLES
</div>
<div class="card-body">
<div id="chart-c" style="height: 250px;"></div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card homecard" style="width: 100%; height: 520px;">
<div class="card-header">
DEV
</div>
<div class="card-body">
<div id="chart-1" style="height: 250px;"></div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card homecard" style="width: 100%; height: 520px;">
<div class="card-header">
CSS
</div>
<div class="card-body">
<div id="chart-3" style="height: 250px;"></div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
graphCadoles();
graphDEV();
graphCSS();
});
function graphCadoles() {
new Morris.Line({
element: 'chart-c',
xkey: 'month',
ymax: 350,
ykeys: [
'Total',
{% for nature in tbnatures %}
'{{ nature.name }}',
{% endfor %}
],
data: [
{% for month in tbmonths %}
{ month: '{{ month.name }}',
{% for nature in month.natures %}
{% if loop.first %}
'Total': {{ nature.totalmonth }},
{% endif %}
'{{ nature.name }}': {{ nature.totalnature }},
{% endfor %}
},
{% endfor %}
],
labels: [
'Total',
{% for nature in tbnatures %}
'{{ nature.name }}',
{% endfor %}
]
});
}
function graphDEV() {
new Morris.Line({
element: 'chart-1',
xkey: 'month',
ymax: 160,
ykeys: [
'Total',
{% for nature in tbnatures %}
'{{ nature.name }}',
{% endfor %}
],
data: [
{% for month in tbmonths %}
{ month: '{{ month.name }}',
{% for nature in month.services[1].natures %}
{% if loop.first %}
'Total': {{ nature.totalservice }},
{% endif %}
'{{ nature.name }}': {{ nature.totalnature }},
{% endfor %}
},
{% endfor %}
],
labels: [
'Total',
{% for nature in tbnatures %}
'{{ nature.name }}',
{% endfor %}
]
});
}
function graphCSS() {
new Morris.Line({
element: 'chart-3',
xkey: 'month',
ymax: 160,
ykeys: [
'Total',
{% for nature in tbnatures %}
'{{ nature.name }}',
{% endfor %}
],
data: [
{% for month in tbmonths %}
{ month: '{{ month.name }}',
{% for nature in month.services[3].natures %}
{% if loop.first %}
'Total': {{ nature.totalservice }},
{% endif %}
'{{ nature.name }}': {{ nature.totalnature }},
{% endfor %}
},
{% endfor %}
],
labels: [
'Total',
{% for nature in tbnatures %}
'{{ nature.name }}',
{% endfor %}
]
});
}
{% endblock %}
{% block localexternalscript %}
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
{% endblock %}

83
templates/Task/edit.html.twig Executable file
View File

@@ -0,0 +1,83 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
TACHE
{% elseif mode=="update" %}
Modification TACHE
{% elseif mode=="submit" %}
Création TACHE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_task') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_task_delete',{'id':task.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.name) }}
{{ form_row(form.project) }}
{{ form_row(form.nature) }}
{{ form_row(form.active) }}
{{ form_row(form.quantity) }}
{{ form_row(form.color) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#task_name").focus();
$("#task_color").spectrum(
{
type: "text",
showAlpha: false
}
);
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,176 @@
{% extends "base.html.twig" %}
{% block localstyle %}
td {
padding:5px !important;
}
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
TACHES {% if app.session.get('viewservice') %}PAR ACTVITE{%else%}PAR DOMAINE{%endif%}
</h1>
<a class="btn btn-success" href={{ path('app_task_submit') }}>Ajouter</a>
<div class="custom-control custom-switch float-right">
<input type="checkbox" class="custom-control-input" id="switchactive" {% if app.session.get('activeproject') %} checked {% endif %}>
<label class="custom-control-label" for="switchactive">Projet Actif</label>
</div>
<div class="custom-control custom-switch float-right" style="margin-right:20px">
<input type="checkbox" class="custom-control-input" id="switchactivetask" {% if app.session.get('activetask') %} checked {% endif %}>
<label class="custom-control-label" for="switchactivetask">Tâche Active</label>
</div>
<div class="custom-control custom-switch float-right mr-3">
<input type="checkbox" class="custom-control-input" id="switchservice" {% if app.session.get('viewservice') %} checked {% endif %}>
{% if app.session.get('viewservice') %}
<label class="custom-control-label" for="switchservice">Vue par Activité</label>
{% else %}
<label class="custom-control-label" for="switchservice">Vue par Domaine</label>
{% endif %}
</div>
<p></p>
{% if app.session.get('viewservice') %}
{% set loop01s=services %}
{% else %}
{% set loop01s=domaines %}
{% endif %}
{%for loop01 in loop01s %}
{% if not loop01.projects is empty %}
{% set havetask=false %}
{% set haveproject=false %}
{% for project in loop01.projects %}
{% if app.session.get('activeproject')==project.active and (app.session.get('idproject')=="all" or app.session.get('idproject')==project.id) %}
{% if not project.tasks is empty %}
{% set havetask=true %}
{% endif %}
{% set haveproject=true %}
{% endif %}
{% endfor %}
{% if haveproject and havetask %}
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> {{ loop01.name }}
</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>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th width="150px">Client</th>
<th width="100px">Nature</th>
<th width="100px">Projet</th>
<th>Tâche</th>
<th>Actif</th>
<th width="100px" class="text-center no-string">Estimation</th>
<th width="100px" class="text-center no-string">Validé</th>
<th width="100px" class="text-center no-string">Planifié</th>
<th width="100px" class="text-center no-string">Reste</th>
<th width="70px" class="text-center no-sort">Couleur</th>
</tr>
</thead>
<tbody>
{% for project in loop01.projects %}
{% if app.session.get('activeproject')==project.active and (app.session.get('idproject')=="all" or app.session.get('idproject')==project.id) %}
{% for task in project.tasks %}
{% if app.session.get('activetask')==task.active %}
{% set totvalidate=task.validate %}
{% set totplanified=task.validate %}
{% for event in task.events %}
{% set totplanified=totplanified+event.duration %}
{% if event.validate %}
{% set totvalidate=totvalidate+event.duration %}
{% endif %}
{% endfor %}
{% for penalty in task.penaltys %}
{% set totplanified=totplanified+penalty.duration %}
{% if penalty.validate %}
{% set totvalidate=totvalidate+penalty.duration %}
{% endif %}
{% endfor %}
<tr>
<td class="no-print">
<a href="{{path("app_task_update",{id:task.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{task.project.customer.name}}</td>
<td>{{task.nature.name}}</td>
<td>{{task.project.name}}</td>
<td>{{task.name}}</td>
<td>{{task.active ? "actif":"non-actif"}}</td>
<td class="text-right">{{task.quantity|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{(totvalidate*-1)|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{((totplanified-totvalidate)*-1)|number_format(2, '.', ' ')}}</td>
<td class="text-right">{{(task.quantity-totplanified)|number_format(2, '.', ' ')}}</td>
<td class="text-center" style="background-color:{{task.color}}; color:#ffffff">{{task.color}}</td>
</tr>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<br>
{% endif %}
{% endif %}
{% endfor %}
{% 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 %}
});
$('#switchactive').change(function() {
window.location="{{ path('app_task_activeproject' )}}";
});
$('#switchactivetask').change(function() {
window.location="{{ path('app_task_activetask' )}}";
});
$('#switchservice').change(function() {
window.location="{{ path('app_task_viewservice' )}}";
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View 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 %}

View 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 %}

View File

@@ -0,0 +1,722 @@
{% extends "base.html.twig" %}
{% block localstyle %}
#timer-task {
width:300px;
}
#timer-desc {
width:300px;
}
.select2-results__group {
font-size:12px !important;
}
.select2-results__option{
font-size: 14px;
padding-left:15px
}
{% 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>
{% if user %}
Lancer un Timer :
<select class="select2entity" id="timer-task" name="timer-task">
<option></option>
{% for project in projects|sort((a, b) => a.displayname <=> b.displayname) %}
<optgroup label="{{project.displayname}}">
{% for task in project.tasks|sort((a, b) => a.displayname <=> b.displayname) %}
<option value="{{task.id}}">{{task.displayname}}</option>
{% endfor %}
</optgroup>
{% 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>
{% else %}
Veuillez choisir un Intervenant pour lancer un Timer.
{% endif %}
</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>
&nbsp;&nbsp;
<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("&nbsp;&nbsp;")
.append(resetLink)
.append("&nbsp;&nbsp;")
.append(saveLink)
.append("&nbsp;&nbsp;&nbsp;&nbsp;")
.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 %}

171
templates/User/edit.html.twig Executable file
View File

@@ -0,0 +1,171 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
UTILISATEUR
{% elseif mode=="update" %}
Modification UTILISATEUR
{% elseif mode=="submit" %}
Création UTILISATEUR
{% elseif mode=="profil" %}
Profil UTILISATEUR
{% endif %}
</h1>
{{ form_widget(form.submit) }}
{% if mode=="profil" %}
<a class="btn btn-secondary" href={{ path('app_home') }}>Annuler</a>
{% else %}
<a class="btn btn-secondary" href={{ path('app_user') }}>Annuler</a>
{% endif %}
{% if mode=="update" %}
<a href="{{ path('app_user_delete',{'id':user.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="no-print" style="width:90px; margin:auto;">
{% set avatar= "noavatar.png" %}
{% if user.avatar %}
{% set avatar= user.avatar %}
{% endif %}
<img id="user_avatar_img" src="/{{ appAlias }}/uploads/avatar/{{ avatar }}" class="avatar big" >
{{ form_widget(form.avatar) }}
<a class="btn btn-info" style="width:100%; margin-bottom:15px;" onClick="showModal();" title='Ajouter un avatar'>Modifier</a>
</div>
<div class="row">
<div class="col-md-6">
<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.username) }}
{% if form.password is defined %}
{{ form_row(form.password) }}
{%endif%}
{{ form_row(form.lastname) }}
{{ form_row(form.firstname) }}
{{ form_row(form.email) }}
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<i class="fa fa-pencil-alt fa-fw"></i> Organisation
</div>
<div class="card-body">
{{ form_row(form.service) }}
{{ form_row(form.jobs) }}
{% if form.roles is defined %}
{{ form_row(form.roles) }}
{%endif%}
</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>
{{ form_end(form) }}
<div id="extraLargeModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"></h5>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
</div>
<div class="modal-body">
<iframe id="frameModal" frameborder=0 width="100%" height="700px"></iframe>
</div>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#user_password_first").val("");
$("#user_login").focus();
});
$("#user_avatar_img").on('load', function() {
})
$("#user_avatar_img").on('error', function(){
console.log("la");
var imgSrc = $(this).attr('src');
if(imgSrc!="/{{appAlias}}/uploads/avatar/")
$(this).attr('src',imgSrc);
});
function showModal() {
$("#frameModal").attr("src","{{path("app_crop01")}}");
$("#extraLargeModal").modal("show");
}
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,106 @@
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
UTILISATEURS
</h1>
<p><a class="btn btn-success" href={{ path('app_user_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Utilisateurs
</div>
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
<thead>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th width="70px" class="no-sort no-print">Avatar</th>
<th>Login</th>
<th>Prénom</th>
<th>Nom</th>
<th>Rôles</th>
<th>Activité</th>
<th>Métiers</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td class="no-print">
<a href="{{path("app_user_update",{id:user.id})}}"><i class="fa fa-file"></i></a>
</td>
<td class="no-print"><img id="user_avatar_img" src="/{{ appAlias }}/uploads/avatar/{{ user.avatar }}" class="avatar" ></td>
<td>{{user.username}}</td>
<td>{{user.firstname}}</td>
<td>{{user.lastname}}</td>
<td>
{%for role in user.roles %}
{%if role=="ROLE_ADMIN" %}
Administrateur<br>
{%elseif role=="ROLE_VALIDATOR" %}
Valideur<br>
{%elseif role=="ROLE_MASTER" %}
Master<br>
{%elseif role=="ROLE_USER" %}
Intervenant<br>
{%elseif role=="ROLE_VISITOR" %}
Invité<br>
{%endif%}
{% endfor %}
</td>
<td>
{% if user.service %}
{{ user.service.name }}
{% endif %}
</td>
<td>
{% for job in user.jobs %}
{{ job.type }} - {{ job.name }}<br>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').DataTable({
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
responsive: true,
iDisplayLength: 100,
order: [[ 2, "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";
}
{% endblock %}

View File

@@ -0,0 +1,223 @@
{% extends "base.html.twig" %}
{% block localstyle %}
.homecard {
margin: 20px 20px 0px 0px;
float:left;
}
table {
}
th,td {
border: 1px solid #37474F;
color: #ffffff;
background-color:#37474F;
text-align:center;
width: 70px;
}
td {
background-color:#e8ecf1;
cursor: help;
height: 44px;
vertical-align: top;
color: #ffffff;
}
.date {
font-size: 9px;
color: #37474F;
}
.allday {
font-size: 12px;
float:left;
width:100%;
height: 18px;
flex: 0 0 auto;
}
.am, .ap {
font-size: 12px;
float:left;
width:50%;
height: 18px;
flex: 0 0 auto;
}
.astreinte {
font-size: 11px;
float:left;
width:100%;
height:12px;
}
{% endblock %}
{% block body %}
{% if fgprint is defined and fgprint %}<h1>Validation</h1>{%endif%}
{% for user in users %}
{% set nbday=1 %}
<div class="card homecard" style="width:380px;">
<div class="card-header">
<img src="\{{appAlias}}\uploads\avatar\{{user.user.avatar}}" class='avatar no-print'>
{{ user.user.displayname }}
</div>
<div class="card-body">
<table>
<thead>
<th class="no-print"></th>
<th>S</th>
<th>L</th>
<th>M</th>
<th>M</th>
<th>J</th>
<th>V</th>
<th>S</th>
<th>D</th>
</thead>
{% set btnvalidate=false %}
{% for event in user.events %}
{% if nbday==1 %}
<tr id="{{user.user.id}}-{{event.date|date("Ymd")}}"}">
<td class="no-print" style="vertical-align:middle">
{% set first=event.events|first %}
{% if first and first.validate %}
<i class="fa fa-thumbs-down devalidate-{{user.user.id}}" onClick="devalidate({{user.user.id}},'{{event.date|date("Ymd")}}','{{event.date|date("m/d/Y")}}')" style="cursor:pointer; color:red;"></i>
{%else%}
<i class="fa fa-thumbs-up validate-{{user.user.id}}" onClick="validate({{user.user.id}},'{{event.date|date("Ymd")}}','{{event.date|date("m/d/Y")}}')" style="cursor:pointer; color:green;{% if btnvalidate %}display:none{% endif %}"></i>
{% set btnvalidate=true %}
{%endif%}
</td>
<td class="date" style="vertical-align:middle">{{event.date|date("W")}}</td>
{% endif %}
<td>
<div class="date">{{ event.date | date("d/m") }}</div>
<div class="d-flex flex-wrap">
{% set haveam=false %}
{% for detail in event.events %}
{% if detail.allday %}
<div class='allday' style='background-color:{{ detail.colorday }};' title='{{ detail.descriptionday }}'>1</div>
{% else %}
{%if detail.am %}
{% set haveam=true %}
<div class='am' style='background-color:{{ detail.coloram }};' title='{{ detail.descriptionam }}'>0.5</div>
{% endif %}
{%if detail.ap %}
{% if not haveam %}<div class='am'></div>{%endif%}
<div class='ap' style='background-color:{{ detail.colorap }};' title='{{ detail.descriptionap }}'>0.5</div>
{% endif %}
{% endif %}
{% endfor %}
</div>
{% if event.astreinte %}
<div class='astreinte' style='background-color:{{ event.colorastreinte }};' title='{{ event.descriptionastreinte }}'>*</div>
{% else %}
<div class='astreinte'></div>
{% endif %}
</td>
{% set nbday=nbday+1 %}
{% if nbday==8 %}
</tr>
{% set nbday=1 %}
{% endif %}
{% endfor %}
</table>
</div>
</div>
{% if (loop.index % 2) == 0 %} <div class="new-page">&nbsp;</div> {% endif %}
{% endfor %}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
resizePanel();
});
$( window ).resize(function() {
resizePanel();
});
function printPage(pdf,pdfName,options,lstPage,cpt) {
pdf.addHTML($("#content h1"), 10, 10, options, function(){
pdf.addHTML(lstPage[cpt], 0, 40, options, function(){
cpt=cpt+1;
if(cpt>=lstPage.length) {
$("#page-wrapper").first("row").css("width","initial");
}
else {
pdf.addPage();
printPage(pdf,pdfName,options,lstPage,cpt);
}
});
});
}
function myprint() {
document.location.href="{{path(app.request.attributes.get('_route'),{fgprint:true})}}";
}
function resizePanel() {
maxheight=0;
$( ".homecard" ).each(function( index ) {
if($(this).height()>maxheight)
maxheight=$(this).height();
});
$( ".homecard" ).height(maxheight);
}
function validate(iduser,idday,day) {
$.ajax({
type: "POST",
data: {
iduser: iduser,
day: day,
},
url: "{{ path('app_validation_validate') }}",
success: function (response) {
response=JSON.parse(response);
if(response.return=="KO") {
alert(response.error);
}
else {
$(".devalidate-"+iduser).remove();
html="<i class=\"fa fa-thumbs-down devalidate-"+iduser+"\" onClick=\"devalidate("+iduser+",'"+idday+"','"+day+"')\" style=\"cursor:pointer; color:red;\"></i>";
$(".validate-"+iduser).first().replaceWith(html);
$(".validate-"+iduser).first().show();
}
}
});
}
function devalidate(iduser,idday,day) {
$.ajax({
type: "POST",
data: {
iduser: iduser,
day: day,
},
url: "{{ path('app_validation_devalidate') }}",
success: function (response) {
response=JSON.parse(response);
if(response.return=="KO") {
alert(response.error);
}
else {
location.reload();
}
}
});
}
{% endblock %}

View File

@@ -0,0 +1,157 @@
{% 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 CONGES
</h1>
<div class="custom-control custom-switch float-right">
<input type="checkbox" class="custom-control-input" id="switchactive" {% if app.session.get('activeholiday') %} checked {% endif %}>
<label class="custom-control-label" for="switchactive">Congès à Valider</label>
</div>
<div style="height:30px;">
{% if not app.session.get('activeholiday') %}
On ne peut dévalider des congés que si la semaine de travail n'a pas été validée
{% endif %}
</div>
<div class="card homecard">
<div class="card-header">
{% if not app.session.get('activeholiday') %}
Congé à Dévalider
{% else %}
Congé à 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>Utilisateur</th>
<th>Tâche</th>
<th>Début</th>
<th>Fin</th>
<th>Durée</th>
</thead>
{% for user in users %}
{% for event in user.holidays %}
<tr id="row-{{event.id}}">
<td class="no-print" style="vertical-align:middle">
{% if event.validateholiday %}
<i class="fa fa-thumbs-down validate-{{user.user.id}}" onClick="devalidate({{event.id}})" style="cursor:pointer; color:red;"></i>
{% else %}
<i class="fa fa-thumbs-up validate-{{user.user.id}}" onClick="validate({{event.id}})" style="cursor:pointer; color:green;"></i>
{% endif %}
</td>
<td>
{{ user.user.displayname }}
</td>
<td>
{{ event.task }}
</td>
<td>
{{ event.start|date("d/m/Y H:i") }}
</td>
<td>
{{ event.end|date("d/m/Y H:i") }}
</td>
<td>
{{ event.duration }}
</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_validationholiday_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_validationholiday_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_validationholiday_activeholiday' )}}";
});
{% endblock %}

View 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 %}

71
templates/Year/edit.html.twig Executable file
View File

@@ -0,0 +1,71 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
<h1 class="page-header">
{% if fgprint is defined and fgprint %}
EXERCICE
{% elseif mode=="update" %}
Modification EXERCICE
{% elseif mode=="submit" %}
Création EXERCICE
{% endif %}
</h1>
{{ form_widget(form.submit) }}
<a class="btn btn-secondary" href={{ path('app_year') }}>Annuler</a>
{% if mode=="update" %}
<a href="{{ path('app_year_delete',{'id':year.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.start) }}
{{ form_row(form.end) }}
{{ form_row(form.nbday) }}
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
$("#year_name").focus();
});
function myprint() {
href=document.location.href;
document.location.href=href+"?fgprint=true";
}
{% endblock %}

View File

@@ -0,0 +1,74 @@
{% 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; }
{%endif%}
{% endblock %}
{% block body %}
<h1 class="page-header">
EXERCICES COMPTABLE
</h1>
<p><a class="btn btn-success" href={{ path('app_year_submit') }}>Ajouter</a></p>
<div class="card">
<div class="card-header">
<i class="fa fa-table fa-fw"></i> Liste des Exercices
</div>
<div class="card-body">
<div class="dataTable_wrapper">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
<thead>
<tr>
<th width="70px" class="no-sort no-print">Action</th>
<th>Début</th>
<th>Fin</th>
<th>Nb jour travail</th>
</tr>
</thead>
<tbody>
{% for year in years %}
<tr>
<td class="no-print">
<a href="{{path("app_year_update",{id:year.id})}}"><i class="fa fa-file"></i></a>
</td>
<td>{{year.start|date("d/m/Y")}}</td>
<td>{{year.end|date("d/m/Y")}}</td>
<td>{{year.nbday}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block localjavascript %}
$(document).ready(function() {
{% if not fgprint is defined or not fgprint %}
$('#dataTables').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";
}
{% endblock %}

630
templates/base.html.twig Normal file
View File

@@ -0,0 +1,630 @@
<!DOCTYPE html>
<html>
{% set color = app.session.get('color') %}
<head>
<meta http-equiv="Content-Type" content="text/html"; charset="utf-8" />
<title>{% block title %}{{ appName }}{% endblock %}</title>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
{% block head_style %}
{{ encore_entry_link_tags('app') }}
{% endblock head_style %}
{% block stylesheets %}{% endblock %}
<link rel="shortcut icon" href="/{{ appAlias }}/images/logo.png" />
</head>
<style>
/* global */
.bg-dark {
background-color: #152c3c !important;
}
h1{
padding: 40px 0px 9px 0px;
border-bottom: 1px solid #eee;
}
.nav a{
background: none;
color: #CFD8DC;
font-size: 14px;
padding: 5px 0px 5px 25px;
display: block;
}
/* Sidebar Styles */
.contentsidebar {
margin-left:250px;
}
#sidebar {
z-index: 1000;
position: fixed;
left: 250px;
width: 250px;
height: 100%;
margin-left: -250px;
overflow-y: auto;
background: #152c3c;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#sidebar header {
background-color: #263238;
font-size: 20px;
line-height: 52px;
text-align: center;
}
#sidebar header a {
color: #fff;
display: block;
text-decoration: none;
}
#sidebar header a:hover {
color: #fff;
}
#sidebar .nav{
display: block;
}
#sidebar .nav a {
padding: 0px 10px 5px 10px;
}
#sidebar .nav .last{
border-bottom: 5px solid #455A64;
padding-bottom:5px;
}
#sidebar .title {
color: #CFD8DC;
font-size: 16px;
padding: 0px 10px 0px 10px;
display: block;
text-transform: uppercase;
margin-left: 0px !important;
font-weight: bold;
}
#sidebar .nav .last{
border-bottom: 5px solid #455A64;
padding-bottom:5px;
}
#sidebar .nav a:hover{
background: none;
color: #ECEFF1;
}
#sidebar .nav a .fa{
margin-right: 5px;
}
#sidebar .nav .select-control {
padding: 0px 10px 5px 10px;
margin-top: -12px;
}
.avatar {
background-color: #343a40;
width: 35px;
height: 35px;
border-radius: 100%;
margin-top: -5px;
}
.avatar.big{
width: 90px;
height: 90px;
margin-bottom: 10px;
}
@media (max-width: 991px) {
.contentsidebar {
margin-left: auto;
}
#sidebar {
position: static;
margin:0px -15px;
width: auto;
}
}
a.btn {
color:#ffffff;
}
@media (min-width: 992px) {
#sidebar {
display: block;
}
}
{% if useheader is defined and useheader %}
#main {
padding-top:55px;
}
{% endif %}
th.dt-center, td.dt-center { text-align: center; }
.new-page {display:none;}
{% if fgprint is defined and fgprint %}
.no-print {display:none}
.new-page {
clear: both;
display: block;
border :1px solid transparent;
page-break-after: always;
}
#sidebar,.navbar,.sf-toolbar {
display: none;
}
#mycontent{
margin:0px;
//width:800px;
}
#main{
margin:0px;
padding:10px;
}
.homecard {
display:inline-block;
float:none;
}
{% endif %}
{% block localstyle %}
{% endblock %}
</style>
<body>
{% if useheader is defined and useheader %}
<nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="{{ path('app_home')}}">
<img src="/{{appAlias}}/images/logo.png" style="height:30px;margin-top:-3px;">
{{appName}}
</a>
{% if usesidebar is defined and usesidebar %}
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#sidebar" aria-controls="sidebar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
{% endif %}
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
</ul>
</div>
<ul class="nav navbar-top-links navbar-right">
{% if app.user and ("ROLE_USER" in app.user.roles or "ROLE_MASTER" in app.user.roles or "ROLE_VALIDATOR" in app.user.roles or "ROLE_ADMIN" in app.user.roles)%}
<li>
<a href="{{path("app_user_profil")}}">
<img src="/{{appAlias}}/uploads/avatar/{{app.user.avatar}}" class="avatar">
</a>
</li>
{% endif %}
{% set routeignore = ["app_home","app_event","app_customer_submit","app_project_submit","app_offer_submit","app_task_submit","app_service_submit","app_user_submit","app_nature_submit","app_nature_update","app_job_submit","app_breakday_submit","app_breakday_update"] %}
{% if app.request.attributes.get('_route') not in routeignore %}
<li>
<a onClick="myprint()" style="cursor:pointer; color:#fff"><i class="fa fa-print fa-fw"></i></a>
</li>
{%endif%}
<li>
{% if app.user %}
{% if appAuth=="MYSQL" %}
<a href="{{path("app_logout")}}"><i class="fa fa-sign-out-alt fa-fw"></i></a>
{% elseif appAuth=="CAS" %}
<a href="{{path("app_logoutcas")}}"><i class="fa fa-sign-out-alt fa-fw"></i></a>
{% endif %}
{% else %}
{% if appAuth=="MYSQL" %}
<a href="{{path("app_login")}}"><i class="fa fa-sign-in-alt fa-fw"></i></a>
{% elseif appAuth=="CAS" %}
<a href="{{path("app_logincas")}}"><i class="fa fa-sign-in-alt fa-fw"></i></a>
{% endif %}
{% endif %}
</li>
</ul>
</nav>
{% endif %}
<main id="main" class="container-fluid">
{% set contentsidebar="" %}
{% if usesidebar is defined and usesidebar %}
{% set contentsidebar="contentsidebar" %}
<div id="sidebar" class="collapse">
<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') %}
<p></p>
<li>
<label class="control-label" style="padding:0px 10px 5px 10px; color:#fff;">
Nombre de Mois
</label>
<div class="select-control">
<select class="form-control select2entity" id="sidemonth" name="sidemonth">
{% set selected="" %}
{% for i in 1..48 %}
{% set selected="" %}
{%if i==app.session.get('nbmonth') %}
{% set selected="selected" %}
{% endif %}
<option value="{{i}}" {{selected}}>{{i}}</option>
{% endfor %}
</select>
</div>
<label class="control-label" style="padding:0px 10px 5px 10px; color:#fff;">
Service
</label>
<div class="select-control">
<select class="form-control select2entity" id="sideservice" name="sideservice">
<option value="all" selected>Toutes les services</option>
{% for service in app.session.get('services') %}
{% set selected="" %}
{%if service.id==app.session.get('idservice') %}
{% set selected="selected" %}
{% endif %}
<option value="{{service.id}}" {{selected}}>{{service.name}}</option>
{% endfor %}
</select>
</div>
<label class="control-label" style="padding:0px 10px 5px 10px; color:#fff;">
Domaine
</label>
<div class="select-control">
<select class="form-control select2entity" id="sidedomaine" name="sidedomaine">
<option value="all" selected>Toutes les domaines</option>
{% for domaine in app.session.get('domaines') %}
{% set selected="" %}
{%if domaine.id==app.session.get('iddomaine') %}
{% set selected="selected" %}
{% endif %}
<option value="{{domaine.id}}" {{selected}}>{{domaine.name}}</option>
{% endfor %}
</select>
</div>
<label class="control-label" style="padding:0px 10px 5px 10px; color:#fff;">
Intervenant
</label>
<div class="select-control">
<select class="form-control select2entity" id="sideuser" name="sideuser">
<option value="all" selected>Tout le monde</option>
{% for user in app.session.get('users') %}
{% set selected="" %}
{%if user.id==app.session.get('iduser') %}
{% set selected="selected" %}
{% endif %}
<option value="{{user.id}}" {{selected}}>{{user.displayname}}</option>
{% endfor %}
</select>
</div>
<label class="control-label" style="padding:0px 10px 5px 10px; color:#fff;">
Projet
</label>
<div class="select-control">
<select class="form-control select2entity" id="sideproject" name="sideproject">
<option value="all" selected>Tous les projets</option>
{% for project in app.session.get('projects')|sort((a, b) => a.displayname <=> b.displayname) %}
{% set selected="" %}
{%if project.id==app.session.get('idproject') %}
{% set selected="selected" %}
{% endif %}
<option value="{{project.id}}" {{selected}}>{{project.displayname}}</option>
{% endfor %}
</select>
</div>
</li>
<li class="last"></li>
<li class="title">Planning</li>
<li>
<a href="{{path("app_synthese")}}">
<i class="fa fa-id-card"></i>Synthese
</a>
</li>
<li>
<a href="{{path("app_planning")}}">
<i class="fa fa-tachometer-alt"></i>Planning
</a>
</li>
<li>
<a href="{{path("app_report")}}">
<i class="fa fa-pen-square"></i>Rapport
</a>
</li>
<li>
<a href="{{path("app_event")}}">
<i class="fa fa-calendar-alt"></i>Calendrier
</a>
</li>
<li>
<a href="{{path("app_timer")}}">
<i class="fa fa-stopwatch"></i>Suivi Horaire
</a>
</li>
<li>
<a href="{{path("app_holiday")}}">
<i class="fa fa-umbrella-beach"></i>Mes Congés
</a>
</li>
<li>
<a href="{{path("app_stat_view")}}">
<i class="fas fa-chart-line"></i>Statistiques
</a>
</li>
<li class="last">
<a href="{{path("app_export_view")}}">
<i class="fa fa-file-download"></i>Exports
</a>
</li>
{% endif %}
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_VALIDATOR') %}
<li class="title">Validations</li>
<li>
<a href="{{path("app_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>
</li>
<li class="last">
<a href="{{path("app_validationtimer")}}">
<i class="fa fa-user-clock"></i>Validation Horaires
</a>
</li>
{% endif %}
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_MASTER') %}
<li class="title">Projets</li>
<li>
<a href="{{path("app_customer")}}">
<i class="fa fa-user"></i>Clients
</a>
</li>
<li>
<a href="{{path("app_project")}}">
<i class="fa fa-suitcase"></i>Projets
</a>
</li>
<li>
<a href="{{path("app_offer")}}">
<i class="fa fa-euro-sign"></i>Commandes
</a>
</li>
<li>
<a href="{{path("app_task")}}">
<i class="fa fa-tasks"></i>Tâches
</a>
</li>
<li class="last">
<a href="{{path("app_budget_last")}}">
<i class="fa fa-money-bill-alt"></i>Budgets
</a>
</li>
{% endif %}
{% if is_granted('ROLE_ADMIN') %}
<li class="title">Organisation</li>
<li>
<a href="{{path("app_service")}}">
<i class="fa fa-building"></i>Service
</a>
</li>
<li>
<a href="{{path("app_domaine")}}">
<i class="fas fa-money-bill-alt"></i>&nbsp;Domaines
</a>
</li>
<li>
<a href="{{path("app_user")}}">
<i class="fa fa-users"></i>Utilisateurs
</a>
</li>
<li>
<a href="{{path("app_nature")}}">
<i class="fa fa-folder"></i>Natures
</a>
</li>
<li>
<a href="{{path("app_job")}}">
<i class="fa fa-clipboard-list"></i>Métiers
</a>
</li>
<li>
<a href="{{path("app_year")}}">
<i class="fa fa-calendar-alt"></i>Exercices Comptable
</a>
</li>
<li class="last">
<a href="{{path("app_breakday")}}">
<i class="fa fa-gifts"></i>Jours Fériés
</a>
</li>
{% if appCron %}
<li class="title">Outils</li>
<li>
<a href="{{path("app_cron")}}">
<i class="fa fa-cogs"></i>Jobs
</a>
</li>
<li class="last">
<a href="{{path("app_cron_log")}}">
<i class="fa fa-list-alt"></i>Logs / Dump
</a>
</li>
{% endif %}
{% endif %}
</ul>
</div>
{%endif%}
<div id="mycontent" class="content {{contentsidebar}}">
{% block body %}
{% endblock %}
</div>
</main>
{{ encore_entry_script_tags('app') }}
{% block localexternalscript %}
{% endblock %}
<script>
$(document).ready(function() {
var doit = true;
$("a[data-method]").on('click',function(){
if($(this).data('confirm')){
doit = confirm($(this).data('confirm'));
if(!doit) return false;
}
});
});
$('#sidemonth').on('select2:select', function (e) {
var data = e.params.data;
console.log(data.id);
$.ajax({
type: "POST",
data: {
nbmonth: data.id,
},
url: "{{ path('app_home_selectmonth') }}",
success: function (response) {
location.reload();
}
});
});
$('#sideuser').on('select2:select', function (e) {
var data = e.params.data;
$.ajax({
type: "POST",
data: {
iduser: data.id,
},
url: "{{ path('app_home_selectuser') }}",
success: function (response) {
location.reload();
}
});
});
$('#sideproject').on('select2:select', function (e) {
var data = e.params.data;
$.ajax({
type: "POST",
data: {
idproject: data.id,
},
url: "{{ path('app_home_selectproject') }}",
success: function (response) {
location.reload();
}
});
});
$('#sideservice').on('select2:select', function (e) {
var data = e.params.data;
$.ajax({
type: "POST",
data: {
idservice: data.id,
},
url: "{{ path('app_home_selectservice') }}",
success: function (response) {
location.reload();
}
});
});
$('#sidedomaine').on('select2:select', function (e) {
var data = e.params.data;
$.ajax({
type: "POST",
data: {
iddomaine: data.id,
},
url: "{{ path('app_home_selectdomaine') }}",
success: function (response) {
location.reload();
}
});
});
</script>
<script>
{% block localjavascript %}
{% endblock %}
</script>
</body>
</html>