svg
This commit is contained in:
parent
9a2e4755e1
commit
4b798fd1f9
11
.env
11
.env
@ -4,4 +4,13 @@ DATABASE_URL="mysql://user:changeme@mariadb:3306/ninecompta"
|
||||
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
||||
|
||||
APP_NAME=Ninecompta
|
||||
APP_NOREPLY=admin@noreply.fr
|
||||
APP_NOREPLY=admin@noreply.fr
|
||||
MODE_AUTH=SQL
|
||||
|
||||
CAS_HOST=auth.cadoles.com
|
||||
CAS_PORT=443
|
||||
CAS_PATH=/cas
|
||||
CAS_USERNAME=uid
|
||||
CAS_MAIL=mail
|
||||
CAS_LASTNAME=lastname
|
||||
CAS_FIRSTNAME=firstname
|
||||
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -3,5 +3,8 @@
|
||||
"php-cs-fixer.executablePath": "${workspaceFolder}/vendor/bin/php-cs-fixer",
|
||||
"php-cs-fixer.onsave": true,
|
||||
"php-cs-fixer.rules": "@Symfony",
|
||||
"php-cs-fixer.config": ".php-cs-fixer.dist.php"
|
||||
"php-cs-fixer.config": ".php-cs-fixer.dist.php",
|
||||
"vscode-php-cs-fixer.toolPath": "/usr/local/bin/php-cs-fixer",
|
||||
"vscode-php-cs-fixer.config": ".php-cs-fixer.dist.php",
|
||||
"vscode-php-cs-fixer.rules": ""
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
"php": ">=8.2",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"apereo/phpcas": "^1.6",
|
||||
"doctrine/dbal": "^3",
|
||||
"doctrine/doctrine-bundle": "^2.13",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.3",
|
||||
@ -14,6 +15,7 @@
|
||||
"oneup/uploader-bundle": "^5.0",
|
||||
"phpdocumentor/reflection-docblock": "^5.4",
|
||||
"phpstan/phpdoc-parser": "^1.33",
|
||||
"ramsey/uuid": "^4.7",
|
||||
"symfony/asset": "7.1.*",
|
||||
"symfony/console": "7.1.*",
|
||||
"symfony/doctrine-messenger": "7.1.*",
|
||||
|
314
composer.lock
generated
314
composer.lock
generated
@ -4,8 +4,139 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "26388d2182ab98b93691c53c2fa59dc5",
|
||||
"content-hash": "89c167c235fc8b9bdd27e885ec95db37",
|
||||
"packages": [
|
||||
{
|
||||
"name": "apereo/phpcas",
|
||||
"version": "1.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/apereo/phpCAS.git",
|
||||
"reference": "c129708154852656aabb13d8606cd5b12dbbabac"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/apereo/phpCAS/zipball/c129708154852656aabb13d8606cd5b12dbbabac",
|
||||
"reference": "c129708154852656aabb13d8606cd5b12dbbabac",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-dom": "*",
|
||||
"php": ">=7.1.0",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"monolog/monolog": "^1.0.0 || ^2.0.0",
|
||||
"phpstan/phpstan": "^1.5",
|
||||
"phpunit/phpunit": ">=7.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"source/CAS.php"
|
||||
],
|
||||
"classmap": [
|
||||
"source/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Joachim Fritschi",
|
||||
"email": "jfritschi@freenet.de",
|
||||
"homepage": "https://github.com/jfritschi"
|
||||
},
|
||||
{
|
||||
"name": "Adam Franco",
|
||||
"homepage": "https://github.com/adamfranco"
|
||||
},
|
||||
{
|
||||
"name": "Henry Pan",
|
||||
"homepage": "https://github.com/phy25"
|
||||
}
|
||||
],
|
||||
"description": "Provides a simple API for authenticating users against a CAS server",
|
||||
"homepage": "https://wiki.jasig.org/display/CASC/phpCAS",
|
||||
"keywords": [
|
||||
"apereo",
|
||||
"cas",
|
||||
"jasig"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/apereo/phpCAS/issues",
|
||||
"source": "https://github.com/apereo/phpCAS/tree/1.6.1"
|
||||
},
|
||||
"time": "2023-02-19T19:52:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.12.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/brick/math.git",
|
||||
"reference": "f510c0a40911935b77b86859eb5223d58d660df1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
|
||||
"reference": "f510c0a40911935b77b86859eb5223d58d660df1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "^2.2",
|
||||
"phpunit/phpunit": "^10.1",
|
||||
"vimeo/psalm": "5.16.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Brick\\Math\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Arbitrary-precision arithmetic library",
|
||||
"keywords": [
|
||||
"Arbitrary-precision",
|
||||
"BigInteger",
|
||||
"BigRational",
|
||||
"arithmetic",
|
||||
"bigdecimal",
|
||||
"bignum",
|
||||
"bignumber",
|
||||
"brick",
|
||||
"decimal",
|
||||
"integer",
|
||||
"math",
|
||||
"mathematics",
|
||||
"rational"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/brick/math/issues",
|
||||
"source": "https://github.com/brick/math/tree/0.12.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/BenMorel",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-29T23:19:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "2.2.0",
|
||||
@ -2022,6 +2153,187 @@
|
||||
},
|
||||
"time": "2024-09-11T13:17:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/collection.git",
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"ergebnis/composer-normalize": "^2.28.3",
|
||||
"fakerphp/faker": "^1.21",
|
||||
"hamcrest/hamcrest-php": "^2.0",
|
||||
"jangregor/phpstan-prophecy": "^1.0",
|
||||
"mockery/mockery": "^1.5",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpcsstandards/phpcsutils": "^1.0.0-rc1",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/extension-installer": "^1.2",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-mockery": "^1.1",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"ramsey/coding-standard": "^2.0.3",
|
||||
"ramsey/conventional-commits": "^1.3",
|
||||
"vimeo/psalm": "^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"captainhook": {
|
||||
"force-install": true
|
||||
},
|
||||
"ramsey/conventional-commits": {
|
||||
"configFile": "conventional-commits.json"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ramsey\\Collection\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ben Ramsey",
|
||||
"email": "ben@benramsey.com",
|
||||
"homepage": "https://benramsey.com"
|
||||
}
|
||||
],
|
||||
"description": "A PHP library for representing and manipulating collections.",
|
||||
"keywords": [
|
||||
"array",
|
||||
"collection",
|
||||
"hash",
|
||||
"map",
|
||||
"queue",
|
||||
"set"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/collection/issues",
|
||||
"source": "https://github.com/ramsey/collection/tree/2.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ramsey",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-31T21:50:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.7.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "91039bc1faa45ba123c4328958e620d382ec7088"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
|
||||
"reference": "91039bc1faa45ba123c4328958e620d382ec7088",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
|
||||
"ext-json": "*",
|
||||
"php": "^8.0",
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
},
|
||||
"replace": {
|
||||
"rhumsaa/uuid": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/captainhook": "^5.10",
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"doctrine/annotations": "^1.8",
|
||||
"ergebnis/composer-normalize": "^2.15",
|
||||
"mockery/mockery": "^1.3",
|
||||
"paragonie/random-lib": "^2",
|
||||
"php-mock/php-mock": "^2.2",
|
||||
"php-mock/php-mock-mockery": "^1.3",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.1",
|
||||
"phpbench/phpbench": "^1.0",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpunit/phpunit": "^8.5 || ^9",
|
||||
"ramsey/composer-repl": "^1.4",
|
||||
"slevomat/coding-standard": "^8.4",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"vimeo/psalm": "^4.9"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
|
||||
"ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
|
||||
"ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
|
||||
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
|
||||
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"captainhook": {
|
||||
"force-install": true
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Ramsey\\Uuid\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
|
||||
"keywords": [
|
||||
"guid",
|
||||
"identifier",
|
||||
"uuid"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid/issues",
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.7.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ramsey",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-27T21:32:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/asset",
|
||||
"version": "v7.1.6",
|
||||
|
@ -1,4 +1,6 @@
|
||||
oneup_uploader:
|
||||
mappings:
|
||||
avatar:
|
||||
frontend: dropzone
|
||||
frontend: dropzone
|
||||
logo:
|
||||
frontend: dropzone
|
@ -1,21 +1,24 @@
|
||||
security:
|
||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||
password_hashers:
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: "auto"
|
||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||
|
||||
providers:
|
||||
# used to reload user from session & other features (e.g. switch_user)
|
||||
app_user_provider:
|
||||
sql_provider:
|
||||
entity:
|
||||
class: App\Entity\User
|
||||
property: username
|
||||
|
||||
|
||||
firewalls:
|
||||
dev:
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
security: false
|
||||
|
||||
main:
|
||||
lazy: true
|
||||
provider: app_user_provider
|
||||
pattern: ^/
|
||||
provider: sql_provider
|
||||
custom_authenticators:
|
||||
- App\Security\DynamicAuthenticator
|
||||
form_login:
|
||||
login_path: app_login
|
||||
check_path: app_login
|
||||
@ -23,31 +26,15 @@ security:
|
||||
default_target_path: /
|
||||
logout:
|
||||
path: app_logout
|
||||
# where to redirect after logout
|
||||
# target: app_any_route
|
||||
|
||||
# activate different ways to authenticate
|
||||
# https://symfony.com/doc/current/security.html#the-firewall
|
||||
|
||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||
# switch_user: true
|
||||
|
||||
# Easy way to control access for large sections of your site
|
||||
# Note: Only the *first* access control that matches will be used
|
||||
access_control:
|
||||
- { path: ^/login, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/register, roles: PUBLIC_ACCESS }
|
||||
|
||||
- { path: ^/admin, roles: ROLE_ADMIN }
|
||||
- { path: ^/, roles: ROLE_USER }
|
||||
|
||||
when@test:
|
||||
security:
|
||||
password_hashers:
|
||||
# By default, password hashers are resource intensive and take time. This is
|
||||
# important to generate secure password hashes. In tests however, secure hashes
|
||||
# are not important, waste resources and increase test times. The following
|
||||
# reduces the work factor to the lowest possible values.
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
||||
algorithm: auto
|
||||
cost: 4 # Lowest possible value for bcrypt
|
||||
|
@ -1,22 +1,23 @@
|
||||
# This file is the entry point to configure your own services.
|
||||
# Files in the packages/ subdirectory configure your dependencies.
|
||||
|
||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
appEnv: "%env(resolve:APP_ENV)%"
|
||||
appSecret: "%env(resolve:APP_SECRET)%"
|
||||
appName: "%env(resolve:APP_NAME)%"
|
||||
appNoreply: "%env(resolve:APP_NOREPLY)%"
|
||||
modeAuth: "%env(resolve:MODE_AUTH)%"
|
||||
casHost: "%env(resolve:CAS_HOST)%"
|
||||
casPort: "%env(resolve:CAS_PORT)%"
|
||||
casPath: "%env(resolve:CAS_PATH)%"
|
||||
casUsername: "%env(resolve:CAS_USERNAME)%"
|
||||
casMail: "%env(resolve:CAS_MAIL)%"
|
||||
casLastname: "%env(resolve:CAS_LASTNAME)%"
|
||||
casFirstname: "%env(resolve:CAS_FIRSTNAME)%"
|
||||
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
autowire: true # Automatically injects dependencies in your services.
|
||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: "../src/"
|
||||
exclude:
|
||||
@ -30,4 +31,8 @@ services:
|
||||
tags:
|
||||
- name: "doctrine.event_listener"
|
||||
event: "postPersist"
|
||||
entity: 'App\Entity\Company'
|
||||
entity: 'App\Entity\Company'
|
||||
|
||||
App\Security\DynamicAuthenticator:
|
||||
arguments:
|
||||
$modeAuth: '%env(MODE_AUTH)%'
|
||||
|
BIN
public/uploads/logo/676bdbf5587bb.jpg
Normal file
BIN
public/uploads/logo/676bdbf5587bb.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
BIN
public/uploads/logo/676bddca6cc2e.jpg
Normal file
BIN
public/uploads/logo/676bddca6cc2e.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
BIN
public/uploads/logo/676bde2e409a7.jpg
Normal file
BIN
public/uploads/logo/676bde2e409a7.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
BIN
public/uploads/logo/thumb_676bdbf5587bb.jpg
Normal file
BIN
public/uploads/logo/thumb_676bdbf5587bb.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
public/uploads/logo/thumb_676bddca6cc2e.jpg
Normal file
BIN
public/uploads/logo/thumb_676bddca6cc2e.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
public/uploads/logo/thumb_676bde2e409a7.jpg
Normal file
BIN
public/uploads/logo/thumb_676bde2e409a7.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
@ -21,7 +21,7 @@ class AccountingController extends AbstractController
|
||||
|
||||
return $this->render('accounting/list.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Plan Comptable',
|
||||
'routesubmit' => 'app_user_accounting_submit',
|
||||
'routeupdate' => 'app_user_accounting_update',
|
||||
@ -47,7 +47,7 @@ class AccountingController extends AbstractController
|
||||
|
||||
return $this->render('accounting/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Création Compagnie',
|
||||
'routecancel' => 'app_user_accounting',
|
||||
'routedelete' => 'app_user_accounting_delete',
|
||||
@ -75,7 +75,7 @@ class AccountingController extends AbstractController
|
||||
|
||||
return $this->render('accounting/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Modification Compagnie = '.$accounting->getTitle(),
|
||||
'routecancel' => 'app_user_accounting',
|
||||
'routedelete' => 'app_user_accounting_delete',
|
||||
|
@ -66,7 +66,7 @@ class CompanyController extends AbstractController
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('app_admin_user');
|
||||
return $this->redirectToRoute('app_admin_company');
|
||||
}
|
||||
|
||||
return $this->render('company/edit.html.twig', [
|
||||
|
@ -26,7 +26,7 @@ class HomeController extends AbstractController
|
||||
#[Route('/admin', name: 'app_admin')]
|
||||
public function admin(): Response
|
||||
{
|
||||
return $this->render('home/home.html.twig', [
|
||||
return $this->render('home/blank.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => true,
|
||||
]);
|
||||
|
151
src/Controller/OperationController.php
Normal file
151
src/Controller/OperationController.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Accounting;
|
||||
use App\Entity\Operation;
|
||||
use App\Form\OperationType;
|
||||
use App\Repository\OperationRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class OperationController extends AbstractController
|
||||
{
|
||||
#[Route('/user/operation', name: 'app_user_operation')]
|
||||
public function list(Request $request, OperationRepository $operationRepository): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$operations = $operationRepository->findBy(['company' => $company], ['date' => 'DESC']);
|
||||
|
||||
return $this->render('operation/list.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Grand Livre',
|
||||
'routesubmit' => 'app_user_operation_submit',
|
||||
'routeupdate' => 'app_user_operation_update',
|
||||
'operations' => $operations,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/operation/submit', name: 'app_user_operation_submit')]
|
||||
public function submit(Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$operation = new Operation();
|
||||
$operation->setCompany($company);
|
||||
$operation->setDate(new \DateTime());
|
||||
|
||||
$form = $this->createForm(OperationType::class, $operation, ['mode' => 'submit', 'company' => $company]);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->persist($operation);
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('app_user_operation');
|
||||
}
|
||||
|
||||
return $this->render('operation/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Création Opération',
|
||||
'routecancel' => 'app_user_operation',
|
||||
'routedelete' => 'app_user_operation_delete',
|
||||
'mode' => 'submit',
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/operation/submit/{id}/{direction}', name: 'app_user_operation_submitwithaccounting')]
|
||||
public function submitwithaccounting(int $id, string $direction, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$accounting = $em->getRepository(Accounting::class)->find($id);
|
||||
if (!$accounting) {
|
||||
return $this->redirectToRoute('app_home');
|
||||
}
|
||||
if ('debit' != $direction && 'credit' != $direction) {
|
||||
return $this->redirectToRoute('app_home');
|
||||
}
|
||||
|
||||
$operation = new Operation();
|
||||
$operation->setCompany($company);
|
||||
$operation->setDate(new \DateTime());
|
||||
if ('debit' == $direction) {
|
||||
$operation->setDebit($accounting);
|
||||
} else {
|
||||
$operation->setCredit($accounting);
|
||||
}
|
||||
|
||||
$form = $this->createForm(OperationType::class, $operation, ['mode' => 'submit', 'company' => $company, 'direction' => $direction]);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->persist($operation);
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('app_home');
|
||||
}
|
||||
|
||||
return $this->render('operation/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Création Opération',
|
||||
'routecancel' => 'app_user_operation',
|
||||
'routedelete' => 'app_user_operation_delete',
|
||||
'mode' => 'submit',
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/operation/update/{id}', name: 'app_user_operation_update')]
|
||||
public function update(int $id, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$operation = $em->getRepository(Operation::class)->find($id);
|
||||
if (!$operation || $operation->getCompany() != $company) {
|
||||
return $this->redirectToRoute('app_user_operation');
|
||||
}
|
||||
|
||||
$form = $this->createForm(OperationType::class, $operation, ['mode' => 'update', 'company' => $company]);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('app_user_operation');
|
||||
}
|
||||
|
||||
return $this->render('operation/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Modification Compagnie = '.$operation->getTitle(),
|
||||
'routecancel' => 'app_user_operation',
|
||||
'routedelete' => 'app_user_operation_delete',
|
||||
'mode' => 'update',
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/operation/delete/{id}', name: 'app_user_operation_delete')]
|
||||
public function delete(int $id, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$operation = $em->getRepository(Operation::class)->find($id);
|
||||
if (!$operation || $operation->getCompany() != $company) {
|
||||
return $this->redirectToRoute('app_user_operation');
|
||||
}
|
||||
|
||||
// Tentative de suppression
|
||||
try {
|
||||
$em->remove($operation);
|
||||
$em->flush();
|
||||
} catch (\Exception $e) {
|
||||
$this->addflash('error', $e->getMessage());
|
||||
|
||||
return $this->redirectToRoute('app_user_operation_update', ['id' => $id]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('app_user_operation');
|
||||
}
|
||||
}
|
108
src/Controller/YearController.php
Normal file
108
src/Controller/YearController.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Year;
|
||||
use App\Form\YearType;
|
||||
use App\Repository\YearRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class YearController extends AbstractController
|
||||
{
|
||||
#[Route('/user/year', name: 'app_user_year')]
|
||||
public function list(Request $request, YearRepository $yearRepository): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$years = $yearRepository->findBy(['company' => $company], ['dateStart' => 'ASC']);
|
||||
|
||||
return $this->render('year/list.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Exercices',
|
||||
'routesubmit' => 'app_user_year_submit',
|
||||
'routeupdate' => 'app_user_year_update',
|
||||
'years' => $years,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/year/submit', name: 'app_user_year_submit')]
|
||||
public function submit(Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$year = new Year();
|
||||
$year->setCompany($company);
|
||||
|
||||
$form = $this->createForm(YearType::class, $year, ['mode' => 'submit']);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->persist($year);
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('app_user_year');
|
||||
}
|
||||
|
||||
return $this->render('year/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Création Exercice',
|
||||
'routecancel' => 'app_user_year',
|
||||
'routedelete' => 'app_user_year_delete',
|
||||
'mode' => 'submit',
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/year/update/{id}', name: 'app_user_year_update')]
|
||||
public function update(int $id, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$year = $em->getRepository(Year::class)->find($id);
|
||||
if (!$year || $year->getCompany() != $company) {
|
||||
return $this->redirectToRoute('app_user_year');
|
||||
}
|
||||
|
||||
$form = $this->createForm(YearType::class, $year, ['mode' => 'update']);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('app_user_year');
|
||||
}
|
||||
|
||||
return $this->render('year/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Modification Exercice = '.$year->getDateStart()->format('d/m/Y').' - '.$year->getDateEnd()->format('d/m/Y'),
|
||||
'routecancel' => 'app_user_year',
|
||||
'routedelete' => 'app_user_year_delete',
|
||||
'mode' => 'update',
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/year/delete/{id}', name: 'app_user_year_delete')]
|
||||
public function delete(int $id, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$company = $request->getSession()->get('company');
|
||||
$year = $em->getRepository(Year::class)->find($id);
|
||||
if (!$year || $year->getCompany() != $company) {
|
||||
return $this->redirectToRoute('app_user_year');
|
||||
}
|
||||
|
||||
// Tentative de suppression
|
||||
try {
|
||||
$em->remove($year);
|
||||
$em->flush();
|
||||
} catch (\Exception $e) {
|
||||
$this->addflash('error', $e->getMessage());
|
||||
|
||||
return $this->redirectToRoute('app_user_year_update', ['id' => $id]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('app_user_year');
|
||||
}
|
||||
}
|
@ -200,4 +200,36 @@ class Accounting
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSoldeDate(?\DateTime $date): float
|
||||
{
|
||||
$solde = (float) 0;
|
||||
|
||||
foreach ($this->credits as $credit) {
|
||||
if (!$date || $credit->getDate() <= $date) {
|
||||
if ('passif' == $this->category || 'produit' == $this->category) {
|
||||
$solde += $credit->getMontant();
|
||||
} else {
|
||||
$solde -= $credit->getMontant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->debits as $debit) {
|
||||
if (!$date || $debit->getDate() <= $date) {
|
||||
if ('passif' == $this->category || 'produit' == $this->category) {
|
||||
$solde -= $debit->getMontant();
|
||||
} else {
|
||||
$solde += $debit->getMontant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $solde;
|
||||
}
|
||||
|
||||
public function getSolde(): float
|
||||
{
|
||||
return $this->getSoldeDate(null);
|
||||
}
|
||||
}
|
||||
|
@ -69,10 +69,24 @@ class Company
|
||||
#[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'companys')]
|
||||
private Collection $users;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Year>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Year::class, mappedBy: 'company', orphanRemoval: true)]
|
||||
private Collection $years;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Operation>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Operation::class, mappedBy: 'company', orphanRemoval: true)]
|
||||
private Collection $operations;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->accountings = new ArrayCollection();
|
||||
$this->users = new ArrayCollection();
|
||||
$this->years = new ArrayCollection();
|
||||
$this->operations = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@ -280,4 +294,64 @@ class Company
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Year>
|
||||
*/
|
||||
public function getYears(): Collection
|
||||
{
|
||||
return $this->years;
|
||||
}
|
||||
|
||||
public function addYear(Year $year): static
|
||||
{
|
||||
if (!$this->years->contains($year)) {
|
||||
$this->years->add($year);
|
||||
$year->setCompany($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeYear(Year $year): static
|
||||
{
|
||||
if ($this->years->removeElement($year)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($year->getCompany() === $this) {
|
||||
$year->setCompany(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Operation>
|
||||
*/
|
||||
public function getOperations(): Collection
|
||||
{
|
||||
return $this->operations;
|
||||
}
|
||||
|
||||
public function addOperation(Operation $operation): static
|
||||
{
|
||||
if (!$this->operations->contains($operation)) {
|
||||
$this->operations->add($operation);
|
||||
$operation->setCompany($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeOperation(Operation $operation): static
|
||||
{
|
||||
if ($this->operations->removeElement($operation)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($operation->getCompany() === $this) {
|
||||
$operation->setCompany(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,10 @@ class Operation
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?Accounting $debit = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'operations')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?Company $company = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@ -95,4 +99,16 @@ class Operation
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCompany(): ?Company
|
||||
{
|
||||
return $this->company;
|
||||
}
|
||||
|
||||
public function setCompany(?Company $company): static
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
67
src/Entity/Year.php
Normal file
67
src/Entity/Year.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\YearRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: YearRepository::class)]
|
||||
class Year
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_MUTABLE)]
|
||||
private ?\DateTimeInterface $dateStart = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_MUTABLE)]
|
||||
private ?\DateTimeInterface $dateEnd = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'years')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?Company $company = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDateStart(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->dateStart;
|
||||
}
|
||||
|
||||
public function setDateStart(\DateTimeInterface $dateStart): static
|
||||
{
|
||||
$this->dateStart = $dateStart;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateEnd(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->dateEnd;
|
||||
}
|
||||
|
||||
public function setDateEnd(\DateTimeInterface $dateEnd): static
|
||||
{
|
||||
$this->dateEnd = $dateEnd;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCompany(): ?Company
|
||||
{
|
||||
return $this->company;
|
||||
}
|
||||
|
||||
public function setCompany(?Company $company): static
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
33
src/EventListener/LogoutListener.php
Normal file
33
src/EventListener/LogoutListener.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\EventListener;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
|
||||
use Symfony\Component\Security\Http\Event\LogoutEvent;
|
||||
|
||||
final class LogoutListener
|
||||
{
|
||||
private ParameterBagInterface $parameterBag;
|
||||
|
||||
public function __construct(ParameterBagInterface $parameterBag)
|
||||
{
|
||||
$this->parameterBag = $parameterBag;
|
||||
}
|
||||
|
||||
#[AsEventListener(event: LogoutEvent::class)]
|
||||
public function onLogoutEvent(LogoutEvent $event): void
|
||||
{
|
||||
if ('CAS' == $this->parameterBag->get('modeAuth')) {
|
||||
// Initialiser phpCAS
|
||||
$request = $event->getRequest();
|
||||
$host = $request->headers->get('X-Forwarded-Host') ?? $request->getHost().($request->getPort() ? ':'.$request->getPort() : '');
|
||||
$scheme = $request->headers->get('X-Forwarded-Proto') ?? $request->getScheme();
|
||||
$url = $scheme.'://'.$host;
|
||||
\phpCAS::client(CAS_VERSION_2_0, $this->parameterBag->get('casHost'), (int) $this->parameterBag->get('casPort'), $this->parameterBag->get('casPath'), $url, false);
|
||||
\phpCAS::setNoCasServerValidation();
|
||||
\phpCAS::logoutWithRedirectService($url);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -39,8 +39,10 @@ final class SessionListener
|
||||
$session->set('company', $user->getCompany());
|
||||
$session->set('companys', $user->getCompanys());
|
||||
|
||||
if (!$user->getCompany()) {
|
||||
$event->setResponse(new RedirectResponse($this->router->generate('app_user_nocompany', [])));
|
||||
$currentPath = $request->getPathInfo();
|
||||
$noCompanyPath = $this->router->generate('app_user_nocompany');
|
||||
if (!$user->getCompany() && $currentPath != $noCompanyPath) {
|
||||
$event->setResponse(new RedirectResponse($noCompanyPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Accounting;
|
||||
use App\Form\DataTransformer\ThreeDigitTransformer;
|
||||
use App\Form\Type\FontawsomeType;
|
||||
use App\Form\Type\ThreeDigitType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
|
99
src/Form/OperationType.php
Normal file
99
src/Form/OperationType.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Accounting;
|
||||
use App\Entity\Company;
|
||||
use App\Entity\Operation;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class OperationType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('submit', SubmitType::class, [
|
||||
'label' => 'Valider',
|
||||
'attr' => ['class' => 'btn btn-success no-print'],
|
||||
])
|
||||
|
||||
->add('date', DateType::class, [
|
||||
'label' => 'Date',
|
||||
])
|
||||
|
||||
->add('title', TextType::class, [
|
||||
'label' => 'Titre',
|
||||
]);
|
||||
|
||||
if (!$options['direction'] || 'credit' == $options['direction']) {
|
||||
$builder
|
||||
->add('debit', EntityType::class, [
|
||||
'label' => 'Débit',
|
||||
'class' => Accounting::class,
|
||||
'choice_label' => 'title',
|
||||
'attr' => ['class' => 'select2'],
|
||||
'placeholder' => 'Selectionnez un compte',
|
||||
'query_builder' => function (EntityRepository $er) use ($options) {
|
||||
$result = $er->createQueryBuilder('acc')
|
||||
->where('acc.company = :company')
|
||||
->setParameter('company', $options['company']->getId())
|
||||
->orderBy('acc.num01', 'ASC')
|
||||
->orderBy('acc.num02', 'ASC');
|
||||
|
||||
if ($options['direction']) {
|
||||
$result = $result->andWhere('acc.category=:category')->setParameter('category', 'charge');
|
||||
}
|
||||
|
||||
return $result;
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$options['direction'] || 'debit' == $options['direction']) {
|
||||
$builder
|
||||
->add('credit', EntityType::class, [
|
||||
'label' => 'Crédit',
|
||||
'class' => Accounting::class,
|
||||
'choice_label' => 'title',
|
||||
'attr' => ['class' => 'select2'],
|
||||
'placeholder' => 'Selectionnez un compte',
|
||||
'query_builder' => function (EntityRepository $er) use ($options) {
|
||||
$result = $er->createQueryBuilder('acc')
|
||||
->where('acc.company = :company')
|
||||
->setParameter('company', $options['company']->getId())
|
||||
->orderBy('acc.num01', 'ASC')
|
||||
->orderBy('acc.num02', 'ASC');
|
||||
|
||||
if ($options['direction']) {
|
||||
$result = $result->andWhere('acc.category=:category')->setParameter('category', 'produit');
|
||||
}
|
||||
|
||||
return $result;
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
$builder
|
||||
->add('montant', NumberType::class, [
|
||||
'label' => 'Montant',
|
||||
]);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Operation::class,
|
||||
'company' => Company::class,
|
||||
'mode' => 'mode',
|
||||
'direction' => null,
|
||||
]);
|
||||
}
|
||||
}
|
43
src/Form/YearType.php
Normal file
43
src/Form/YearType.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Year;
|
||||
use App\Form\DataTransformer\ThreeDigitTransformer;
|
||||
use App\Form\Type\FontawsomeType;
|
||||
use App\Form\Type\ThreeDigitType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class YearType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('submit', SubmitType::class, [
|
||||
'label' => 'Valider',
|
||||
'attr' => ['class' => 'btn btn-success no-print'],
|
||||
])
|
||||
|
||||
->add('dateStart', DateType::class, [
|
||||
'label' => 'Date Début',
|
||||
])
|
||||
|
||||
->add('dateEnd', DateType::class, [
|
||||
'label' => 'Date Fin',
|
||||
]);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Year::class,
|
||||
'mode' => 'submit',
|
||||
]);
|
||||
}
|
||||
}
|
43
src/Repository/YearRepository.php
Normal file
43
src/Repository/YearRepository.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Year;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Year>
|
||||
*/
|
||||
class YearRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Year::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Year[] Returns an array of Year objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('y')
|
||||
// ->andWhere('y.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('y.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?Year
|
||||
// {
|
||||
// return $this->createQueryBuilder('y')
|
||||
// ->andWhere('y.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
87
src/Security/CasUserProvider.php
Normal file
87
src/Security/CasUserProvider.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
|
||||
class CasUserProvider implements UserProviderInterface
|
||||
{
|
||||
private UserRepository $userRepository;
|
||||
private EntityManagerInterface $em;
|
||||
private ParameterBagInterface $parameterBag;
|
||||
|
||||
public function __construct(UserRepository $userRepository, EntityManagerInterface $em, ParameterBagInterface $parameterBag)
|
||||
{
|
||||
$this->userRepository = $userRepository;
|
||||
$this->em = $em;
|
||||
$this->parameterBag = $parameterBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge un utilisateur par son identifiant CAS.
|
||||
*/
|
||||
public function loadUserByIdentifier(string $identifier): UserInterface
|
||||
{
|
||||
// Récupérer l'utilisateur depuis la base de données
|
||||
$user = $this->userRepository->findOneBy(['username' => $identifier]);
|
||||
|
||||
if (!$user) {
|
||||
throw new UserNotFoundException(sprintf('User with username "%s" not found.', $identifier));
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge un utilisateur par son identifiant CAS et autosubmit autoupdate en fonction des attributs CAS
|
||||
*/
|
||||
public function loadUserByIdentifierAndAttributes(string $identifier, array $attributes): UserInterface
|
||||
{
|
||||
// Charger l'utilisateur existant depuis la base de données
|
||||
$user = $this->userRepository->findOneBy(['username' => $identifier]);
|
||||
|
||||
if (!$user) {
|
||||
// Créer un nouvel utilisateur avec les attributs CAS
|
||||
$user = new User();
|
||||
$user->setUsername($identifier);
|
||||
$user->setPassword(Uuid::uuid4()->toString());
|
||||
$user->setRoles(['ROLE_USER']);
|
||||
|
||||
// Persister l'utilisateur en base si nécessaire
|
||||
$this->em->persist($user);
|
||||
}
|
||||
|
||||
$user->setEmail($attributes[$this->parameterBag->get('casMail')] ?? null);
|
||||
$this->em->flush();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de recharger un utilisateur déjà authentifié (si nécessaire).
|
||||
*/
|
||||
public function refreshUser(UserInterface $user): UserInterface
|
||||
{
|
||||
if (!$user instanceof User) {
|
||||
throw new \InvalidArgumentException(sprintf('Instances of "%s" are not supported.', get_class($user)));
|
||||
}
|
||||
|
||||
// Recharge l'utilisateur en base si nécessaire (ex. : rôles mis à jour)
|
||||
return $this->userRepository->find($user->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indique si ce provider supporte un type d'utilisateur donné.
|
||||
*/
|
||||
public function supportsClass(string $class): bool
|
||||
{
|
||||
return User::class === $class;
|
||||
}
|
||||
}
|
123
src/Security/DynamicAuthenticator.php
Normal file
123
src/Security/DynamicAuthenticator.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Repository\UserRepository;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
|
||||
|
||||
class DynamicAuthenticator extends AbstractAuthenticator
|
||||
{
|
||||
private string $modeAuth;
|
||||
private UserRepository $userRepository;
|
||||
private CasUserProvider $casUserProvider;
|
||||
private ParameterBagInterface $parameterBag;
|
||||
|
||||
public function __construct(string $modeAuth, UserRepository $userRepository, CasUserProvider $casUserProvider, ParameterBagInterface $parameterBag)
|
||||
{
|
||||
$this->modeAuth = $modeAuth;
|
||||
$this->userRepository = $userRepository;
|
||||
$this->casUserProvider = $casUserProvider;
|
||||
$this->parameterBag = $parameterBag;
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
// Vérifie si l'utilisateur est déjà connecté
|
||||
if ($request->getSession()->get('_security_main')) {
|
||||
return false; // L'utilisateur est déjà authentifié
|
||||
}
|
||||
|
||||
// Exclure les routes de login et logout pour éviter les boucles
|
||||
$currentPath = $request->getPathInfo();
|
||||
if (in_array($currentPath, ['/login', '/logout'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): Passport
|
||||
{
|
||||
switch ($this->modeAuth) {
|
||||
case 'SQL':
|
||||
return $this->authenticateWithSql($request);
|
||||
|
||||
case 'CAS':
|
||||
return $this->authenticateWithCas($request);
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException('Invalid authentication method');
|
||||
}
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
||||
{
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
private function authenticateWithSql(Request $request): Passport
|
||||
{
|
||||
$username = $request->request->get('_username', '');
|
||||
$password = $request->request->get('_password', '');
|
||||
|
||||
if (!$username || !$password) {
|
||||
throw new AuthenticationException('Username and password are required.');
|
||||
}
|
||||
|
||||
// Charger l'utilisateur via Doctrine
|
||||
$user = $this->userRepository->findOneBy(['username' => $username]);
|
||||
|
||||
if (!$user) {
|
||||
throw new AuthenticationException('User not found.');
|
||||
}
|
||||
|
||||
return new Passport(
|
||||
new UserBadge($username, function ($userIdentifier) {
|
||||
return $this->userRepository->findOneBy(['username' => $userIdentifier]);
|
||||
}),
|
||||
new PasswordCredentials($password)
|
||||
);
|
||||
}
|
||||
|
||||
private function authenticateWithCas(Request $request): Passport
|
||||
{
|
||||
// Récupérer l'hôte d'origine derrière le reverse proxy
|
||||
$host = $request->headers->get('X-Forwarded-Host') ?? $request->getHost().($request->getPort() ? ':'.$request->getPort() : '');
|
||||
$scheme = $request->headers->get('X-Forwarded-Proto') ?? $request->getScheme();
|
||||
|
||||
// Construire l'URL
|
||||
$url = $scheme.'://'.$host;
|
||||
|
||||
// \phpCAS::setDebug('/tmp/logcas.log');
|
||||
\phpCAS::client(CAS_VERSION_2_0, $this->parameterBag->get('casHost'), (int) $this->parameterBag->get('casPort'), $this->parameterBag->get('casPath'), $url, false);
|
||||
\phpCAS::setNoCasServerValidation();
|
||||
\phpCAS::forceAuthentication();
|
||||
|
||||
$username = \phpCAS::getUser();
|
||||
$attributes = \phpCAS::getAttributes();
|
||||
|
||||
if (!$username) {
|
||||
throw new AuthenticationException('CAS authentication failed.');
|
||||
}
|
||||
|
||||
$userBadge = new UserBadge($username, function ($userIdentifier) use ($attributes) {
|
||||
return $this->casUserProvider->loadUserByIdentifierAndAttributes($userIdentifier, $attributes);
|
||||
});
|
||||
|
||||
return new SelfValidatingPassport($userBadge);
|
||||
}
|
||||
}
|
@ -40,32 +40,25 @@
|
||||
{% if usemenu is defined and usemenu %}
|
||||
<nav class="navbar navbar-expand-lg bg-dark" data-bs-theme="dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="{{ path('app_home') }}"><img src="{{asset("medias/logo/logo.png")}}"> {{appName}}</a>
|
||||
<a class="navbar-brand" href="{{ path('app_home') }}">
|
||||
{% if app.session.get('company') %}
|
||||
<img src="{{asset(app.session.get('company').logo)}}"> Compagnie = {{app.session.get('company').title}}
|
||||
{% else %}
|
||||
<img src="{{asset("medias/logo/logo.png")}}"> {{appName}}
|
||||
{% endif %}
|
||||
</a>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarColor02">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_user_accounting')}}" class="nav-link" href="#">Plan Comptable</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Features</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Pricing</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">About</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Dropdown</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
<a class="dropdown-item" href="#">Something else here</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#">Separated link</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_user_operation')}}" class="nav-link" href="#">Grand Livre</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_user_accounting')}}" class="nav-link" href="#">Plan Comptable</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_user_year')}}" class="nav-link" href="#">Exercices</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
1
templates/home/blank.html.twig
Normal file
1
templates/home/blank.html.twig
Normal file
@ -0,0 +1 @@
|
||||
{% extends 'base.html.twig' %}
|
@ -3,7 +3,8 @@
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="d-flex justify-content-center">
|
||||
|
||||
<div class="d-flex justify-content-center mt-5">
|
||||
{% for accounting in accountings %}
|
||||
<div class="card" style="width:400px">
|
||||
<div class="card-body d-flex align-items-center">
|
||||
@ -11,7 +12,19 @@
|
||||
<i class="fas {{accounting.icon}} fa-4x"></i>
|
||||
</div>
|
||||
|
||||
<div class="p-3 fs-1">{{accounting.title}}</div>
|
||||
<div class="p-3 fs-1 d-flex flex-column flex-grow-1 align-items-center">
|
||||
<div>{{accounting.title}}</div>
|
||||
<div>{{accounting.solde}}€</div>
|
||||
|
||||
<div class="d-flex ">
|
||||
<a class="p-3" href="{{path('app_user_operation_submitwithaccounting',{id:accounting.id,direction:'credit'})}}">
|
||||
<i class="fas fa-minus bg-danger text-white rounded-circle fa-fw" style="height:60px; padding-top:7px;"></i>
|
||||
</a>
|
||||
<a class="p-3" href="{{path('app_user_operation_submitwithaccounting',{id:accounting.id,direction:'debit'})}}">
|
||||
<i class="fas fa-plus bg-success text-white rounded-circle fa-fw" style="height:60px; padding-top:7px;"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -1 +1,4 @@
|
||||
<h2>Veuillez selectionner une compagnie</h2>
|
||||
{% extends 'base.html.twig' %}
|
||||
{%block body%}
|
||||
<h2>Veuillez selectionner une compagnie</h2>
|
||||
{%endblock%}
|
40
templates/operation/edit.html.twig
Normal file
40
templates/operation/edit.html.twig
Normal file
@ -0,0 +1,40 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form.submit) }}
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary ms-1">Annuler</a>
|
||||
{%if mode=="update" %}<a href="{{ path(routedelete,{id:form.vars.value.id}) }}" class="btn btn-danger float-end" onclick="return confirm('Confirmez-vous la suppression de cet enregistrement ?')">Supprimer</a>{%endif%}
|
||||
|
||||
{% include('include/error.html.twig') %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mx-auto">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.date) }}
|
||||
{{ form_row(form.title) }}
|
||||
{{ form.debit is defined ? form_row(form.debit):"" }}
|
||||
{{ form.credit is defined ? form_row(form.credit):"" }}
|
||||
{{ form_row(form.montant) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#operation_title").focus();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
48
templates/operation/list.html.twig
Normal file
48
templates/operation/list.html.twig
Normal file
@ -0,0 +1,48 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
<a href="{{ path(routesubmit) }}" class="btn btn-success">Ajouter</a>
|
||||
|
||||
<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 width="70px" class="no-sort">Date</th>
|
||||
<th>Titre</th>
|
||||
<th>Débit</th>
|
||||
<th>Crédit</th>
|
||||
<th width="150px">Montant</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for operation in operations %}
|
||||
<tr>
|
||||
<td><a href="{{ path(routeupdate,{id:operation.id}) }}"><i class="fas fa-file fa-2x"></i></a></td>
|
||||
<td>{{operation.date|date("d/m/y")}}</td>
|
||||
<td>{{operation.title}}</td>
|
||||
<td>{{operation.debit.num01}}-{{operation.debit.num02}} = {{operation.debit.title}}</td>
|
||||
<td>{{operation.credit.num01}}-{{operation.credit.num02}} = {{operation.credit.title}}</td>
|
||||
<td>{{operation.montant}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#dataTables').DataTable({
|
||||
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
|
||||
responsive: true,
|
||||
iDisplayLength: 100,
|
||||
order: [[ 1, "asc" ]]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
@ -44,9 +44,9 @@
|
||||
}
|
||||
|
||||
function reportThumb() {
|
||||
window.parent.$("#user_avatar").val("{{thumb}}");
|
||||
window.parent.$("#{{reportThumb}}").val("{{thumb}}");
|
||||
url="{{ asset(thumb) }}";
|
||||
window.parent.$("#user_avatar_img").attr("src",url);
|
||||
window.parent.$("#{{reportThumb}}_img").attr("src",url);
|
||||
closeModal();
|
||||
}
|
||||
|
||||
|
37
templates/year/edit.html.twig
Normal file
37
templates/year/edit.html.twig
Normal file
@ -0,0 +1,37 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form.submit) }}
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary ms-1">Annuler</a>
|
||||
{%if mode=="update" %}<a href="{{ path(routedelete,{id:form.vars.value.id}) }}" class="btn btn-danger float-end" onclick="return confirm('Confirmez-vous la suppression de cet enregistrement ?')">Supprimer</a>{%endif%}
|
||||
|
||||
{% include('include/error.html.twig') %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mx-auto">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.dateStart) }}
|
||||
{{ form_row(form.dateEnd) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#year_dateStart").focus();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
42
templates/year/list.html.twig
Normal file
42
templates/year/list.html.twig
Normal file
@ -0,0 +1,42 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
<a href="{{ path(routesubmit) }}" class="btn btn-success">Ajouter</a>
|
||||
|
||||
<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>Début</th>
|
||||
<th>Fin</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for year in years %}
|
||||
<tr>
|
||||
<td><a href="{{ path(routeupdate,{id:year.id}) }}"><i class="fas fa-file fa-2x"></i></a></td>
|
||||
<td>{{year.dateStart|date('d/m/Y')}}</td>
|
||||
<td>{{year.dateEnd|date('d/m/Y')}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#dataTables').DataTable({
|
||||
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
|
||||
responsive: true,
|
||||
iDisplayLength: 100,
|
||||
order: [[ 1, "asc" ]]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user