diff --git a/app/Http/Controllers/BesoinInformatiqueController.php b/app/Http/Controllers/BesoinInformatiqueController.php new file mode 100644 index 0000000..4c5aebc --- /dev/null +++ b/app/Http/Controllers/BesoinInformatiqueController.php @@ -0,0 +1,90 @@ +get(); + return Inertia::render('BesoinsInformatiques/Index', [ + 'besoins' => $besoins + ]); + } + + public function create() + { + return Inertia::render('BesoinsInformatiques/Create'); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'collectivite' => 'nullable|string|max:255', + 'nom_referent' => 'nullable|string|max:255', + 'descriptif_projet' => 'nullable|string', + 'materiels_support' => 'nullable|array', + 'licences_bureautique' => 'nullable|array', + 'equipements_reseaux' => 'nullable|string', + 'cablage_reseau' => 'nullable|string', + 'telephonie_ip' => 'nullable|string', + 'nouveau_batiment' => 'nullable|string', + 'logiciels_metiers' => 'nullable|string', + 'licences_projets' => 'nullable|array', + 'date_validation' => 'nullable|date', + 'validation_dgs' => 'nullable|string|max:255', + ]); + + BesoinInformatique::create($validated); + + return redirect()->route('besoins-informatiques.index')->with('success', 'Besoin informatique créé avec succès.'); + } + + public function show(BesoinInformatique $besoinInformatique) + { + return Inertia::render('BesoinsInformatiques/Show', [ + 'besoin' => $besoinInformatique + ]); + } + + public function edit(BesoinInformatique $besoinInformatique) + { + return Inertia::render('BesoinsInformatiques/Edit', [ + 'besoin' => $besoinInformatique + ]); + } + + public function update(Request $request, BesoinInformatique $besoinInformatique) + { + $validated = $request->validate([ + 'collectivite' => 'nullable|string|max:255', + 'nom_referent' => 'nullable|string|max:255', + 'descriptif_projet' => 'nullable|string', + 'materiels_support' => 'nullable|array', + 'licences_bureautique' => 'nullable|array', + 'equipements_reseaux' => 'nullable|string', + 'cablage_reseau' => 'nullable|string', + 'telephonie_ip' => 'nullable|string', + 'nouveau_batiment' => 'nullable|string', + 'logiciels_metiers' => 'nullable|string', + 'licences_projets' => 'nullable|array', + 'date_validation' => 'nullable|date', + 'validation_dgs' => 'nullable|string|max:255', + ]); + + $besoinInformatique->update($validated); + + return redirect()->route('besoins-informatiques.index')->with('success', 'Besoin informatique mis à jour avec succès.'); + } + + public function destroy(BesoinInformatique $besoinInformatique) + { + $besoinInformatique->delete(); + return redirect()->route('besoins-informatiques.index')->with('success', 'Besoin informatique supprimé avec succès.'); + } +} diff --git a/app/Http/Controllers/DevisController.php b/app/Http/Controllers/DevisController.php new file mode 100644 index 0000000..a93db83 --- /dev/null +++ b/app/Http/Controllers/DevisController.php @@ -0,0 +1,177 @@ +get(); + return Inertia::render('Devis/Index', [ + 'devis' => $devis + ]); + } + + public function create() + { + return Inertia::render('Devis/Create'); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'destinataire_type' => 'required|string|in:commune,service_interne', + 'destinataire_nom' => 'required|string|max:255', + 'referent' => 'nullable|string|max:255', + 'date_devis' => 'required|date', + 'status' => 'required|string|in:draft,sent,accepted,rejected', + 'items' => 'nullable|array', + 'tva_rate' => 'nullable|numeric|min:0|max:100', + 'notes' => 'nullable|string', + ]); + + // Calculer les montants + $totalHt = 0; + if (!empty($validated['items'])) { + foreach ($validated['items'] as $item) { + $qty = floatval($item['quantite'] ?? 0); + $price = floatval($item['prix_unitaire'] ?? 0); + $totalHt += $qty * $price; + } + } + + $tvaRate = floatval($validated['tva_rate'] ?? 20); + $totalTtc = $totalHt * (1 + ($tvaRate / 100)); + + $validated['total_ht'] = $totalHt; + $validated['total_ttc'] = $totalTtc; + + Devis::create($validated); + + return redirect()->route('devis.index')->with('success', 'Devis créé avec succès.'); + } + + public function show(Devis $devi) + { + $settings = DevisSetting::first() ?? DevisSetting::create([ + 'entity_name' => "Direction des Systèmes d'Information", + 'entity_sub' => "Communauté d'Agglomération Béziers Méditerranée", + 'email' => "support.informatique@beziers-mediterranee.fr", + 'telephone' => "04.67.01.60.00", + 'adresse' => "Béziers, France", + ]); + + return Inertia::render('Devis/Show', [ + 'devis' => $devi, + 'settings' => $settings + ]); + } + + public function edit(Devis $devi) + { + return Inertia::render('Devis/Edit', [ + 'devis' => $devi + ]); + } + + public function update(Request $request, Devis $devi) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'destinataire_type' => 'required|string|in:commune,service_interne', + 'destinataire_nom' => 'required|string|max:255', + 'referent' => 'nullable|string|max:255', + 'date_devis' => 'required|date', + 'status' => 'required|string|in:draft,sent,accepted,rejected', + 'items' => 'nullable|array', + 'tva_rate' => 'nullable|numeric|min:0|max:100', + 'notes' => 'nullable|string', + ]); + + // Calculer les montants + $totalHt = 0; + if (!empty($validated['items'])) { + foreach ($validated['items'] as $item) { + $qty = floatval($item['quantite'] ?? 0); + $price = floatval($item['prix_unitaire'] ?? 0); + $totalHt += $qty * $price; + } + } + + $tvaRate = floatval($validated['tva_rate'] ?? 20); + $totalTtc = $totalHt * (1 + ($tvaRate / 100)); + + $validated['total_ht'] = $totalHt; + $validated['total_ttc'] = $totalTtc; + + $devi->update($validated); + + return redirect()->route('devis.index')->with('success', 'Devis mis à jour avec succès.'); + } + + public function destroy(Devis $devi) + { + $devi->delete(); + return redirect()->route('devis.index')->with('success', 'Devis supprimé avec succès.'); + } + + public function settings() + { + $settings = DevisSetting::first() ?? DevisSetting::create([ + 'entity_name' => "Direction des Systèmes d'Information", + 'entity_sub' => "Communauté d'Agglomération Béziers Méditerranée", + 'email' => "support.informatique@beziers-mediterranee.fr", + 'telephone' => "04.67.01.60.00", + 'adresse' => "Béziers, France", + ]); + + return Inertia::render('Devis/Settings', [ + 'settings' => $settings + ]); + } + + public function updateSettings(Request $request) + { + $validated = $request->validate([ + 'entity_name' => 'required|string|max:255', + 'entity_sub' => 'required|string|max:255', + 'email' => 'required|email|max:255', + 'telephone' => 'required|string|max:50', + 'adresse' => 'nullable|string|max:255', + ]); + + $settings = DevisSetting::first(); + if ($settings) { + $settings->update($validated); + } else { + DevisSetting::create($validated); + } + + return redirect()->route('devis.index')->with('success', 'Paramètres du devis mis à jour avec succès.'); + } + + public function downloadPdf(Devis $devi) + { + $settings = DevisSetting::first() ?? DevisSetting::create([ + 'entity_name' => "Direction des Systèmes d'Information", + 'entity_sub' => "Communauté d'Agglomération Béziers Méditerranée", + 'email' => "support.informatique@beziers-mediterranee.fr", + 'telephone' => "04.67.01.60.00", + 'adresse' => "Béziers, France", + ]); + + $pdf = Pdf::loadView('pdf.devis', [ + 'devis' => $devi, + 'settings' => $settings, + ]); + + return $pdf->download("devis-{$devi->number}.pdf"); + } +} diff --git a/app/Models/BesoinInformatique.php b/app/Models/BesoinInformatique.php new file mode 100644 index 0000000..69ec7ac --- /dev/null +++ b/app/Models/BesoinInformatique.php @@ -0,0 +1,17 @@ + 'array', + 'licences_bureautique' => 'array', + 'licences_projets' => 'array', + 'date_validation' => 'date', + ]; +} diff --git a/app/Models/Devis.php b/app/Models/Devis.php new file mode 100644 index 0000000..7cf546f --- /dev/null +++ b/app/Models/Devis.php @@ -0,0 +1,32 @@ + 'array', + 'date_devis' => 'date', + 'total_ht' => 'decimal:2', + 'total_ttc' => 'decimal:2', + 'tva_rate' => 'decimal:2', + ]; + + protected static function booted() + { + static::creating(function ($devis) { + if (empty($devis->number)) { + $year = date('Y'); + $prefix = sprintf('DEV-%s-', $year); + $last = static::where('number', 'like', $prefix . '%') + ->max('number'); + $next = $last ? (intval(substr($last, strlen($prefix))) + 1) : 1; + $devis->number = $prefix . sprintf('%04d', $next); + } + }); + } +} diff --git a/app/Models/DevisSetting.php b/app/Models/DevisSetting.php new file mode 100644 index 0000000..d16f10e --- /dev/null +++ b/app/Models/DevisSetting.php @@ -0,0 +1,10 @@ +=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + }, + "time": "2025-07-25T09:04:22+00:00" + }, { "name": "monolog/monolog", "version": "3.10.0", @@ -3441,6 +3740,86 @@ }, "time": "2025-12-14T04:43:48+00:00" }, + { + "name": "sabberworm/php-css-parser", + "version": "v9.3.0", + "source": { + "type": "git", + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "1.12.32 || 2.1.32", + "phpstan/phpstan-phpunit": "1.4.2 || 2.0.8", + "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7", + "phpunit/phpunit": "8.5.52", + "rawr/phpunit-data-provider": "3.3.1", + "rector/rector": "1.2.10 || 2.2.8", + "rector/type-perfect": "1.0.0 || 2.1.0", + "squizlabs/php_codesniffer": "4.0.1", + "thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.4.x-dev" + } + }, + "autoload": { + "files": [ + "src/Rule/Rule.php", + "src/RuleSet/RuleContainer.php" + ], + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0" + }, + "time": "2026-03-03T17:31:43+00:00" + }, { "name": "symfony/clock", "version": "v7.4.8", @@ -6030,6 +6409,149 @@ ], "time": "2026-03-30T13:44:50+00:00" }, + { + "name": "thecodingmachine/safe", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^10", + "squizlabs/php_codesniffer": "^3.2" + }, + "type": "library", + "autoload": { + "files": [ + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gettext.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rnp.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "classmap": [ + "lib/DateTime.php", + "lib/DateTimeImmutable.php", + "lib/Exceptions/", + "generated/Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/OskarStark", + "type": "github" + }, + { + "url": "https://github.com/shish", + "type": "github" + }, + { + "url": "https://github.com/silasjoisten", + "type": "github" + }, + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2026-02-04T18:08:13+00:00" + }, { "name": "tightenco/ziggy", "version": "v2.6.2", diff --git a/database/migrations/2026_06_17_075838_create_besoin_informatiques_table.php b/database/migrations/2026_06_17_075838_create_besoin_informatiques_table.php new file mode 100644 index 0000000..972733d --- /dev/null +++ b/database/migrations/2026_06_17_075838_create_besoin_informatiques_table.php @@ -0,0 +1,50 @@ +id(); + // Entête + $table->string('collectivite')->nullable(); + $table->string('nom_referent')->nullable(); + $table->text('descriptif_projet')->nullable(); + + // Service Support et Relations Usagers + $table->json('materiels_support')->nullable(); // Liste PC / Portables / Ecran etc. + $table->json('licences_bureautique')->nullable(); // Liste Licences Bureautique + + // Infrastructures Système et Télécommunications + $table->text('equipements_reseaux')->nullable(); + $table->text('cablage_reseau')->nullable(); + $table->text('telephonie_ip')->nullable(); + $table->text('nouveau_batiment')->nullable(); + + // Etudes Projets et Dématérialisation + $table->text('logiciels_metiers')->nullable(); + $table->json('licences_projets')->nullable(); // Liste Renouvellement ou achat + + // Validation + $table->date('date_validation')->nullable(); + $table->string('validation_dgs')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('besoin_informatiques'); + } +}; diff --git a/database/migrations/2026_06_17_111413_create_devis_table.php b/database/migrations/2026_06_17_111413_create_devis_table.php new file mode 100644 index 0000000..4832a72 --- /dev/null +++ b/database/migrations/2026_06_17_111413_create_devis_table.php @@ -0,0 +1,39 @@ +id(); + $table->string('number')->unique(); + $table->string('title'); + $table->string('destinataire_type'); // 'commune', 'service_interne' + $table->string('destinataire_nom'); + $table->string('referent')->nullable(); + $table->date('date_devis'); + $table->string('status')->default('draft'); // 'draft', 'sent', 'accepted', 'rejected' + $table->json('items')->nullable(); // details of items (type, designation, quantity, unit_price, total_price) + $table->decimal('total_ht', 15, 2)->default(0.00); + $table->decimal('tva_rate', 5, 2)->default(20.00); + $table->decimal('total_ttc', 15, 2)->default(0.00); + $table->text('notes')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('devis'); + } +}; diff --git a/database/migrations/2026_06_17_113134_create_devis_settings_table.php b/database/migrations/2026_06_17_113134_create_devis_settings_table.php new file mode 100644 index 0000000..a7e9b65 --- /dev/null +++ b/database/migrations/2026_06_17_113134_create_devis_settings_table.php @@ -0,0 +1,42 @@ +id(); + $table->string('entity_name')->default("Direction des Systèmes d'Information"); + $table->string('entity_sub')->default("Communauté d'Agglomération Béziers Méditerranée"); + $table->string('email')->default("support.informatique@beziers-mediterranee.fr"); + $table->string('telephone')->default("04.67.01.60.00"); + $table->string('adresse')->nullable()->default("Béziers, France"); + $table->timestamps(); + }); + + \DB::table('devis_settings')->insert([ + 'entity_name' => "Direction des Systèmes d'Information", + 'entity_sub' => "Communauté d'Agglomération Béziers Méditerranée", + 'email' => "support.informatique@beziers-mediterranee.fr", + 'telephone' => "04.67.01.60.00", + 'adresse' => "Béziers, France", + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('devis_settings'); + } +}; diff --git a/package-lock.json b/package-lock.json index 312f8da..55a7e97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "SuivisCommande", + "name": "OrderCheck", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..2610c2f Binary files /dev/null and b/public/logo.png differ diff --git a/resources/js/Layouts/AuthenticatedLayout.vue b/resources/js/Layouts/AuthenticatedLayout.vue index 6c0481a..7b88574 100644 --- a/resources/js/Layouts/AuthenticatedLayout.vue +++ b/resources/js/Layouts/AuthenticatedLayout.vue @@ -51,6 +51,18 @@ const showingNavigationDropdown = ref(false); > Matériels + + Besoins Informatiques + + + Gestion des Devis + @@ -170,6 +182,18 @@ const showingNavigationDropdown = ref(false); > Matériels + + Besoins Informatiques + + + Gestion des Devis + diff --git a/resources/js/Pages/BesoinsInformatiques/Create.vue b/resources/js/Pages/BesoinsInformatiques/Create.vue new file mode 100644 index 0000000..ce13e69 --- /dev/null +++ b/resources/js/Pages/BesoinsInformatiques/Create.vue @@ -0,0 +1,219 @@ + + + diff --git a/resources/js/Pages/BesoinsInformatiques/Edit.vue b/resources/js/Pages/BesoinsInformatiques/Edit.vue new file mode 100644 index 0000000..2eea78d --- /dev/null +++ b/resources/js/Pages/BesoinsInformatiques/Edit.vue @@ -0,0 +1,231 @@ + + + diff --git a/resources/js/Pages/BesoinsInformatiques/Index.vue b/resources/js/Pages/BesoinsInformatiques/Index.vue new file mode 100644 index 0000000..693acd4 --- /dev/null +++ b/resources/js/Pages/BesoinsInformatiques/Index.vue @@ -0,0 +1,113 @@ + + + diff --git a/resources/js/Pages/Devis/Create.vue b/resources/js/Pages/Devis/Create.vue new file mode 100644 index 0000000..a9d5957 --- /dev/null +++ b/resources/js/Pages/Devis/Create.vue @@ -0,0 +1,229 @@ + + + diff --git a/resources/js/Pages/Devis/Edit.vue b/resources/js/Pages/Devis/Edit.vue new file mode 100644 index 0000000..7bb6a98 --- /dev/null +++ b/resources/js/Pages/Devis/Edit.vue @@ -0,0 +1,233 @@ + + + diff --git a/resources/js/Pages/Devis/Index.vue b/resources/js/Pages/Devis/Index.vue new file mode 100644 index 0000000..efd4076 --- /dev/null +++ b/resources/js/Pages/Devis/Index.vue @@ -0,0 +1,190 @@ + + + diff --git a/resources/js/Pages/Devis/Settings.vue b/resources/js/Pages/Devis/Settings.vue new file mode 100644 index 0000000..f2485be --- /dev/null +++ b/resources/js/Pages/Devis/Settings.vue @@ -0,0 +1,124 @@ + + + diff --git a/resources/js/Pages/Devis/Show.vue b/resources/js/Pages/Devis/Show.vue new file mode 100644 index 0000000..a344ec8 --- /dev/null +++ b/resources/js/Pages/Devis/Show.vue @@ -0,0 +1,266 @@ + + + + + diff --git a/resources/js/Pages/Materiels/Index.vue b/resources/js/Pages/Materiels/Index.vue index fab30c6..fcc0e97 100644 --- a/resources/js/Pages/Materiels/Index.vue +++ b/resources/js/Pages/Materiels/Index.vue @@ -317,7 +317,7 @@ const getWarrantyClasses = (hw) => { class="text-slate-500 hover:text-sky-600 dark:text-slate-400 dark:hover:text-sky-400" title="Voir les détails" > - + @@ -327,7 +327,7 @@ const getWarrantyClasses = (hw) => { class="text-slate-500 hover:text-amber-500 dark:text-slate-400 dark:hover:text-amber-400" title="Modifier la fiche" > - + diff --git a/resources/views/pdf/devis.blade.php b/resources/views/pdf/devis.blade.php new file mode 100644 index 0000000..75e2290 --- /dev/null +++ b/resources/views/pdf/devis.blade.php @@ -0,0 +1,259 @@ + + + + + Devis {{ $devis->number }} + + + +
+ + {{-- ─── HEADER ─────────────────────────────────────────── --}} + + + + + + + +
+ + + +
+ @if(file_exists(public_path('logo.png'))) + + @endif + + {{ $settings->entity_name ?? "Direction des Systèmes d'Information" }} +
+ + + + + +
+
+
+ {{ $settings->entity_sub ?? "Communauté d'Agglomération Béziers Méditerranée" }} + @if(!empty($settings->telephone))Téléphone : {{ $settings->telephone }}
@endif + @if(!empty($settings->email))E-mail : {{ $settings->email }}
@endif + @if(!empty($settings->adresse))Adresse : {{ $settings->adresse }}@endif +
+ +
+ + {{-- ─── INFO CARDS ──────────────────────────────────────── --}} + + + + + + +
+
+
DEVIS N° : {{ $devis->number }}
+
+ DATE : {{ \Carbon\Carbon::parse($devis->date_devis)->format('d/m/Y') }}
+ OBJET : {{ $devis->title }} + @if(!empty($devis->notes)) +
CONDITIONS : {{ $devis->notes }} + @endif +
+
+
+
+
DESTINATAIRE :
+
+ {{ $devis->destinataire_nom }} + + {{ $devis->destinataire_type === 'commune' ? 'Commune / Collectivité' : 'Service Interne' }} + + @if(!empty($devis->referent)) +
+ À L'ATTENTION DE : {{ $devis->referent }} +
+ @endif +
+
+
+ +
+ + {{-- ─── TABLEAU LIGNES ──────────────────────────────────── --}} + + + + + + + + + + + @foreach($devis->items as $item) + + + + + + + @endforeach + +
Description :Prix Unitaire :Quantité :Total :
+
{{ $item['designation'] ?? '' }}
+
{{ $item['type'] ?? '' }}
+
{{ number_format($item['prix_unitaire'] ?? 0, 2, ',', "\u{202F}") }} €{{ $item['quantite'] ?? 0 }}{{ number_format(($item['quantite'] ?? 0) * ($item['prix_unitaire'] ?? 0), 2, ',', "\u{202F}") }} €
+ +
+ + {{-- ─── TOTAUX ───────────────────────────────────────────── --}} + + + + + +
+ + + + + + + + + + + + + + + +
TOTAL HT :{{ number_format($devis->total_ht, 2, ',', "\u{202F}") }} €
TVA ({{ $devis->tva_rate }}%) :{{ number_format($devis->total_ttc - $devis->total_ht, 2, ',', "\u{202F}") }} €
TOTAL TTC :{{ number_format($devis->total_ttc, 2, ',', "\u{202F}") }} €
+
+ + {{-- ─── FOOTER : SIGNATURE DESTINATAIRE ────────────────── --}} + + + + + + +
+ + diff --git a/routes/web.php b/routes/web.php index 89371dd..7b6ad07 100644 --- a/routes/web.php +++ b/routes/web.php @@ -8,6 +8,8 @@ use Inertia\Inertia; use App\Http\Controllers\OrderController; use App\Http\Controllers\AttachmentController; use App\Http\Controllers\HardwareController; +use App\Http\Controllers\BesoinInformatiqueController; +use App\Http\Controllers\DevisController; Route::get('/', function () { return redirect()->route('login'); @@ -70,6 +72,19 @@ Route::middleware('auth')->group(function () { // Gestion de matériel d'infrastructure Route::resource('materiels', HardwareController::class); + + // Besoins Informatiques (Mutualisation) + Route::resource('besoins-informatiques', BesoinInformatiqueController::class)->parameters([ + 'besoins-informatiques' => 'besoin_informatique', + ]); + + // Gestion des Devis + Route::get('/devis/settings', [DevisController::class, 'settings'])->name('devis.settings'); + Route::put('/devis/settings', [DevisController::class, 'updateSettings'])->name('devis.settings.update'); + Route::get('/devis/{devi}/pdf', [DevisController::class, 'downloadPdf'])->name('devis.pdf'); + Route::resource('devis', DevisController::class)->parameters([ + 'devis' => 'devi', + ]); }); require __DIR__.'/auth.php';