Compare commits
13 Commits
production
...
production
| Author | SHA1 | Date | |
|---|---|---|---|
| a0d17190bf | |||
| 25b27a7f32 | |||
| 9d29beecfb | |||
| 07dcd6d91d | |||
| 4ce0f3c350 | |||
| 70aed1fbe0 | |||
| b5c15c0425 | |||
| e11d11f10a | |||
| 04c8f648a3 | |||
| 203e92123b | |||
| 9b617eac73 | |||
| 351801d4ac | |||
| 572d7708ec |
19
.gitignore
vendored
19
.gitignore
vendored
@ -1,17 +1,7 @@
|
|||||||
# Ignore tout par défaut
|
# Ignore tout par défaut
|
||||||
*
|
vendor/
|
||||||
|
config/
|
||||||
# Exceptions : fichiers et dossiers à inclure
|
data/
|
||||||
!.gitignore
|
|
||||||
!Jenkinsfile
|
|
||||||
|
|
||||||
# Dossiers à inclure
|
|
||||||
!calendar/
|
|
||||||
!gestion/
|
|
||||||
|
|
||||||
# Inclure tout le contenu de ces dossiers
|
|
||||||
!calendar/**
|
|
||||||
!gestion/**
|
|
||||||
|
|
||||||
# Ignorer spécifiquement (même dans les dossiers inclus)
|
# Ignorer spécifiquement (même dans les dossiers inclus)
|
||||||
*.sql
|
*.sql
|
||||||
@ -23,3 +13,6 @@ node_modules/
|
|||||||
**/.env.*
|
**/.env.*
|
||||||
**/dist/
|
**/dist/
|
||||||
**/build/
|
**/build/
|
||||||
|
|
||||||
|
*.sh
|
||||||
|
docker-compose.yml
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"symfony/framework-bundle": "^5.4"
|
"symfony/framework-bundle": "^5.4"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"setasign/fpdf": "^1.8"
|
"setasign/fpdf": "^1.8",
|
||||||
|
"dompdf/dompdf": "^3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
298
gestion/composer.lock
generated
298
gestion/composer.lock
generated
@ -4,8 +4,296 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "79912f1c84e373fcd7778fb095176063",
|
"content-hash": "2cbec79cf4e2f6e464d23e0fd4df0b09",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "dompdf/dompdf",
|
||||||
|
"version": "v3.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/dompdf.git",
|
||||||
|
"reference": "a51bd7a063a65499446919286fb18b518177155a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a",
|
||||||
|
"reference": "a51bd7a063a65499446919286fb18b518177155a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dompdf/php-font-lib": "^1.0.0",
|
||||||
|
"dompdf/php-svg-lib": "^1.0.0",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"masterminds/html5": "^2.0",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"mockery/mockery": "^1.3",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "Needed to process images",
|
||||||
|
"ext-gmagick": "Improves image processing performance",
|
||||||
|
"ext-imagick": "Improves image processing performance",
|
||||||
|
"ext-zlib": "Needed for pdf stream compression"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dompdf\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"lib/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The Dompdf Community",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||||
|
"source": "https://github.com/dompdf/dompdf/tree/v3.1.0"
|
||||||
|
},
|
||||||
|
"time": "2025-01-15T14:09:04+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-font-lib",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-font-lib.git",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"FontLib\\": "src/FontLib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The FontLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse, export and make subsets of different types of font files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-font-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.1"
|
||||||
|
},
|
||||||
|
"time": "2024-12-02T14:37:59+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-svg-lib",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"sabberworm/php-css-parser": "^8.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Svg\\": "src/Svg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The SvgLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse and export to PDF SVG files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0"
|
||||||
|
},
|
||||||
|
"time": "2024-04-29T13:26:35+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "masterminds/html5",
|
||||||
|
"version": "2.10.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Masterminds/html5-php.git",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"php": ">=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": "sabberworm/php-css-parser",
|
||||||
|
"version": "v8.9.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
|
||||||
|
"rawr/cross-data-providers": "^2.0.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "9.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"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/v8.9.0"
|
||||||
|
},
|
||||||
|
"time": "2025-07-11T13:20:48+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setasign/fpdf",
|
"name": "setasign/fpdf",
|
||||||
"version": "1.8.5",
|
"version": "1.8.5",
|
||||||
@ -4777,10 +5065,10 @@
|
|||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": [],
|
"stability-flags": {},
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": [],
|
"platform": {},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace OCA\Gestion\Controller;
|
namespace OCA\Gestion\Controller;
|
||||||
|
|
||||||
use OCA\Gestion\Constants\BddConstant;
|
use OCA\Gestion\Constants\BddConstant;
|
||||||
@ -43,9 +44,7 @@ class InvoiceController extends Controller
|
|||||||
IMailer $mailer,
|
IMailer $mailer,
|
||||||
MailerService $mailerService,
|
MailerService $mailerService,
|
||||||
IUserSession $userSession
|
IUserSession $userSession
|
||||||
|
) {
|
||||||
)
|
|
||||||
{
|
|
||||||
$this->currentUserIdNextcloud = $UserId;
|
$this->currentUserIdNextcloud = $UserId;
|
||||||
$this->invoicePdfService = $invoicePdfService;
|
$this->invoicePdfService = $invoicePdfService;
|
||||||
$this->rootFolder = $rootFolder;
|
$this->rootFolder = $rootFolder;
|
||||||
@ -68,10 +67,10 @@ class InvoiceController extends Controller
|
|||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function getInvoicePdfContent($factureId){
|
public function getInvoicePdfContent($factureId)
|
||||||
$facture = $this->gestionRepository->getFactureByFactureId($factureId);
|
|
||||||
if($facture == null)
|
|
||||||
{
|
{
|
||||||
|
$facture = $this->gestionRepository->getFactureByFactureId($factureId);
|
||||||
|
if($facture == null) {
|
||||||
return new DataResponse("La facture n'existe pas", 404, ['Content-Type' => 'application/json']);
|
return new DataResponse("La facture n'existe pas", 404, ['Content-Type' => 'application/json']);
|
||||||
}
|
}
|
||||||
$factureGeneratedResponse = $this->invoicePdfService->generateFacturePdfByFactureId($factureId, $this->currentUserIdNextcloud);
|
$factureGeneratedResponse = $this->invoicePdfService->generateFacturePdfByFactureId($factureId, $this->currentUserIdNextcloud);
|
||||||
@ -91,8 +90,7 @@ class InvoiceController extends Controller
|
|||||||
public function sendInvoicePdfViaMail($factureId, $email = '')
|
public function sendInvoicePdfViaMail($factureId, $email = '')
|
||||||
{
|
{
|
||||||
$facture = $this->gestionRepository->getFactureByFactureId($factureId);
|
$facture = $this->gestionRepository->getFactureByFactureId($factureId);
|
||||||
if($facture == null)
|
if($facture == null) {
|
||||||
{
|
|
||||||
return new DataResponse("La facture n'existe pas", 404, ['Content-Type' => 'application/json']);
|
return new DataResponse("La facture n'existe pas", 404, ['Content-Type' => 'application/json']);
|
||||||
}
|
}
|
||||||
$factureGeneratedResponse = $this->invoicePdfService->generateFacturePdfByFactureId($factureId, $this->currentUserIdNextcloud);
|
$factureGeneratedResponse = $this->invoicePdfService->generateFacturePdfByFactureId($factureId, $this->currentUserIdNextcloud);
|
||||||
@ -109,7 +107,8 @@ class InvoiceController extends Controller
|
|||||||
$message->attach($content);
|
$message->attach($content);
|
||||||
$message->setSubject("Facture");
|
$message->setSubject("Facture");
|
||||||
|
|
||||||
$signature = $this->mailerService->getFooterContent();
|
$signature = $this->mailerService->getFooterContent($this->getUserNameForEmailSignature());
|
||||||
|
|
||||||
|
|
||||||
$message->setHtmlBody(
|
$message->setHtmlBody(
|
||||||
"<p>Bonjour.</p>".
|
"<p>Bonjour.</p>".
|
||||||
@ -128,4 +127,11 @@ class InvoiceController extends Controller
|
|||||||
}
|
}
|
||||||
return new DataResponse("E-mail envoyé avec succès à ".$email.".", 200, ['Content-Type' => 'application/json']);
|
return new DataResponse("E-mail envoyé avec succès à ".$email.".", 200, ['Content-Type' => 'application/json']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUserNameForEmailSignature()
|
||||||
|
{
|
||||||
|
$configs = json_decode($this->gestionRepository->getConfiguration(BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD));
|
||||||
|
$currentConfig = $configs[0];
|
||||||
|
return $currentConfig->nom . " " . $currentConfig->prenom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -3352,6 +3352,7 @@ class Bdd
|
|||||||
if($factureData == null) {
|
if($factureData == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$products = $this->getDevisProduits($factureData["devis_id"]);
|
$products = $this->getDevisProduits($factureData["devis_id"]);
|
||||||
$isDevisNegative = $this->isDevisNegative($factureData['devis_id'], $factureData['client_id']);
|
$isDevisNegative = $this->isDevisNegative($factureData['devis_id'], $factureData['client_id']);
|
||||||
$factureData = $this->setDevisStartAndEndTime($factureData);
|
$factureData = $this->setDevisStartAndEndTime($factureData);
|
||||||
@ -3359,6 +3360,11 @@ class Bdd
|
|||||||
$factureData["products"] = $products;
|
$factureData["products"] = $products;
|
||||||
$factureData["configuration"] = $configuration;
|
$factureData["configuration"] = $configuration;
|
||||||
|
|
||||||
|
// Récupération des informations client et gestion TVA
|
||||||
|
$client = $this->getClientById($factureData['client_id']);
|
||||||
|
$hasTva = ($client && isset($client['tva'])) ? ($client['tva'] == 1) : true;
|
||||||
|
$groupClient = $this->getTvaItracomuIdClient($factureData['client_id']);
|
||||||
|
|
||||||
$isClientInsideGroup = $factureData["group_id"] != null;
|
$isClientInsideGroup = $factureData["group_id"] != null;
|
||||||
if($isClientInsideGroup) {
|
if($isClientInsideGroup) {
|
||||||
$factureData["client_real_adress"] = $factureData["group_address"];
|
$factureData["client_real_adress"] = $factureData["group_address"];
|
||||||
@ -3371,11 +3377,15 @@ class Bdd
|
|||||||
$factureData["client_real_adress"] = $clientAdresses["address"];
|
$factureData["client_real_adress"] = $clientAdresses["address"];
|
||||||
$factureData["client_adress_city"] = $clientAdresses["city"];
|
$factureData["client_adress_city"] = $clientAdresses["city"];
|
||||||
}
|
}
|
||||||
|
|
||||||
$factureData['is_negative'] = $isDevisNegative;
|
$factureData['is_negative'] = $isDevisNegative;
|
||||||
|
$factureData["is_tva"] = $hasTva;
|
||||||
|
$factureData["client_tva_intracommu"] = $groupClient["tva_intracommu"];
|
||||||
|
|
||||||
$configurationAdresses = FileExportHelpers::GetAddressAndCityFromAddress($configuration->adresse);
|
$configurationAdresses = FileExportHelpers::GetAddressAndCityFromAddress($configuration->adresse);
|
||||||
$factureData["configuration_adresse"] = $configurationAdresses["address"];
|
$factureData["configuration_adresse"] = $configurationAdresses["address"];
|
||||||
$factureData["configuration_adresse_city"] = $configurationAdresses["city"];
|
$factureData["configuration_adresse_city"] = $configurationAdresses["city"];
|
||||||
|
|
||||||
return $factureData;
|
return $factureData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3522,6 +3532,13 @@ class Bdd
|
|||||||
$products = $this->getDevisProduits($invoice["devis_id"]);
|
$products = $this->getDevisProduits($invoice["devis_id"]);
|
||||||
$invoice["products"] = $products;
|
$invoice["products"] = $products;
|
||||||
$invoice["configuration"] = $configuration;
|
$invoice["configuration"] = $configuration;
|
||||||
|
// Déterminer la TVA pour cette facture
|
||||||
|
$hasTva = true; // Valeur par défaut
|
||||||
|
if(isset($invoice['client_id']) && $invoice['client_id']) {
|
||||||
|
$client = $this->getClientById($invoice['client_id']);
|
||||||
|
$hasTva = ($client && isset($client['tva'])) ? ($client['tva'] == 1) : true;
|
||||||
|
}
|
||||||
|
$invoice["is_tva"] = $hasTva;
|
||||||
|
|
||||||
$isClientInsideGroup = $invoice["group_id"] != null;
|
$isClientInsideGroup = $invoice["group_id"] != null;
|
||||||
if($isClientInsideGroup) {
|
if($isClientInsideGroup) {
|
||||||
@ -5318,7 +5335,7 @@ COMMENTAIRES: ".$comment;
|
|||||||
$configuration = $this->getConfiguration(BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD);
|
$configuration = $this->getConfiguration(BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD);
|
||||||
$configuration = json_decode($configuration);
|
$configuration = json_decode($configuration);
|
||||||
$currentConfig = $configuration[0];
|
$currentConfig = $configuration[0];
|
||||||
$tvaValue = $currentConfig->tva_default;
|
|
||||||
$isFactureSingleClient = $facture['fk_client_id'] != null
|
$isFactureSingleClient = $facture['fk_client_id'] != null
|
||||||
&& $facture['fk_client_id'] != 0;
|
&& $facture['fk_client_id'] != 0;
|
||||||
|
|
||||||
@ -5329,6 +5346,26 @@ COMMENTAIRES: ".$comment;
|
|||||||
$devis = $this->getDevisByFkFactureId($factureId);
|
$devis = $this->getDevisByFkFactureId($factureId);
|
||||||
$factureGroupIsRelatedToAnyDevis = $devis != null;
|
$factureGroupIsRelatedToAnyDevis = $devis != null;
|
||||||
|
|
||||||
|
// LOGIQUE TVA SIMPLIFIÉE
|
||||||
|
$tvaValue = (float)$currentConfig->tva_default;
|
||||||
|
$isTvaApplicable = true;
|
||||||
|
|
||||||
|
// Récupérer le statut TVA du client de cette facture
|
||||||
|
$clientId = $facture['fk_client_id'];
|
||||||
|
if ($clientId != null && $clientId != 0) {
|
||||||
|
$client = $this->getClientById($clientId);
|
||||||
|
if (isset($client['tva']) && $client['tva'] == 0) {
|
||||||
|
$isTvaApplicable = false;
|
||||||
|
$tvaValue = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$clientId = $devis['id_client'];
|
||||||
|
$client = $this->getClientById($clientId);
|
||||||
|
if (isset($client['tva']) && $client['tva'] == 0) {
|
||||||
|
$isTvaApplicable = false;
|
||||||
|
$tvaValue = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($isFactureSingleClient) {
|
if($isFactureSingleClient) {
|
||||||
$client = $this->getClientById($facture['fk_client_id']);
|
$client = $this->getClientById($facture['fk_client_id']);
|
||||||
@ -5337,6 +5374,7 @@ COMMENTAIRES: ".$comment;
|
|||||||
$facture['client_address'] = $client["client_address"];
|
$facture['client_address'] = $client["client_address"];
|
||||||
$facture['siret'] = $client["client_legal_one"];
|
$facture['siret'] = $client["client_legal_one"];
|
||||||
$facture['mail'] = $client["client_mail"];
|
$facture['mail'] = $client["client_mail"];
|
||||||
|
|
||||||
if (!$factureGroupIsRelatedToAnyDevis) {
|
if (!$factureGroupIsRelatedToAnyDevis) {
|
||||||
$devisList = $this->getDevisDataByClientIdAndMonthYear(
|
$devisList = $this->getDevisDataByClientIdAndMonthYear(
|
||||||
$facture['fk_client_id'],
|
$facture['fk_client_id'],
|
||||||
@ -5344,7 +5382,6 @@ COMMENTAIRES: ".$comment;
|
|||||||
$facture['year'],
|
$facture['year'],
|
||||||
$devisMentionFilters
|
$devisMentionFilters
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$devisList = $this->getDevisDataGroupByFactureId($factureId, $devisMentionFilters);
|
$devisList = $this->getDevisDataGroupByFactureId($factureId, $devisMentionFilters);
|
||||||
}
|
}
|
||||||
@ -5355,6 +5392,7 @@ COMMENTAIRES: ".$comment;
|
|||||||
$facture['client_address'] = $clientGroupFacturation["address"] . ' - ' .$clientGroupFacturation["postal_code"] . ' ' . $clientGroupFacturation['city'];
|
$facture['client_address'] = $clientGroupFacturation["address"] . ' - ' .$clientGroupFacturation["postal_code"] . ' ' . $clientGroupFacturation['city'];
|
||||||
$facture['siret'] = $clientGroupFacturation["siret_number"];
|
$facture['siret'] = $clientGroupFacturation["siret_number"];
|
||||||
$facture['mail'] = $clientGroupFacturation["email"];
|
$facture['mail'] = $clientGroupFacturation["email"];
|
||||||
|
|
||||||
if (!$factureGroupIsRelatedToAnyDevis) {
|
if (!$factureGroupIsRelatedToAnyDevis) {
|
||||||
$devisList = $this->getDevisDataByClientGroupFacturationIdAndMonthYear(
|
$devisList = $this->getDevisDataByClientGroupFacturationIdAndMonthYear(
|
||||||
$facture['fk_client_group_facturation_id'],
|
$facture['fk_client_group_facturation_id'],
|
||||||
@ -5366,22 +5404,36 @@ COMMENTAIRES: ".$comment;
|
|||||||
$devisList = $this->getDevisDataGroupByFactureId($factureId, $devisMentionFilters);
|
$devisList = $this->getDevisDataGroupByFactureId($factureId, $devisMentionFilters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$factureTotalHt = 0;
|
$factureTotalHt = 0;
|
||||||
$factureTotalTva = 0;
|
$factureTotalTva = 0;
|
||||||
$factureTotalTtc = 0;
|
$factureTotalTtc = 0;
|
||||||
|
|
||||||
foreach($devisList as &$currentDevis) {
|
foreach($devisList as &$currentDevis) {
|
||||||
$totalHt = 0;
|
$totalHt = 0;
|
||||||
$totalTva = 0;
|
$totalTva = 0;
|
||||||
$totalTtc = 0;
|
$totalTtc = 0;
|
||||||
$devisProducts = $this->getDevisProduits($currentDevis['devis_id']);
|
$devisProducts = $this->getDevisProduits($currentDevis['devis_id']);
|
||||||
|
|
||||||
foreach($devisProducts as $currentProduct) {
|
foreach($devisProducts as $currentProduct) {
|
||||||
$valueHt = $currentProduct['produit_price'] * $currentProduct['quantite'];
|
$valueHt = $currentProduct['produit_price'] * $currentProduct['quantite'];
|
||||||
|
|
||||||
|
// CALCUL SIMPLE : TVA OU PAS TVA
|
||||||
|
if ($isTvaApplicable) {
|
||||||
|
// Client soumis à TVA : utiliser le taux par défaut
|
||||||
$valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt, $tvaValue);
|
$valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt, $tvaValue);
|
||||||
|
$tvaAmount = $valueTtc - $valueHt;
|
||||||
|
} else {
|
||||||
|
// Client exonéré : TTC = HT
|
||||||
|
$valueTtc = $valueHt;
|
||||||
|
$tvaAmount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
$totalHt += $valueHt;
|
$totalHt += $valueHt;
|
||||||
$totalTtc += $valueTtc;
|
$totalTtc += $valueTtc;
|
||||||
$tvaAmount = $valueTtc - $valueHt;
|
|
||||||
$totalTva += $tvaAmount;
|
$totalTva += $tvaAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
$currentDevis["totalHt"] = $totalHt;
|
$currentDevis["totalHt"] = $totalHt;
|
||||||
$currentDevis["totalTtc"] = $totalTtc;
|
$currentDevis["totalTtc"] = $totalTtc;
|
||||||
$currentDevis["totalTva"] = $totalTva;
|
$currentDevis["totalTva"] = $totalTva;
|
||||||
@ -5390,10 +5442,19 @@ COMMENTAIRES: ".$comment;
|
|||||||
$factureTotalTva += $totalTva;
|
$factureTotalTva += $totalTva;
|
||||||
$facture["devisList"][] = $currentDevis;
|
$facture["devisList"][] = $currentDevis;
|
||||||
}
|
}
|
||||||
|
|
||||||
$facture["totalHt"] = $factureTotalHt;
|
$facture["totalHt"] = $factureTotalHt;
|
||||||
$facture["totalTtc"] = $factureTotalTtc;
|
$facture["totalTtc"] = $factureTotalTtc;
|
||||||
$facture["totalTva"] = $factureTotalTva;
|
$facture["totalTva"] = $factureTotalTva;
|
||||||
$facture["isFactureClientGroup"] = !$isFactureSingleClient;
|
$facture["isFactureClientGroup"] = !$isFactureSingleClient;
|
||||||
|
|
||||||
|
// INFOS TVA POUR LE TEMPLATE
|
||||||
|
$facture["tvaInfo"] = [
|
||||||
|
'is_applicable' => $isTvaApplicable,
|
||||||
|
'rate' => $tvaValue,
|
||||||
|
'is_exempt' => !$isTvaApplicable
|
||||||
|
];
|
||||||
|
|
||||||
return $facture;
|
return $facture;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5402,6 +5463,7 @@ COMMENTAIRES: ".$comment;
|
|||||||
$defaultTvaValue = $configuration->tva_default;
|
$defaultTvaValue = $configuration->tva_default;
|
||||||
$factureData = $this->getFactureByFactureId($factureId);
|
$factureData = $this->getFactureByFactureId($factureId);
|
||||||
$isFactureForSingleClient = $factureData['fk_client_id'] != null && $factureData['fk_client_id'] != 0;
|
$isFactureForSingleClient = $factureData['fk_client_id'] != null && $factureData['fk_client_id'] != 0;
|
||||||
|
|
||||||
$devisMentionFilters = [
|
$devisMentionFilters = [
|
||||||
DevisMentionConstant::FACTURED_FORMATTED,
|
DevisMentionConstant::FACTURED_FORMATTED,
|
||||||
DevisMentionConstant::FACTURED
|
DevisMentionConstant::FACTURED
|
||||||
@ -5409,6 +5471,16 @@ COMMENTAIRES: ".$comment;
|
|||||||
$devis = $this->getDevisByFkFactureId($factureId);
|
$devis = $this->getDevisByFkFactureId($factureId);
|
||||||
$factureGroupIsRelatedToAnyDevis = $devis != null;
|
$factureGroupIsRelatedToAnyDevis = $devis != null;
|
||||||
|
|
||||||
|
$hasTva = true; // Valeur par défaut
|
||||||
|
if($isFactureForSingleClient) {
|
||||||
|
$client = $this->getClientById($factureData['fk_client_id']);
|
||||||
|
$hasTva = ($client && isset($client['tva'])) ? ($client['tva'] == 1) : true;
|
||||||
|
$groupClient = $this->getTvaItracomuIdClient($factureData['fk_client_id']);
|
||||||
|
} else {
|
||||||
|
$client = $this->getClientById($devis['id_client']);
|
||||||
|
$hasTva = ($client && isset($client['tva'])) ? ($client['tva'] == 1) : true;
|
||||||
|
$groupClient = $this->getTvaItracomuIdClient($devis['id_client']);
|
||||||
|
}
|
||||||
// Déterminer le taux de TVA global pour l'affichage
|
// Déterminer le taux de TVA global pour l'affichage
|
||||||
$globalTvaValue = $defaultTvaValue;
|
$globalTvaValue = $defaultTvaValue;
|
||||||
|
|
||||||
@ -5437,7 +5509,6 @@ COMMENTAIRES: ".$comment;
|
|||||||
} else {
|
} else {
|
||||||
$factureDevisList = $this->getDevisDataGroupByFactureId($factureId, $devisMentionFilters);
|
$factureDevisList = $this->getDevisDataGroupByFactureId($factureId, $devisMentionFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
$factureIncrement = 0;
|
$factureIncrement = 0;
|
||||||
$productsCount = 0;
|
$productsCount = 0;
|
||||||
$totalHt = 0;
|
$totalHt = 0;
|
||||||
@ -5525,15 +5596,22 @@ COMMENTAIRES: ".$comment;
|
|||||||
} elseif($globalTvaValue > 0) {
|
} elseif($globalTvaValue > 0) {
|
||||||
$tvaLabel = "TVA ".$globalTvaValue. "%";
|
$tvaLabel = "TVA ".$globalTvaValue. "%";
|
||||||
} else {
|
} else {
|
||||||
$tvaLabel = "TVA (exonéré)";
|
$tvaLabel = "TVA 0 %";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($hasTva) {
|
||||||
$totaPricesArray = [
|
$totaPricesArray = [
|
||||||
"TOTAL HT" => $totalHt,
|
"TOTAL HT" => $totalHt,
|
||||||
$tvaLabel => $totalTva,
|
$tvaLabel => $totalTva,
|
||||||
"TOTAL TTC" => $totalTtc
|
"TOTAL TTC" => $totalTtc
|
||||||
];
|
];
|
||||||
|
} else {
|
||||||
|
$totaPricesArray = [
|
||||||
|
"TOTAL HT" => $totalHt
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$factureData["is_tva"] = $hasTva;
|
||||||
$factureData["devis"] = $factureDevisList;
|
$factureData["devis"] = $factureDevisList;
|
||||||
$factureData["configuration"] = $configuration;
|
$factureData["configuration"] = $configuration;
|
||||||
$configurationAdresses = FileExportHelpers::GetAddressAndCityFromAddress($configuration->adresse);
|
$configurationAdresses = FileExportHelpers::GetAddressAndCityFromAddress($configuration->adresse);
|
||||||
@ -5542,6 +5620,7 @@ COMMENTAIRES: ".$comment;
|
|||||||
$factureData["productsCount"] = $productsCount;
|
$factureData["productsCount"] = $productsCount;
|
||||||
$factureData["totalPrices"] = $totaPricesArray;
|
$factureData["totalPrices"] = $totaPricesArray;
|
||||||
$factureData["template_type_key"] = $templateType;
|
$factureData["template_type_key"] = $templateType;
|
||||||
|
$factureData["client_tva_intracommu"] = $groupClient["tva_intracommu"];
|
||||||
return $factureData;
|
return $factureData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5633,4 +5712,25 @@ COMMENTAIRES: ".$comment;
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTvaItracomuIdClient($clientId)
|
||||||
|
{
|
||||||
|
$sql = "SELECT
|
||||||
|
gf.tva_intracommu
|
||||||
|
FROM ".$this->tableprefix."client_group_facturation AS gf
|
||||||
|
LEFT JOIN ".$this->tableprefix."client AS gc
|
||||||
|
ON gc.fk_client_group_facturation_id = gf.id
|
||||||
|
WHERE gc.id = ?;";
|
||||||
|
|
||||||
|
$data = $this->execSQLNoJsonReturn(
|
||||||
|
$sql,
|
||||||
|
[$clientId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!empty($data)) {
|
||||||
|
return $data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
gestion/lib/Exception/TemplateException.php
Normal file
7
gestion/lib/Exception/TemplateException.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\Gestion\Exception;
|
||||||
|
|
||||||
|
class TemplateException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
126
gestion/lib/Service/HtmlToPdfService.php
Normal file
126
gestion/lib/Service/HtmlToPdfService.php
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\Gestion\Service;
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
use OCA\Gestion\Exception\TemplateException;
|
||||||
|
|
||||||
|
class HtmlToPdfService
|
||||||
|
{
|
||||||
|
private $templatesPath;
|
||||||
|
private $assetsPath;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->templatesPath = __DIR__ . '/../../templates/pdf/';
|
||||||
|
$this->assetsPath = '/var/www/html/data/admin/files/.gestion/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePdf($templateName, $data, $options = [])
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$htmlContent = $this->renderPhpTemplate($templateName, $data);
|
||||||
|
return $this->convertToPdf($htmlContent, $options);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('HtmlToPdfService Error: ' . $e->getMessage());
|
||||||
|
throw new TemplateException('Erreur génération PDF: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rend un template PHP avec les données
|
||||||
|
*/
|
||||||
|
private function renderPhpTemplate($templateName, $data)
|
||||||
|
{
|
||||||
|
$templateFile = $this->templatesPath . $templateName . '.php';
|
||||||
|
|
||||||
|
if (!file_exists($templateFile)) {
|
||||||
|
throw new TemplateException("Template introuvable: " . $templateFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$templateData = array_merge($data, [
|
||||||
|
'logo_base64' => $this->getLogoBase64()
|
||||||
|
]);
|
||||||
|
|
||||||
|
extract($templateData);
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
include $templateFile;
|
||||||
|
return ob_get_clean();
|
||||||
|
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
ob_end_clean();
|
||||||
|
throw new TemplateException("Erreur lors du rendu du template: " . $e->getMessage(), 0, $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère le logo en base64
|
||||||
|
*/
|
||||||
|
private function getLogoBase64()
|
||||||
|
{
|
||||||
|
$logoPath = $this->assetsPath . 'logo.png';
|
||||||
|
|
||||||
|
if (file_exists($logoPath)) {
|
||||||
|
return base64_encode(file_get_contents($logoPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retour d'un pixel transparent si pas de logo
|
||||||
|
return 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convertit HTML en PDF
|
||||||
|
*/
|
||||||
|
private function convertToPdf($htmlContent, $options = [])
|
||||||
|
{
|
||||||
|
$dompdfOptions = new Options();
|
||||||
|
$dompdfOptions->set('defaultFont', 'DejaVu Sans');
|
||||||
|
$dompdfOptions->set('isRemoteEnabled', true);
|
||||||
|
$dompdfOptions->set('isHtml5ParserEnabled', true);
|
||||||
|
$dompdfOptions->set('enable_css_float', true);
|
||||||
|
$dompdfOptions->set('enable_font_subsetting', true);
|
||||||
|
|
||||||
|
$paper = $options['paper'] ?? 'A4';
|
||||||
|
$orientation = $options['orientation'] ?? 'portrait';
|
||||||
|
|
||||||
|
$dompdf = new Dompdf($dompdfOptions);
|
||||||
|
$dompdf->loadHtml($htmlContent);
|
||||||
|
$dompdf->setPaper($paper, $orientation);
|
||||||
|
$dompdf->render();
|
||||||
|
|
||||||
|
return $dompdf->output();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateInvoiceFilename($factureData, $prefix = 'FACTURE')
|
||||||
|
{
|
||||||
|
$numero = str_pad($factureData['num'] ?? '', 6, '0', STR_PAD_LEFT);
|
||||||
|
$month = str_pad($factureData['month'] ?? date('m'), 2, '0', STR_PAD_LEFT);
|
||||||
|
$year = $factureData['year'] ?? date('Y');
|
||||||
|
|
||||||
|
return "{$prefix}_{$numero}_{$month}_{$year}.pdf";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug template PHP
|
||||||
|
*/
|
||||||
|
public function debugTemplate($templateName, $data)
|
||||||
|
{
|
||||||
|
echo "=== DONNÉES REÇUES ===\n";
|
||||||
|
var_dump($data);
|
||||||
|
|
||||||
|
echo "\n=== TEMPLATE PHP UTILISÉ ===\n";
|
||||||
|
$templateFile = $this->templatesPath . $templateName . '.php';
|
||||||
|
echo "Fichier: $templateFile\n";
|
||||||
|
echo "Existe: " . (file_exists($templateFile) ? "OUI" : "NON") . "\n";
|
||||||
|
|
||||||
|
echo "\n=== HTML GÉNÉRÉ ===\n";
|
||||||
|
$html = $this->renderPhpTemplate($templateName, $data);
|
||||||
|
echo substr($html, 0, 2000) . "...\n";
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -27,7 +27,7 @@ declare(strict_types=1);
|
|||||||
namespace OCA\Gestion\Service\InvoiceGroupPdfHandler;
|
namespace OCA\Gestion\Service\InvoiceGroupPdfHandler;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use \FPDF;
|
use FPDF;
|
||||||
use OCA\Gestion\Helpers\FileExportHelpers;
|
use OCA\Gestion\Helpers\FileExportHelpers;
|
||||||
use OCA\Gestion\Helpers\PriceHelpers;
|
use OCA\Gestion\Helpers\PriceHelpers;
|
||||||
|
|
||||||
@ -50,15 +50,16 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
|
|
||||||
public $thereIsOrderOrCaseNumber = false;
|
public $thereIsOrderOrCaseNumber = false;
|
||||||
public $startingYOfArticlesTable = 100;
|
public $startingYOfArticlesTable = 100;
|
||||||
public int $maxArticlePerPage = 19;
|
public int $maxArticlePerPage = 7;
|
||||||
public $additionalArticlesLineBasedOnMultiline = 0;
|
public $additionalArticlesLineBasedOnMultiline = 0;
|
||||||
public $interLigneHeader = 5;
|
public $interLigneHeader = 5;
|
||||||
|
public $hasTva = true;
|
||||||
|
|
||||||
function Header()
|
public function Header()
|
||||||
{
|
{
|
||||||
if ($this->logo != "nothing") {
|
if ($this->logo != "nothing") {
|
||||||
$this->Image($this->logoPath . "logo.png", 4, 2, 50, 35);
|
$this->Image($this->logoPath . "logo.png", 4, 2, 50, 35);
|
||||||
$this->AddWatermark();
|
//$this->AddWatermark();
|
||||||
} else {
|
} else {
|
||||||
$this->Cell(55, 30, '');
|
$this->Cell(55, 30, '');
|
||||||
}
|
}
|
||||||
@ -66,8 +67,19 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$this->DrawInvoiceCompanyAndClientInfo();
|
$this->DrawInvoiceCompanyAndClientInfo();
|
||||||
$this->DrawInvoiceInfoTable();
|
$this->DrawInvoiceInfoTable();
|
||||||
}
|
}
|
||||||
function AddWatermark()
|
|
||||||
|
public function SafeTextForPdf($text)
|
||||||
{
|
{
|
||||||
|
if (empty($text)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML401, 'UTF-8');
|
||||||
|
return iconv('UTF-8', 'ISO-8859-1//IGNORE', $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function AddWatermark()
|
||||||
|
{
|
||||||
|
try {
|
||||||
$this->SetAlpha(0.2);
|
$this->SetAlpha(0.2);
|
||||||
|
|
||||||
$imagePath = $this->logoPath . "filigrane_pdf.png";
|
$imagePath = $this->logoPath . "filigrane_pdf.png";
|
||||||
@ -89,9 +101,13 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
// Ajouter l'image en filigrane
|
// Ajouter l'image en filigrane
|
||||||
$this->Image($imagePath, $x, $y, $width, $height); // Chemin, position x, position y, largeur, hauteur
|
$this->Image($imagePath, $x, $y, $width, $height); // Chemin, position x, position y, largeur, hauteur
|
||||||
$this->SetAlpha(0.1); // Définir l'opacité
|
$this->SetAlpha(0.1); // Définir l'opacité
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetAlpha($alpha)
|
}
|
||||||
|
|
||||||
|
public function SetAlpha($alpha)
|
||||||
{
|
{
|
||||||
// Appliquer la transparence au document
|
// Appliquer la transparence au document
|
||||||
$this->SetFillColor(255, 255, 255, $alpha * 255);
|
$this->SetFillColor(255, 255, 255, $alpha * 255);
|
||||||
@ -106,21 +122,21 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Footer()
|
public function Footer()
|
||||||
{
|
{
|
||||||
$this->SetY(-34);
|
$this->SetY(-34);
|
||||||
$this->SetFont('ComicSans', '', 7);
|
$this->SetFont('Arial', '', 7);
|
||||||
|
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('Tout retard de paiement entraînera de plein droit une pénalité de retard de 3 fois le taux légal ')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('Tout retard de paiement entraînera de plein droit une pénalité de retard de 3 fois le taux légal '));
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('(Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40 EUR pour frais de recouvrement sera appliquée.')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('(Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40 EUR pour frais de recouvrement sera appliquée.'));
|
||||||
|
|
||||||
$this->Ln(1);
|
$this->Ln(1);
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('Si les frais de recouvrement sont supérieurs à ce montant forfaitaire, une indemnisation complémentaire')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('Si les frais de recouvrement sont supérieurs à ce montant forfaitaire, une indemnisation complémentaire'));
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('sera due sur présentation de justificatifs (articles L.441-3 et L.441-6 du code de commerce).')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('sera due sur présentation de justificatifs (articles L.441-3 et L.441-6 du code de commerce).'));
|
||||||
|
|
||||||
$this->SetY(-10);
|
$this->SetY(-10);
|
||||||
$this->SetFont('ComicSans', '', 7);
|
$this->SetFont('Arial', '', 7);
|
||||||
$this->Cell(0, 10, utf8_decode(html_entity_decode($this->factureData['configuration']->legal_one)), 0, 0, 'C');
|
$this->Cell(0, 10, $this->SafeTextForPdf($this->factureData['configuration']->legal_one), 0, 0, 'C');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function InvoicePdfFactory(array $factureData, $logo = null)
|
public function InvoicePdfFactory(array $factureData, $logo = null)
|
||||||
@ -132,6 +148,8 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$this->devisCountToGet = ($this->devisCount <= $this->maxArticlePerPage) ? $this->devisCount : $this->maxArticlePerPage;
|
$this->devisCountToGet = ($this->devisCount <= $this->maxArticlePerPage) ? $this->devisCount : $this->maxArticlePerPage;
|
||||||
$this->devisList = $this->factureData['devis'];
|
$this->devisList = $this->factureData['devis'];
|
||||||
$this->logo = $logo;
|
$this->logo = $logo;
|
||||||
|
// Déterminer si la TVA est applicable
|
||||||
|
$this->hasTva = isset($factureData['is_tva']) ? $factureData['is_tva'] : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetInvoiceFilename()
|
public function GetInvoiceFilename()
|
||||||
@ -167,7 +185,7 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
public function DrawInvoiceCompanyInfo()
|
public function DrawInvoiceCompanyInfo()
|
||||||
{
|
{
|
||||||
$this->SetY(40);
|
$this->SetY(40);
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport($this->factureData['configuration']->entreprise), 0, 1);
|
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport($this->factureData['configuration']->entreprise), 0, 1);
|
||||||
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport($this->factureData['configuration_adresse']), 0, 1);
|
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport($this->factureData['configuration_adresse']), 0, 1);
|
||||||
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport($this->factureData['configuration_adresse_city']), 0, 1);
|
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport($this->factureData['configuration_adresse_city']), 0, 1);
|
||||||
@ -176,7 +194,7 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
}
|
}
|
||||||
public function DrawInvoiceClientInfo()
|
public function DrawInvoiceClientInfo()
|
||||||
{
|
{
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
$clientName = $this->factureData['group_name'];
|
$clientName = $this->factureData['group_name'];
|
||||||
$clientInfoXAxis = 135;
|
$clientInfoXAxis = 135;
|
||||||
|
|
||||||
@ -245,11 +263,22 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
}
|
}
|
||||||
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
||||||
$this->Cell(0, $this->interLigneHeader, trim(FileExportHelpers::FormatTextForExport($this->factureData['client_adress_city'])));
|
$this->Cell(0, $this->interLigneHeader, trim(FileExportHelpers::FormatTextForExport($this->factureData['client_adress_city'])));
|
||||||
|
|
||||||
|
// Gestion Siret ou TVA intracommunautaire selon is_tva
|
||||||
|
if ($this->hasTva) {
|
||||||
|
// Avec TVA : afficher le Siret
|
||||||
if ($this->factureData['siret']) {
|
if ($this->factureData['siret']) {
|
||||||
$clientInfoYAxis += $this->interLigneHeader;
|
$clientInfoYAxis += $this->interLigneHeader;
|
||||||
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
||||||
$this->Cell(0, $this->interLigneHeader, 'Siret: ' . $this->factureData['siret']);
|
$this->Cell(0, $this->interLigneHeader, 'Siret: ' . $this->factureData['siret']);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Sans TVA : afficher N° TVA intracommunautaire
|
||||||
|
$clientInfoYAxis += $this->interLigneHeader;
|
||||||
|
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
||||||
|
$tvaIntracommu = isset($this->factureData['client_tva_intracommu']) ? $this->factureData['client_tva_intracommu'] : '';
|
||||||
|
$this->Cell(0, $this->interLigneHeader, 'TVA intracom : ' . $tvaIntracommu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,15 +295,15 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$factureDateEcheance->modify('last day of next month');
|
$factureDateEcheance->modify('last day of next month');
|
||||||
$factureDateEcheance = $factureDateEcheance->format('d-m-Y');
|
$factureDateEcheance = $factureDateEcheance->format('d-m-Y');
|
||||||
|
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
$this->Cell(25, 7, 'DATE', 1, 0, 'C');
|
$this->Cell(25, 7, 'DATE', 1, 0, 'C');
|
||||||
$this->Cell(104, 7, 'CLIENT', 1, 0, 'C');
|
$this->Cell(104, 7, 'CLIENT', 1, 0, 'C');
|
||||||
$this->Cell(39, 7, 'FACTURE', 1, 0, 'C');
|
$this->Cell(39, 7, 'FACTURE', 1, 0, 'C');
|
||||||
$this->Cell(36, 7, 'ECHEANCE', 1, 1, 'C');
|
$this->Cell(36, 7, 'ECHEANCE', 1, 1, 'C');
|
||||||
|
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
$this->Cell(25, 7, $factureDatePaiement, 1, 0, 'C');
|
$this->Cell(25, 7, $factureDatePaiement, 1, 0, 'C');
|
||||||
$this->Cell(104, 7, utf8_decode(html_entity_decode($this->factureData['group_name'])), 1, 0, 'C');
|
$this->Cell(104, 7, $this->SafeTextForPdf($this->factureData['group_name']), 1, 0, 'C');
|
||||||
$this->Cell(39, 7, $this->factureData['num'], 1, 0, 'C');
|
$this->Cell(39, 7, $this->factureData['num'], 1, 0, 'C');
|
||||||
$this->Cell(36, 7, $factureDateEcheance, 1, 1, 'C');
|
$this->Cell(36, 7, $factureDateEcheance, 1, 1, 'C');
|
||||||
|
|
||||||
@ -294,11 +323,16 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$this->Line(3, $this->startingYOfArticlesTable + $gapBetweenStartingOfArticlesTableAndColumnName, 207, $this->startingYOfArticlesTable + $gapBetweenStartingOfArticlesTableAndColumnName);
|
$this->Line(3, $this->startingYOfArticlesTable + $gapBetweenStartingOfArticlesTableAndColumnName, 207, $this->startingYOfArticlesTable + $gapBetweenStartingOfArticlesTableAndColumnName);
|
||||||
// les traits verticaux colonnes
|
// les traits verticaux colonnes
|
||||||
$additionalMargRight = 1;
|
$additionalMargRight = 1;
|
||||||
$endingLine = 233 + $additionnalheight;
|
$endingLine = $this->startingYOfArticlesTable + $tableHeight;
|
||||||
$this->Line(27 + $additionalMargRight, $this->startingYOfArticlesTable, 27 + $additionalMargRight, $endingLine);
|
$this->Line(27 + $additionalMargRight, $this->startingYOfArticlesTable, 27 + $additionalMargRight, $endingLine);
|
||||||
$this->Line(142 + $additionalMargRight, $this->startingYOfArticlesTable, 142 + $additionalMargRight, $endingLine);
|
$this->Line(142 + $additionalMargRight, $this->startingYOfArticlesTable, 142 + $additionalMargRight, $endingLine);
|
||||||
|
|
||||||
|
if ($this->hasTva) {
|
||||||
$this->Line(164 + $additionalMargRight, $this->startingYOfArticlesTable, 164 + $additionalMargRight, $endingLine);
|
$this->Line(164 + $additionalMargRight, $this->startingYOfArticlesTable, 164 + $additionalMargRight, $endingLine);
|
||||||
$this->Line(182 + $additionalMargRight, $this->startingYOfArticlesTable, 182 + $additionalMargRight, $endingLine);
|
$this->Line(182 + $additionalMargRight, $this->startingYOfArticlesTable, 182 + $additionalMargRight, $endingLine);
|
||||||
|
} else {
|
||||||
|
$this->Line(182 + $additionalMargRight, $this->startingYOfArticlesTable, 182 + $additionalMargRight, $endingLine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DrawArticlesTableHeader()
|
public function DrawArticlesTableHeader()
|
||||||
@ -306,9 +340,9 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$additionalMargRight = 1;
|
$additionalMargRight = 1;
|
||||||
$tvaValue = $this->factureData["configuration"]->tva_default;
|
$tvaValue = $this->factureData["configuration"]->tva_default;
|
||||||
$columnNameY = $this->startingYOfArticlesTable - 1.5;
|
$columnNameY = $this->startingYOfArticlesTable - 1.5;
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
$this->SetXY(12 + $additionalMargRight, $columnNameY);
|
$this->SetXY(35 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(7, 10, "Date", 0, 0, 'C');
|
$this->Cell(7, 10, "", 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(30 + $additionalMargRight, $columnNameY);
|
$this->SetXY(30 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(100, 10, "Description", 0, 0, 'C');
|
$this->Cell(100, 10, "Description", 0, 0, 'C');
|
||||||
@ -316,18 +350,23 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$this->SetXY(143 + $additionalMargRight, $columnNameY);
|
$this->SetXY(143 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(20, 10, "Prix Uni. HT", 0, 0, 'C');
|
$this->Cell(20, 10, "Prix Uni. HT", 0, 0, 'C');
|
||||||
|
|
||||||
|
if ($this->hasTva) {
|
||||||
$this->SetXY(163 + $additionalMargRight, $columnNameY);
|
$this->SetXY(163 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(20, 10, 'TVA ' . $tvaValue . '%', 0, 0, 'C');
|
$this->Cell(20, 10, 'TVA ' . $tvaValue . '%', 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(185, $columnNameY);
|
$this->SetXY(185, $columnNameY);
|
||||||
$this->Cell(20, 10, "Prix Uni. TTC", 0, 0, 'C');
|
$this->Cell(20, 10, "Prix Uni. TTC", 0, 0, 'C');
|
||||||
|
} else {
|
||||||
|
$this->SetXY(185, $columnNameY);
|
||||||
|
$this->Cell(20, 10, "Montant HT", 0, 0, 'C');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DrawArticlesTableValue()
|
public function DrawArticlesTableValue()
|
||||||
{
|
{
|
||||||
// Set espacement avant de continue
|
// Set espacement avant de continue
|
||||||
|
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
$devisData = $this->factureData['devis'];
|
$devisData = $this->factureData['devis'];
|
||||||
$tvaValue = $this->factureData["configuration"]->tva_default;
|
$tvaValue = $this->factureData["configuration"]->tva_default;
|
||||||
$totalHt = 0;
|
$totalHt = 0;
|
||||||
@ -336,6 +375,7 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$yValue = $this->startingYOfArticlesTable + 13;
|
$yValue = $this->startingYOfArticlesTable + 13;
|
||||||
// $maxDescriptionWidth = 102;
|
// $maxDescriptionWidth = 102;
|
||||||
$maxDescriptionWidth = 104.3;
|
$maxDescriptionWidth = 104.3;
|
||||||
|
// $maxDescriptionWidth = 51;
|
||||||
$currentIndexPosition = $this->currentIndexPosition;
|
$currentIndexPosition = $this->currentIndexPosition;
|
||||||
for ($currentIndexPosition; $currentIndexPosition < ($this->initialIndexPosition + $this->devisCountToGet); $currentIndexPosition++) {
|
for ($currentIndexPosition; $currentIndexPosition < ($this->initialIndexPosition + $this->devisCountToGet); $currentIndexPosition++) {
|
||||||
$currentDevis = $devisData[$currentIndexPosition];
|
$currentDevis = $devisData[$currentIndexPosition];
|
||||||
@ -347,20 +387,32 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
foreach ($products as $product) {
|
foreach ($products as $product) {
|
||||||
|
|
||||||
$valueHt = $product['produit_price'] * $product["quantite"];
|
$valueHt = $product['produit_price'] * $product["quantite"];
|
||||||
|
if ($this->hasTva) {
|
||||||
$valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt, $tvaValue);
|
$valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt, $tvaValue);
|
||||||
|
$tvaAmount = $valueTtc - $valueHt;
|
||||||
|
} else {
|
||||||
|
$valueTtc = $valueHt; // Sans TVA, TTC = HT
|
||||||
|
$tvaAmount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
$totalHt += $valueHt;
|
$totalHt += $valueHt;
|
||||||
$totalTtc += $valueTtc;
|
$totalTtc += $valueTtc;
|
||||||
$productDescription = $product["produit_description"] ?? "";
|
$productDescription = $product["produit_description"] ?? "";
|
||||||
|
$currentDevisDefuntName = $currentDevis["defunt_nom"] ?? "";
|
||||||
|
|
||||||
$dateValue = "";
|
$dateValue = "";
|
||||||
|
$dateAndDefuntName = "";
|
||||||
if ($productIncrement == 0) {
|
if ($productIncrement == 0) {
|
||||||
$dateValue = $devisDate;
|
$dateValue = $devisDate;
|
||||||
$productDescription .= " de " . $currentDevis["defunt_nom"] ?? "";
|
// $productDescription .= " de " . $currentDevis["defunt_nom"] ?? "";
|
||||||
}
|
$dateAndDefuntName = $dateValue . " - " . $currentDevisDefuntName;
|
||||||
$tvaAmount = $valueTtc - $valueHt;
|
$this->SetXY(70, $yValue);
|
||||||
$this->SetXY(4, $yValue);
|
$this->Cell(5, 6, $currentDevisDefuntName, 0, 0);
|
||||||
|
$this->SetXY(4, $yValue + 5);
|
||||||
$this->Cell(5, 6, $dateValue, 0, 0);
|
$this->Cell(5, 6, $dateValue, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
$this->SetXY(30, $yValue);
|
$this->SetXY(30, $yValue + 5);
|
||||||
$productDescription = FileExportHelpers::FormatTextForExport($productDescription);
|
$productDescription = FileExportHelpers::FormatTextForExport($productDescription);
|
||||||
$productDescriptionWidth = $this->GetStringWidth($productDescription);
|
$productDescriptionWidth = $this->GetStringWidth($productDescription);
|
||||||
$productDescriptionWidthIsGreaterThanMaxWidth = $productDescriptionWidth > $maxDescriptionWidth;
|
$productDescriptionWidthIsGreaterThanMaxWidth = $productDescriptionWidth > $maxDescriptionWidth;
|
||||||
@ -378,14 +430,20 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$this->SetXY(144, $yValue);
|
$this->SetXY(144, $yValue + 5);
|
||||||
$this->Cell(20, 6, number_format($valueHt, 2, '.', '') . chr(128), 0, 0, 'C');
|
$this->Cell(20, 6, number_format($valueHt, 2, '.', '') . chr(128), 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(165, $yValue);
|
if ($this->hasTva) {
|
||||||
|
$this->SetXY(165, $yValue + 5);
|
||||||
$this->Cell(20, 6, number_format($tvaAmount, 2, '.', '') . chr(128), 0, 0, 'C');
|
$this->Cell(20, 6, number_format($tvaAmount, 2, '.', '') . chr(128), 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(182, $yValue);
|
$this->SetXY(182, $yValue + 5);
|
||||||
$this->Cell(25, 6, number_format($valueTtc, 2, '.', '') . chr(128), 0, 1, 'C');
|
$this->Cell(25, 6, number_format($valueTtc, 2, '.', '') . chr(128), 0, 1, 'C');
|
||||||
|
} else {
|
||||||
|
$this->SetXY(182, $yValue + 5);
|
||||||
|
$this->Cell(25, 6, number_format($valueHt, 2, '.', '') . chr(128), 0, 1, 'C');
|
||||||
|
}
|
||||||
|
|
||||||
$yValue += 6;
|
$yValue += 6;
|
||||||
$totalTva += $tvaAmount;
|
$totalTva += $tvaAmount;
|
||||||
if ($productDescriptionWidthIsGreaterThanMaxWidth) {
|
if ($productDescriptionWidthIsGreaterThanMaxWidth) {
|
||||||
@ -393,6 +451,11 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
}
|
}
|
||||||
$productIncrement++;
|
$productIncrement++;
|
||||||
}
|
}
|
||||||
|
$yValue += 6;
|
||||||
|
$isLastLigneDevis = $currentIndexPosition == (($this->initialIndexPosition + $this->devisCountToGet) - 1);
|
||||||
|
if (!$isLastLigneDevis) {
|
||||||
|
$this->Line(3, $yValue, 207, $yValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$this->currentIndexPosition = $currentIndexPosition;
|
$this->currentIndexPosition = $currentIndexPosition;
|
||||||
$this->initialIndexPosition = $this->currentIndexPosition;
|
$this->initialIndexPosition = $this->currentIndexPosition;
|
||||||
@ -406,21 +469,21 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
{
|
{
|
||||||
$startOfYAfterMainTable = 239;
|
$startOfYAfterMainTable = 239;
|
||||||
$this->SetY($startOfYAfterMainTable);
|
$this->SetY($startOfYAfterMainTable);
|
||||||
$this->SetFont('ComicSans', '', 8);
|
$this->SetFont('Arial', '', 8);
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode("Paiement à votre convenance par chèque à l'ordre de " . $this->factureData['configuration']->entreprise)));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf("Paiement à votre convenance par chèque à l'ordre de " . $this->factureData['configuration']->entreprise));
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode("en indiquant le numéro de facture, ou par virement :")));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf("en indiquant le numéro de facture, ou par virement :"));
|
||||||
|
|
||||||
$this->Ln(1);
|
$this->Ln(1);
|
||||||
//Table IBAN
|
//Table IBAN
|
||||||
$startOftable = 3;
|
$startOftable = 3;
|
||||||
$this->SetX($startOftable);
|
$this->SetX($startOftable);
|
||||||
$this->SetFont('ComicSans', '', 8);
|
$this->SetFont('Arial', '', 8);
|
||||||
$ibanWidth = 62;
|
$ibanWidth = 62;
|
||||||
$this->Cell($ibanWidth, 6.5, 'IBAN : FR76 1360 6000 1436 5418 1800 038', 1, 1, 'C');
|
$this->Cell($ibanWidth, 6.5, 'IBAN : FR76 1670 6052 4453 9757 9734 871', 1, 1, 'C');
|
||||||
$ibanCursorX = $this->GetX();
|
$ibanCursorX = $this->GetX();
|
||||||
$this->SetX($startOftable);
|
$this->SetX($startOftable);
|
||||||
|
|
||||||
$this->Cell($ibanWidth, 6.5, 'Code SWIFT : AGRI FR PP 836', 1, 1, 'C');
|
$this->Cell($ibanWidth, 6.5, 'Code SWIFT : AGRI FR PP867', 1, 1, 'C');
|
||||||
|
|
||||||
//TABLE HT
|
//TABLE HT
|
||||||
$tableWidth = 48; // Largeur totale de la 2e table (20+20)
|
$tableWidth = 48; // Largeur totale de la 2e table (20+20)
|
||||||
@ -430,7 +493,7 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$startOfArrayX = $pageWidth - $tableWidth - $marginRight;
|
$startOfArrayX = $pageWidth - $tableWidth - $marginRight;
|
||||||
$startOfArrayY = $startOfYAfterMainTable + 0.5;
|
$startOfArrayY = $startOfYAfterMainTable + 0.5;
|
||||||
|
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
$totalPriceArray = $this->totalPrices;
|
$totalPriceArray = $this->totalPrices;
|
||||||
foreach ($totalPriceArray as $label => $price) {
|
foreach ($totalPriceArray as $label => $price) {
|
||||||
$this->SetXY($startOfArrayX, $startOfArrayY);
|
$this->SetXY($startOfArrayX, $startOfArrayY);
|
||||||
@ -449,7 +512,7 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$this->DrawBankAndTotalPriceInfo();
|
$this->DrawBankAndTotalPriceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
function MultiAlignCell($w, $h, $text, $border = 0, $ln = 0, $align = 'L', $fill = false)
|
public function MultiAlignCell($w, $h, $text, $border = 0, $ln = 0, $align = 'L', $fill = false)
|
||||||
{
|
{
|
||||||
// Store reset values for (x,y) positions
|
// Store reset values for (x,y) positions
|
||||||
$x = $this->GetX() + $w;
|
$x = $this->GetX() + $w;
|
||||||
@ -464,19 +527,22 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function NbLines($w, $txt)
|
public function NbLines($w, $txt)
|
||||||
{
|
{
|
||||||
// Compute the number of lines a MultiCell of width w will take
|
// Compute the number of lines a MultiCell of width w will take
|
||||||
if (!isset($this->CurrentFont))
|
if (!isset($this->CurrentFont)) {
|
||||||
$this->Error('No font has been set');
|
$this->Error('No font has been set');
|
||||||
|
}
|
||||||
$cw = $this->CurrentFont['cw'];
|
$cw = $this->CurrentFont['cw'];
|
||||||
if ($w == 0)
|
if ($w == 0) {
|
||||||
$w = $this->w - $this->rMargin - $this->x;
|
$w = $this->w - $this->rMargin - $this->x;
|
||||||
|
}
|
||||||
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
|
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
|
||||||
$s = str_replace("\r", '', (string) $txt);
|
$s = str_replace("\r", '', (string) $txt);
|
||||||
$nb = strlen($s);
|
$nb = strlen($s);
|
||||||
if ($nb > 0 && $s[$nb - 1] == "\n")
|
if ($nb > 0 && $s[$nb - 1] == "\n") {
|
||||||
$nb--;
|
$nb--;
|
||||||
|
}
|
||||||
$sep = -1;
|
$sep = -1;
|
||||||
$i = 0;
|
$i = 0;
|
||||||
$j = 0;
|
$j = 0;
|
||||||
@ -492,22 +558,26 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
$nl++;
|
$nl++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($c == ' ')
|
if ($c == ' ') {
|
||||||
$sep = $i;
|
$sep = $i;
|
||||||
|
}
|
||||||
$l += $cw[$c];
|
$l += $cw[$c];
|
||||||
if ($l > $wmax) {
|
if ($l > $wmax) {
|
||||||
if ($sep == -1) {
|
if ($sep == -1) {
|
||||||
if ($i == $j)
|
if ($i == $j) {
|
||||||
$i++;
|
$i++;
|
||||||
} else
|
}
|
||||||
|
} else {
|
||||||
$i = $sep + 1;
|
$i = $sep + 1;
|
||||||
|
}
|
||||||
$sep = -1;
|
$sep = -1;
|
||||||
$j = $i;
|
$j = $i;
|
||||||
$l = 0;
|
$l = 0;
|
||||||
$nl++;
|
$nl++;
|
||||||
} else
|
} else {
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return $nl;
|
return $nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,38 +586,42 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
{
|
{
|
||||||
$k = $this->k;
|
$k = $this->k;
|
||||||
$hp = $this->h;
|
$hp = $this->h;
|
||||||
if ($style == 'F')
|
if ($style == 'F') {
|
||||||
$op = 'f';
|
$op = 'f';
|
||||||
elseif ($style == 'FD' || $style == 'DF')
|
} elseif ($style == 'FD' || $style == 'DF') {
|
||||||
$op = 'B';
|
$op = 'B';
|
||||||
else
|
} else {
|
||||||
$op = 'S';
|
$op = 'S';
|
||||||
|
}
|
||||||
$MyArc = 4 / 3 * (sqrt(2) - 1);
|
$MyArc = 4 / 3 * (sqrt(2) - 1);
|
||||||
$this->_out(sprintf('%.2F %.2F m', ($x + $r) * $k, ($hp - $y) * $k));
|
$this->_out(sprintf('%.2F %.2F m', ($x + $r) * $k, ($hp - $y) * $k));
|
||||||
|
|
||||||
$xc = $x + $w - $r;
|
$xc = $x + $w - $r;
|
||||||
$yc = $y + $r;
|
$yc = $y + $r;
|
||||||
$this->_out(sprintf('%.2F %.2F l', $xc * $k, ($hp - $y) * $k));
|
$this->_out(sprintf('%.2F %.2F l', $xc * $k, ($hp - $y) * $k));
|
||||||
if (strpos($corners, '2') === false)
|
if (strpos($corners, '2') === false) {
|
||||||
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - $y) * $k));
|
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - $y) * $k));
|
||||||
else
|
} else {
|
||||||
$this->_Arc($xc + $r * $MyArc, $yc - $r, $xc + $r, $yc - $r * $MyArc, $xc + $r, $yc);
|
$this->_Arc($xc + $r * $MyArc, $yc - $r, $xc + $r, $yc - $r * $MyArc, $xc + $r, $yc);
|
||||||
|
}
|
||||||
|
|
||||||
$xc = $x + $w - $r;
|
$xc = $x + $w - $r;
|
||||||
$yc = $y + $h - $r;
|
$yc = $y + $h - $r;
|
||||||
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - $yc) * $k));
|
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - $yc) * $k));
|
||||||
if (strpos($corners, '3') === false)
|
if (strpos($corners, '3') === false) {
|
||||||
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - ($y + $h)) * $k));
|
$this->_out(sprintf('%.2F %.2F l', ($x + $w) * $k, ($hp - ($y + $h)) * $k));
|
||||||
else
|
} else {
|
||||||
$this->_Arc($xc + $r, $yc + $r * $MyArc, $xc + $r * $MyArc, $yc + $r, $xc, $yc + $r);
|
$this->_Arc($xc + $r, $yc + $r * $MyArc, $xc + $r * $MyArc, $yc + $r, $xc, $yc + $r);
|
||||||
|
}
|
||||||
|
|
||||||
$xc = $x + $r;
|
$xc = $x + $r;
|
||||||
$yc = $y + $h - $r;
|
$yc = $y + $h - $r;
|
||||||
$this->_out(sprintf('%.2F %.2F l', $xc * $k, ($hp - ($y + $h)) * $k));
|
$this->_out(sprintf('%.2F %.2F l', $xc * $k, ($hp - ($y + $h)) * $k));
|
||||||
if (strpos($corners, '4') === false)
|
if (strpos($corners, '4') === false) {
|
||||||
$this->_out(sprintf('%.2F %.2F l', ($x) * $k, ($hp - ($y + $h)) * $k));
|
$this->_out(sprintf('%.2F %.2F l', ($x) * $k, ($hp - ($y + $h)) * $k));
|
||||||
else
|
} else {
|
||||||
$this->_Arc($xc - $r * $MyArc, $yc + $r, $xc - $r, $yc + $r * $MyArc, $xc - $r, $yc);
|
$this->_Arc($xc - $r * $MyArc, $yc + $r, $xc - $r, $yc + $r * $MyArc, $xc - $r, $yc);
|
||||||
|
}
|
||||||
|
|
||||||
$xc = $x + $r;
|
$xc = $x + $r;
|
||||||
$yc = $y + $r;
|
$yc = $y + $r;
|
||||||
@ -555,8 +629,9 @@ class InvoiceGroupPdfHandler extends FPDF
|
|||||||
if (strpos($corners, '1') === false) {
|
if (strpos($corners, '1') === false) {
|
||||||
$this->_out(sprintf('%.2F %.2F l', ($x) * $k, ($hp - $y) * $k));
|
$this->_out(sprintf('%.2F %.2F l', ($x) * $k, ($hp - $y) * $k));
|
||||||
$this->_out(sprintf('%.2F %.2F l', ($x + $r) * $k, ($hp - $y) * $k));
|
$this->_out(sprintf('%.2F %.2F l', ($x + $r) * $k, ($hp - $y) * $k));
|
||||||
} else
|
} else {
|
||||||
$this->_Arc($xc - $r, $yc - $r * $MyArc, $xc - $r * $MyArc, $yc - $r, $xc, $yc - $r);
|
$this->_Arc($xc - $r, $yc - $r * $MyArc, $xc - $r * $MyArc, $yc - $r, $xc, $yc - $r);
|
||||||
|
}
|
||||||
$this->_out($op);
|
$this->_out($op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,22 +42,30 @@ class InvoicePdfHandler extends FPDF
|
|||||||
protected $extgstates = [];
|
protected $extgstates = [];
|
||||||
private $thereIsOrderOrCaseNumber = false;
|
private $thereIsOrderOrCaseNumber = false;
|
||||||
private $startingYOfArticlesTable = 100;
|
private $startingYOfArticlesTable = 100;
|
||||||
|
|
||||||
private $endingYOfArticlesTable = 230;
|
private $endingYOfArticlesTable = 230;
|
||||||
|
|
||||||
private $articleTablesHeight = 130;
|
private $articleTablesHeight = 130;
|
||||||
|
|
||||||
public $interLigneHeader = 5;
|
public $interLigneHeader = 5;
|
||||||
|
public $hasTva = true;
|
||||||
|
|
||||||
public function Header()
|
public function Header()
|
||||||
{
|
{
|
||||||
if ($this->logo != "nothing") {
|
if ($this->logo != "nothing") {
|
||||||
$this->Image($this->logoPath . "logo.png", 4, 2, 50, 35);
|
$this->Image($this->logoPath . "logo.png", 2, 10, 75, 25);
|
||||||
$this->AddWatermark();
|
//$this->AddWatermark();
|
||||||
} else {
|
} else {
|
||||||
$this->Cell(55, 30, '');
|
$this->Cell(55, 30, '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function SafeTextForPdf($text)
|
||||||
|
{
|
||||||
|
if (empty($text)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML401, 'UTF-8');
|
||||||
|
return iconv('UTF-8', 'ISO-8859-1//IGNORE', $text);
|
||||||
|
}
|
||||||
|
|
||||||
public function AddWatermark()
|
public function AddWatermark()
|
||||||
{
|
{
|
||||||
$this->SetAlpha(0.2);
|
$this->SetAlpha(0.2);
|
||||||
@ -97,21 +105,23 @@ class InvoicePdfHandler extends FPDF
|
|||||||
$this->SetY(-34);
|
$this->SetY(-34);
|
||||||
$this->SetFont('ComicSans', '', 7);
|
$this->SetFont('ComicSans', '', 7);
|
||||||
|
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('Tout retard de paiement entraînera de plein droit une pénalité de retard de 3 fois le taux légal ')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('Tout retard de paiement entraînera de plein droit une pénalité de retard de 3 fois le taux légal '));
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('(Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40 EUR pour frais de recouvrement sera appliquée.')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('(Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40 EUR pour frais de recouvrement sera appliquée.'));
|
||||||
$this->Ln(1);
|
$this->Ln(1);
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('Si les frais de recouvrement sont supérieurs à ce montant forfaitaire, une indemnisation complémentaire')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('Si les frais de recouvrement sont supérieurs à ce montant forfaitaire, une indemnisation complémentaire'));
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode('sera due sur présentation de justificatifs (articles L.441-3 et L.441-6 du code de commerce).')));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf('sera due sur présentation de justificatifs (articles L.441-3 et L.441-6 du code de commerce).'));
|
||||||
|
|
||||||
$this->SetY(-10);
|
$this->SetY(-10);
|
||||||
$this->SetFont('ComicSans', '', 7);
|
$this->SetFont('ComicSans', '', 7);
|
||||||
$this->Cell(0, 10, utf8_decode(html_entity_decode($this->factureData['configuration']->legal_one)), 0, 0, 'C');
|
$this->Cell(0, 10, $this->SafeTextForPdf($this->factureData['configuration']->legal_one), 0, 0, 'C');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function InvoicePdfFactory(array $factureData, $logo = null)
|
public function InvoicePdfFactory(array $factureData, $logo = null)
|
||||||
{
|
{
|
||||||
$this->factureData = $factureData;
|
$this->factureData = $factureData;
|
||||||
$this->logo = $logo;
|
$this->logo = $logo;
|
||||||
|
// Déterminer si la TVA est applicable
|
||||||
|
$this->hasTva = isset($factureData['is_tva']) ? $factureData['is_tva'] : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function MutlipleInvoicePdfFactory(array $multipleInvoiceData, $logo = null)
|
public function MutlipleInvoicePdfFactory(array $multipleInvoiceData, $logo = null)
|
||||||
@ -155,6 +165,7 @@ class InvoicePdfHandler extends FPDF
|
|||||||
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport('Tél : ') . FileExportHelpers::FormatTextForExport($this->factureData['configuration']->telephone), 0, 1);
|
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport('Tél : ') . FileExportHelpers::FormatTextForExport($this->factureData['configuration']->telephone), 0, 1);
|
||||||
$this->Cell(0, $this->interLigneHeader, 'Mail : ' . $this->factureData['configuration']->mail, 0, 1);
|
$this->Cell(0, $this->interLigneHeader, 'Mail : ' . $this->factureData['configuration']->mail, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function DrawInvoiceClientInfo()
|
private function DrawInvoiceClientInfo()
|
||||||
{
|
{
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('ComicSans', '', 10);
|
||||||
@ -203,7 +214,17 @@ class InvoicePdfHandler extends FPDF
|
|||||||
$this->Cell(0, $this->interLigneHeader, trim(FileExportHelpers::FormatTextForExport($this->factureData['client_adress_city'])));
|
$this->Cell(0, $this->interLigneHeader, trim(FileExportHelpers::FormatTextForExport($this->factureData['client_adress_city'])));
|
||||||
$clientInfoYAxis += $this->interLigneHeader;
|
$clientInfoYAxis += $this->interLigneHeader;
|
||||||
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
||||||
|
|
||||||
|
// Gestion Siret ou TVA intracommunautaire selon is_tva
|
||||||
|
if ($this->hasTva) {
|
||||||
|
// Avec TVA : afficher le Siret
|
||||||
$this->Cell(0, $this->interLigneHeader, 'Siret: ' . $this->factureData['siret']);
|
$this->Cell(0, $this->interLigneHeader, 'Siret: ' . $this->factureData['siret']);
|
||||||
|
} else {
|
||||||
|
// Sans TVA : afficher N° TVA intracommunautaire
|
||||||
|
$tvaIntracommu = isset($this->factureData['client_tva_intracommu']) ? $this->factureData['client_tva_intracommu'] : '';
|
||||||
|
$this->Cell(0, $this->interLigneHeader, 'TVA intracom : ' . $tvaIntracommu);
|
||||||
|
}
|
||||||
|
|
||||||
$clientInfoYAxis += $this->interLigneHeader;
|
$clientInfoYAxis += $this->interLigneHeader;
|
||||||
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
$this->SetXY($clientInfoXAxis, $clientInfoYAxis);
|
||||||
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport('Mail : ') . $this->factureData['client_mail']);
|
$this->Cell(0, $this->interLigneHeader, FileExportHelpers::FormatTextForExport('Mail : ') . $this->factureData['client_mail']);
|
||||||
@ -236,7 +257,7 @@ class InvoicePdfHandler extends FPDF
|
|||||||
|
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('ComicSans', '', 10);
|
||||||
$this->Cell(25, 7, $factureDatePaiement, 1, 0, 'C');
|
$this->Cell(25, 7, $factureDatePaiement, 1, 0, 'C');
|
||||||
$this->Cell(104, 7, utf8_decode(html_entity_decode($this->factureData['client_nom'])), 1, 0, 'C');
|
$this->Cell(104, 7, $this->SafeTextForPdf($this->factureData['client_nom']), 1, 0, 'C');
|
||||||
$this->Cell(39, 7, $this->factureData['num'], 1, 0, 'C');
|
$this->Cell(39, 7, $this->factureData['num'], 1, 0, 'C');
|
||||||
$this->Cell(36, 7, $factureDateEcheance, 1, 1, 'C');
|
$this->Cell(36, 7, $factureDateEcheance, 1, 1, 'C');
|
||||||
|
|
||||||
@ -275,31 +296,40 @@ class InvoicePdfHandler extends FPDF
|
|||||||
$endingLine = $this->thereIsOrderOrCaseNumber ? 231 : 230; // mois +1 pour le groupe
|
$endingLine = $this->thereIsOrderOrCaseNumber ? 231 : 230; // mois +1 pour le groupe
|
||||||
$this->Line(27 + $additionalMargRight, $this->startingYOfArticlesTable, 27 + $additionalMargRight, $endingLine);
|
$this->Line(27 + $additionalMargRight, $this->startingYOfArticlesTable, 27 + $additionalMargRight, $endingLine);
|
||||||
$this->Line(142 + $additionalMargRight, $this->startingYOfArticlesTable, 142 + $additionalMargRight, $endingLine);
|
$this->Line(142 + $additionalMargRight, $this->startingYOfArticlesTable, 142 + $additionalMargRight, $endingLine);
|
||||||
|
|
||||||
|
if ($this->hasTva) {
|
||||||
$this->Line(164 + $additionalMargRight, $this->startingYOfArticlesTable, 164 + $additionalMargRight, $endingLine);
|
$this->Line(164 + $additionalMargRight, $this->startingYOfArticlesTable, 164 + $additionalMargRight, $endingLine);
|
||||||
$this->Line(182 + $additionalMargRight, $this->startingYOfArticlesTable, 182 + $additionalMargRight, $endingLine);
|
$this->Line(182 + $additionalMargRight, $this->startingYOfArticlesTable, 182 + $additionalMargRight, $endingLine);
|
||||||
|
} else {
|
||||||
|
$this->Line(182 + $additionalMargRight, $this->startingYOfArticlesTable, 182 + $additionalMargRight, $endingLine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function DrawArticlesTableHeader()
|
private function DrawArticlesTableHeader()
|
||||||
{
|
{
|
||||||
$additionalMargRight = 1;
|
$additionalMargRight = 1;
|
||||||
$tvaDefault = $this->factureData["configuration"]->tva_default;
|
$tvaValue = $this->factureData["configuration"]->tva_default;
|
||||||
$clientTvaStatus = isset($this->factureData["tva"]) ? (int)$this->factureData["tva"] : 1;
|
|
||||||
|
|
||||||
// Déterminer le libellé TVA selon le statut du client
|
|
||||||
$tvaLabel = ($clientTvaStatus === 0) ? "TVA 0%" : "TVA " . $tvaDefault . "%";
|
|
||||||
|
|
||||||
$columnNameY = $this->startingYOfArticlesTable - 1;
|
$columnNameY = $this->startingYOfArticlesTable - 1;
|
||||||
$this->SetFont('ComicSans', '', 10);
|
$this->SetFont('ComicSans', '', 10);
|
||||||
$this->SetXY(12 + $additionalMargRight, $columnNameY);
|
$this->SetXY(12 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(7, 10, "Date", 0, 0, 'C');
|
$this->Cell(7, 10, "", 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(30 + $additionalMargRight, $columnNameY);
|
$this->SetXY(30 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(100, 10, "Description", 0, 0, 'C');
|
$this->Cell(100, 10, "Description", 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(143 + $additionalMargRight, $columnNameY);
|
$this->SetXY(143 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(20, 10, "Prix Uni. HT", 0, 0, 'C');
|
$this->Cell(20, 10, "Prix Uni. HT", 0, 0, 'C');
|
||||||
|
|
||||||
|
if ($this->hasTva) {
|
||||||
$this->SetXY(163 + $additionalMargRight, $columnNameY);
|
$this->SetXY(163 + $additionalMargRight, $columnNameY);
|
||||||
$this->Cell(20, 10, $tvaLabel, 0, 0, 'C');
|
$this->Cell(20, 10, 'TVA ' . $tvaValue . '%', 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(185, $columnNameY);
|
$this->SetXY(185, $columnNameY);
|
||||||
$this->Cell(20, 10, "Prix Uni. TTC", 0, 0, 'C');
|
$this->Cell(20, 10, "Prix Uni. TTC", 0, 0, 'C');
|
||||||
|
} else {
|
||||||
|
$this->SetXY(185, $columnNameY);
|
||||||
|
$this->Cell(20, 10, "Montant HT", 0, 0, 'C');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DrawArticlesTableValueAndReturnTotalPrice()
|
public function DrawArticlesTableValueAndReturnTotalPrice()
|
||||||
@ -308,14 +338,7 @@ class InvoicePdfHandler extends FPDF
|
|||||||
$devisDate = $this->factureData['devis_date'];
|
$devisDate = $this->factureData['devis_date'];
|
||||||
$devisDate = DateTime::createFromFormat('Y-m-d', $devisDate);
|
$devisDate = DateTime::createFromFormat('Y-m-d', $devisDate);
|
||||||
$devisDate = $devisDate->format('d-m-Y');
|
$devisDate = $devisDate->format('d-m-Y');
|
||||||
|
$tvaValue = $this->factureData["configuration"]->tva_default;
|
||||||
$tvaDefault = $this->factureData["configuration"]->tva_default;
|
|
||||||
$clientTvaStatus = isset($this->factureData["tva"]) ? (int)$this->factureData["tva"] : 1;
|
|
||||||
|
|
||||||
// Déterminer le taux de TVA à appliquer selon le statut du client
|
|
||||||
$tvaValue = ($clientTvaStatus === 0) ? 0 : $tvaDefault;
|
|
||||||
$tvaLabel = ($clientTvaStatus === 0) ? "0%" : $tvaDefault . "%";
|
|
||||||
|
|
||||||
$totalHt = 0;
|
$totalHt = 0;
|
||||||
$totalTtc = 0;
|
$totalTtc = 0;
|
||||||
$totalTva = 0;
|
$totalTva = 0;
|
||||||
@ -326,23 +349,19 @@ class InvoicePdfHandler extends FPDF
|
|||||||
foreach ($products as $product) {
|
foreach ($products as $product) {
|
||||||
$valueHt = $product['produit_price'] * $product['quantite'];
|
$valueHt = $product['produit_price'] * $product['quantite'];
|
||||||
|
|
||||||
// Calculer la TVA selon le statut du client
|
if ($this->hasTva) {
|
||||||
if ($clientTvaStatus === 0) {
|
|
||||||
// Client exonéré - pas de TVA
|
|
||||||
$valueTtc = $valueHt;
|
|
||||||
$tvaAmount = 0;
|
|
||||||
} else {
|
|
||||||
// Client soumis à la TVA - utiliser le calcul normal
|
|
||||||
$valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt, $tvaValue);
|
$valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt, $tvaValue);
|
||||||
$tvaAmount = $valueTtc - $valueHt;
|
$tvaAmount = $valueTtc - $valueHt;
|
||||||
|
} else {
|
||||||
|
$valueTtc = $valueHt; // Sans TVA, TTC = HT
|
||||||
|
$tvaAmount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$totalHt += $valueHt;
|
$totalHt += $valueHt;
|
||||||
$totalTtc += $valueTtc;
|
$totalTtc += $valueTtc;
|
||||||
$totalTva += $tvaAmount;
|
|
||||||
|
|
||||||
$productDescription = $product["produit_description"];
|
$productDescription = $product["produit_description"];
|
||||||
$dateValue = "";
|
$dateValue = "";
|
||||||
|
|
||||||
if ($product === end($products)) {
|
if ($product === end($products)) {
|
||||||
$dateValue = $devisDate;
|
$dateValue = $devisDate;
|
||||||
$productDescription .= " de " . FileExportHelpers::GetSexeLabel($this->factureData['defunt_sexe']) . ' ' . $this->factureData["defunt_nom"];
|
$productDescription .= " de " . FileExportHelpers::GetSexeLabel($this->factureData['defunt_sexe']) . ' ' . $this->factureData["defunt_nom"];
|
||||||
@ -350,22 +369,40 @@ class InvoicePdfHandler extends FPDF
|
|||||||
|
|
||||||
$this->SetXY(5, $yValue);
|
$this->SetXY(5, $yValue);
|
||||||
$this->Cell(5, 6, $dateValue, 0, 0);
|
$this->Cell(5, 6, $dateValue, 0, 0);
|
||||||
|
|
||||||
$this->SetXY(30, $yValue);
|
$this->SetXY(30, $yValue);
|
||||||
$this->MultiAlignCell($maxDescriptionWidth, 6, utf8_decode(html_entity_decode($productDescription)), 0, '0', );
|
$this->MultiAlignCell($maxDescriptionWidth, 6, $this->SafeTextForPdf($productDescription), 0, '0', );
|
||||||
|
|
||||||
$this->SetXY(144, $yValue);
|
$this->SetXY(144, $yValue);
|
||||||
$this->Cell(20, 6, number_format($valueHt, 2, '.', '') . chr(128), 0, 0, 'C');
|
$this->Cell(20, 6, number_format($valueHt, 2, '.', '') . chr(128), 0, 0, 'C');
|
||||||
|
|
||||||
|
if ($this->hasTva) {
|
||||||
$this->SetXY(165, $yValue);
|
$this->SetXY(165, $yValue);
|
||||||
$this->Cell(20, 6, number_format($tvaAmount, 2, '.', '') . chr(128), 0, 0, 'C');
|
$this->Cell(20, 6, number_format($tvaAmount, 2, '.', '') . chr(128), 0, 0, 'C');
|
||||||
|
|
||||||
$this->SetXY(182, $yValue);
|
$this->SetXY(182, $yValue);
|
||||||
$this->Cell(25, 6, number_format($valueTtc, 2, '.', '') . chr(128), 0, 1, 'C');
|
$this->Cell(25, 6, number_format($valueTtc, 2, '.', '') . chr(128), 0, 1, 'C');
|
||||||
$yValue += 12;
|
} else {
|
||||||
|
$this->SetXY(182, $yValue);
|
||||||
|
$this->Cell(25, 6, number_format($valueHt, 2, '.', '') . chr(128), 0, 1, 'C');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$yValue += 12;
|
||||||
|
$totalTva += $tvaAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construction du tableau de retour selon hasTva
|
||||||
|
if ($this->hasTva) {
|
||||||
return [
|
return [
|
||||||
"TOTAL HT" => $totalHt,
|
"TOTAL HT" => $totalHt,
|
||||||
"TVA " . $tvaLabel => $totalTva,
|
"TVA " . $tvaValue . "%" => $totalTva,
|
||||||
"TOTAL TTC" => $totalTtc
|
"TOTAL TTC" => $totalTtc
|
||||||
];
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
"TOTAL HT" => $totalHt
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function DrawBankAndTotalPriceInfo($totalPriceArray)
|
private function DrawBankAndTotalPriceInfo($totalPriceArray)
|
||||||
@ -373,8 +410,8 @@ class InvoicePdfHandler extends FPDF
|
|||||||
$startOfYAfterMainTable = 236;
|
$startOfYAfterMainTable = 236;
|
||||||
$this->SetY($startOfYAfterMainTable);
|
$this->SetY($startOfYAfterMainTable);
|
||||||
$this->SetFont('ComicSans', '', 8);
|
$this->SetFont('ComicSans', '', 8);
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode("Paiement à votre convenance par chèque à l'ordre de " . $this->factureData['configuration']->entreprise)));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf("Paiement à votre convenance par chèque à l'ordre de " . $this->factureData['configuration']->entreprise));
|
||||||
$this->MultiCell(0, 4, utf8_decode(html_entity_decode("en indiquant le numéro de facture, ou par virement :")));
|
$this->MultiCell(0, 4, $this->SafeTextForPdf("en indiquant le numéro de facture, ou par virement :"));
|
||||||
|
|
||||||
$this->Ln(1);
|
$this->Ln(1);
|
||||||
$startOftable = 3;
|
$startOftable = 3;
|
||||||
|
|||||||
@ -27,19 +27,21 @@ declare(strict_types=1);
|
|||||||
namespace OCA\Gestion\Service;
|
namespace OCA\Gestion\Service;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use OCA\Gestion\Constants\BddConstant;
|
use Exception;
|
||||||
use OCA\Gestion\Constants\ClientTemplateTypeConstant;
|
|
||||||
use OCA\Gestion\Constants\DevisMentionConstant;
|
|
||||||
use OCA\Gestion\Constants\FactureTypeConstant;
|
|
||||||
use OCA\Gestion\Constants\MultipleFactureTypeConstant;
|
|
||||||
use OCA\Gestion\Db\Bdd;
|
use OCA\Gestion\Db\Bdd;
|
||||||
use OCA\Gestion\Helpers\DateHelpers;
|
|
||||||
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceFunecapPdfHandler;
|
|
||||||
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceGroupPdfHandler;
|
|
||||||
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceOgfPdfHandler;
|
|
||||||
use OCA\Gestion\Service\InvoiceRecap\InvoiceRecapService;
|
|
||||||
use OCP\DB\Exception;
|
|
||||||
use OCP\Files\IRootFolder;
|
use OCP\Files\IRootFolder;
|
||||||
|
use OCA\Gestion\Helpers\DateHelpers;
|
||||||
|
use OCA\Gestion\Constants\BddConstant;
|
||||||
|
use OCA\Gestion\Service\HtmlToPdfService;
|
||||||
|
use OCA\Gestion\Exception\TemplateException;
|
||||||
|
use OCA\Gestion\Constants\FactureTypeConstant;
|
||||||
|
use OCA\Gestion\Constants\DevisMentionConstant;
|
||||||
|
use OCA\Gestion\Constants\ClientTemplateTypeConstant;
|
||||||
|
use OCA\Gestion\Constants\MultipleFactureTypeConstant;
|
||||||
|
use OCA\Gestion\Service\InvoiceRecap\InvoiceRecapService;
|
||||||
|
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceOgfPdfHandler;
|
||||||
|
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceGroupPdfHandler;
|
||||||
|
use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceFunecapPdfHandler;
|
||||||
|
|
||||||
class InvoicePdfService
|
class InvoicePdfService
|
||||||
{
|
{
|
||||||
@ -52,6 +54,8 @@ class InvoicePdfService
|
|||||||
/** @var InvoiceRecapService */
|
/** @var InvoiceRecapService */
|
||||||
private $invoiceRecapService;
|
private $invoiceRecapService;
|
||||||
|
|
||||||
|
private $htmlToPdfService;
|
||||||
|
|
||||||
private const DEFAULT_NEXTCLOUD_ADMIN = "admin";
|
private const DEFAULT_NEXTCLOUD_ADMIN = "admin";
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Bdd $gestionBdd,
|
Bdd $gestionBdd,
|
||||||
@ -61,6 +65,7 @@ class InvoicePdfService
|
|||||||
$this->gestionBdd = $gestionBdd;
|
$this->gestionBdd = $gestionBdd;
|
||||||
$this->rootFolder = $rootFolder;
|
$this->rootFolder = $rootFolder;
|
||||||
$this->invoiceRecapService = $invoiceRecapService;
|
$this->invoiceRecapService = $invoiceRecapService;
|
||||||
|
$this->htmlToPdfService = new HtmlToPdfService();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLogo()
|
private function getLogo()
|
||||||
@ -108,17 +113,7 @@ class InvoicePdfService
|
|||||||
}
|
}
|
||||||
$pdfFilename = $prefixPdf."_".$pdfFilename;
|
$pdfFilename = $prefixPdf."_".$pdfFilename;
|
||||||
$filenames = [];
|
$filenames = [];
|
||||||
foreach($factureFolders as $folder) {
|
$filenames = $this->savePdfToFolders($factureFolders, $pdfFilename, $pdfContent, $storage);
|
||||||
try {
|
|
||||||
$storage->newFolder($folder);
|
|
||||||
} catch(\OCP\Files\NotPermittedException $e) {
|
|
||||||
}
|
|
||||||
$ff_pdf = $folder.$pdfFilename.'.pdf';
|
|
||||||
$storage->newFile($ff_pdf);
|
|
||||||
$file_pdf = $storage->get($ff_pdf);
|
|
||||||
$file_pdf->putContent($pdfContent);
|
|
||||||
$filenames[] = $ff_pdf;
|
|
||||||
}
|
|
||||||
$this->gestionBdd->setFactureGeneratedDate($factureId);
|
$this->gestionBdd->setFactureGeneratedDate($factureId);
|
||||||
return [
|
return [
|
||||||
"content" => $pdfContent,
|
"content" => $pdfContent,
|
||||||
@ -174,6 +169,12 @@ class InvoicePdfService
|
|||||||
if($invoicePdfData == null) {
|
if($invoicePdfData == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOUVELLE LOGIQUE : Vérifier si TVA exonérée
|
||||||
|
/*if ($this->isTvaExempt($invoicePdfData)) {
|
||||||
|
return $this->generateWithHtmlTemplate($invoicePdfData, $storage);
|
||||||
|
}*/
|
||||||
|
|
||||||
$templateType = $invoicePdfData['template_type_key'];
|
$templateType = $invoicePdfData['template_type_key'];
|
||||||
$clean_folder = html_entity_decode(string: $currentConfig->path).'/';
|
$clean_folder = html_entity_decode(string: $currentConfig->path).'/';
|
||||||
$factureFolders = $this->getGroupFactureFolder($invoicePdfData, $clean_folder);
|
$factureFolders = $this->getGroupFactureFolder($invoicePdfData, $clean_folder);
|
||||||
@ -200,17 +201,7 @@ class InvoicePdfService
|
|||||||
$pdfContent = $pdf->Output('', 'S');
|
$pdfContent = $pdf->Output('', 'S');
|
||||||
$pdfFilename = $pdf->GetInvoiceFilename();
|
$pdfFilename = $pdf->GetInvoiceFilename();
|
||||||
$filenames = [];
|
$filenames = [];
|
||||||
foreach($factureFolders as $folder) {
|
$filenames = $this->savePdfToFolders($factureFolders, $pdfFilename, $pdfContent, $storage);
|
||||||
try {
|
|
||||||
$storage->newFolder($folder);
|
|
||||||
} catch(\OCP\Files\NotPermittedException $e) {
|
|
||||||
}
|
|
||||||
$ff_pdf = $folder.$pdfFilename.'.pdf';
|
|
||||||
$storage->newFile($ff_pdf);
|
|
||||||
$file_pdf = $storage->get($ff_pdf);
|
|
||||||
$file_pdf->putContent($pdfContent);
|
|
||||||
$filenames[] = $ff_pdf;
|
|
||||||
}
|
|
||||||
$this->gestionBdd->setFactureGeneratedDate($factureId);
|
$this->gestionBdd->setFactureGeneratedDate($factureId);
|
||||||
return [
|
return [
|
||||||
"content" => $pdfContent,
|
"content" => $pdfContent,
|
||||||
@ -218,6 +209,19 @@ class InvoicePdfService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sanitizePathDev(string $path): string
|
||||||
|
{
|
||||||
|
$path = ltrim($path, '/');
|
||||||
|
// Remplacer accents UTF-8 par ASCII
|
||||||
|
$path = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $path);
|
||||||
|
// Supprimer caractères interdits par Nextcloud/Docker
|
||||||
|
$path = preg_replace('#[<>:"/\\|?*]#', '_', $path);
|
||||||
|
// Supprimer doublons d'espaces
|
||||||
|
$path = preg_replace('#\s+#', ' ', $path);
|
||||||
|
return trim($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function generateFacturePdfByFactureIds(array $factureIds, $idNextCloud)
|
public function generateFacturePdfByFactureIds(array $factureIds, $idNextCloud)
|
||||||
{
|
{
|
||||||
foreach($factureIds as $factureId) {
|
foreach($factureIds as $factureId) {
|
||||||
@ -249,16 +253,10 @@ class InvoicePdfService
|
|||||||
}
|
}
|
||||||
$clientRacineFolder = $racinePath.'CLIENTS/'.mb_strtoupper($clientNameInFolder, 'UTF-8').'/';
|
$clientRacineFolder = $racinePath.'CLIENTS/'.mb_strtoupper($clientNameInFolder, 'UTF-8').'/';
|
||||||
$filename = "FACTURE".'_'.$pdf->GetMultipleInvoiceFilename($month, $year);
|
$filename = "FACTURE".'_'.$pdf->GetMultipleInvoiceFilename($month, $year);
|
||||||
$filenamePath = $clientRacineFolder.$filename.'.pdf';
|
|
||||||
$pdfContent = $pdf->Output('', 'S');
|
$pdfContent = $pdf->Output('', 'S');
|
||||||
try {
|
$singleFolderArray = [$clientRacineFolder];
|
||||||
$storage->newFolder($clientRacineFolder);
|
$filenames = $this->savePdfToFolders($singleFolderArray, $filename, $pdfContent, $storage);
|
||||||
} catch(\OCP\Files\NotPermittedException $e) {
|
return $filenames[0];
|
||||||
}
|
|
||||||
$storage->newFile($filenamePath);
|
|
||||||
$file_pdf = $storage->get($filenamePath);
|
|
||||||
$file_pdf->putContent($pdfContent);
|
|
||||||
return $filenamePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateInvoiceRecap($filter, $filterType, $date, $idNextCloud)
|
public function generateInvoiceRecap($filter, $filterType, $date, $idNextCloud)
|
||||||
@ -338,4 +336,315 @@ class InvoicePdfService
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOUVELLE MÉTHODE : Génération avec template HTML
|
||||||
|
*/
|
||||||
|
private function generateWithHtmlTemplate($invoicePdfData, $storage)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Préparer les données pour le template HTML
|
||||||
|
$templateData = $this->prepareHtmlTemplateData($invoicePdfData);
|
||||||
|
|
||||||
|
// Générer le PDF avec le nouveau système
|
||||||
|
$pdfContent = $this->htmlToPdfService->generatePdf('facture_dv_thanato', $templateData);
|
||||||
|
|
||||||
|
// Nom du fichier
|
||||||
|
$pdfFilename = $this->htmlToPdfService->generateInvoiceFilename($invoicePdfData);
|
||||||
|
|
||||||
|
// Sauvegarder dans Nextcloud
|
||||||
|
$clean_folder = html_entity_decode(string: $invoicePdfData['configuration']->path).'/';
|
||||||
|
$factureFolders = $this->getGroupFactureFolder($invoicePdfData, $clean_folder);
|
||||||
|
$filenames = [];
|
||||||
|
$filenames = $this->savePdfToFolders($factureFolders, $pdfFilename, $pdfContent, $storage);
|
||||||
|
$this->gestionBdd->setFactureGeneratedDate($invoicePdfData['id']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
"content" => $pdfContent,
|
||||||
|
"filenames" => $filenames
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (TemplateException $e) {
|
||||||
|
error_log('HTML Template PDF Error: ' . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOUVELLE MÉTHODE : Détecte si TVA exonérée
|
||||||
|
*/
|
||||||
|
private function isTvaExempt($invoicePdfData)
|
||||||
|
{
|
||||||
|
// Vérifier si c'est un client unique avec TVA = 0
|
||||||
|
if (isset($invoicePdfData['fk_client_id']) && $invoicePdfData['fk_client_id'] != null && $invoicePdfData['fk_client_id'] != 0) {
|
||||||
|
$client = $this->gestionBdd->getClientById($invoicePdfData['fk_client_id']);
|
||||||
|
if (isset($client['tva']) && $client['tva'] == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prépare les données pour le template HTML - Version refactorisée
|
||||||
|
*/
|
||||||
|
private function prepareHtmlTemplateData($invoicePdfData)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'company' => $this->prepareCompanyData($invoicePdfData),
|
||||||
|
'client' => $this->prepareClientData($invoicePdfData),
|
||||||
|
'facture' => $this->prepareInvoiceData($invoicePdfData),
|
||||||
|
'groupedArticles' => $this->prepareGroupedArticles($invoicePdfData),
|
||||||
|
'totals' => $this->prepareTotals($invoicePdfData),
|
||||||
|
'bank' => $this->prepareBankData($invoicePdfData),
|
||||||
|
'legal_text' => $this->getLegalText()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prépare les données de l'entreprise
|
||||||
|
*/
|
||||||
|
private function prepareCompanyData($invoicePdfData)
|
||||||
|
{
|
||||||
|
$config = $invoicePdfData['configuration'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => $config->entreprise ?? 'DV Thanato',
|
||||||
|
'address' => $invoicePdfData['configuration_adresse'] ?? '47 rue Boldoduc',
|
||||||
|
'city' => $invoicePdfData['configuration_adresse_city'] ?? '59800 Lille',
|
||||||
|
'phone' => $config->telephone ?? '06.13.57.29.84',
|
||||||
|
'email' => $config->mail ?? 'soins@dvthanato.fr',
|
||||||
|
'logo' => 'logo_dv_thanato.png'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prépare les données du client
|
||||||
|
*/
|
||||||
|
private function prepareClientData($invoicePdfData)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => $invoicePdfData['group_name'] ?? '',
|
||||||
|
'address' => $invoicePdfData['client_real_adress'] ?? '',
|
||||||
|
'city' => $invoicePdfData['client_adress_city'] ?? '',
|
||||||
|
'siret' => $invoicePdfData['siret'] ?? ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prépare les données de la facture
|
||||||
|
*/
|
||||||
|
private function prepareInvoiceData($invoicePdfData)
|
||||||
|
{
|
||||||
|
$numero = $invoicePdfData['num'] ?? '';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'date' => date('d-m-Y'),
|
||||||
|
'number' => 'FAC' . str_pad((string)$numero, 6, '0', STR_PAD_LEFT),
|
||||||
|
'echeance' => date('d-m-Y', strtotime('+30 days')),
|
||||||
|
'period_start' => date('d/m/Y', strtotime($invoicePdfData['date'] ?? 'now')),
|
||||||
|
'period_end' => date('d/m/Y', strtotime($invoicePdfData['date_paiement'] ?? 'now'))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prépare les articles groupés par date et défunt
|
||||||
|
*/
|
||||||
|
private function prepareGroupedArticles($invoicePdfData)
|
||||||
|
{
|
||||||
|
if (!isset($invoicePdfData['devis']) || !is_array($invoicePdfData['devis'])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$groupedByDate = [];
|
||||||
|
|
||||||
|
foreach ($invoicePdfData['devis'] as $devis) {
|
||||||
|
$this->processDevis($devis, $groupedByDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->convertToIndexedArray($groupedByDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traite un devis et l'ajoute aux données groupées
|
||||||
|
*/
|
||||||
|
private function processDevis($devis, &$groupedByDate)
|
||||||
|
{
|
||||||
|
$dateDevis = date('d/m/Y', strtotime($devis['devis_date'] ?? 'now'));
|
||||||
|
$defuntNom = $devis['defunt_nom'] ?? 'Non défini';
|
||||||
|
|
||||||
|
$this->initializeDateGroup($groupedByDate, $dateDevis);
|
||||||
|
$this->initializeDefuntGroup($groupedByDate, $dateDevis, $defuntNom);
|
||||||
|
$this->addServicesToDefunt($groupedByDate, $dateDevis, $defuntNom, $devis['products'] ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise un groupe de date
|
||||||
|
*/
|
||||||
|
private function initializeDateGroup(&$groupedByDate, $dateDevis)
|
||||||
|
{
|
||||||
|
if (!isset($groupedByDate[$dateDevis])) {
|
||||||
|
$groupedByDate[$dateDevis] = [
|
||||||
|
'date' => $dateDevis,
|
||||||
|
'defunts' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise un groupe de défunt
|
||||||
|
*/
|
||||||
|
private function initializeDefuntGroup(&$groupedByDate, $dateDevis, $defuntNom)
|
||||||
|
{
|
||||||
|
if (!isset($groupedByDate[$dateDevis]['defunts'][$defuntNom])) {
|
||||||
|
$groupedByDate[$dateDevis]['defunts'][$defuntNom] = [
|
||||||
|
'nom' => $defuntNom,
|
||||||
|
'services' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajoute les services à un défunt
|
||||||
|
*/
|
||||||
|
private function addServicesToDefunt(&$groupedByDate, $dateDevis, $defuntNom, $products)
|
||||||
|
{
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$service = $this->createServiceFromProduct($product);
|
||||||
|
$groupedByDate[$dateDevis]['defunts'][$defuntNom]['services'][] = $service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un service à partir d'un produit
|
||||||
|
*/
|
||||||
|
private function createServiceFromProduct($product)
|
||||||
|
{
|
||||||
|
$prixHt = ($product['produit_price'] ?? 0) * ($product['quantite'] ?? 1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'reference' => $product['produit_reference'] ?? '',
|
||||||
|
'description' => $product['produit_description'] ?? 'Produit inconnu',
|
||||||
|
'prix_ht' => number_format($prixHt, 2, ',', ' '),
|
||||||
|
'quantite' => number_format($product['quantite'] ?? 1, 2, ',', ' '),
|
||||||
|
'prix_ttc' => number_format($prixHt, 2, ',', ' ')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convertit les données groupées en array indexé
|
||||||
|
*/
|
||||||
|
private function convertToIndexedArray($groupedByDate)
|
||||||
|
{
|
||||||
|
$groupedArticles = [];
|
||||||
|
|
||||||
|
foreach ($groupedByDate as $dateGroup) {
|
||||||
|
$defuntsArray = array_values($dateGroup['defunts']);
|
||||||
|
$dateGroup['defunts'] = $defuntsArray;
|
||||||
|
$groupedArticles[] = $dateGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $groupedArticles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prépare les totaux
|
||||||
|
*/
|
||||||
|
private function prepareTotals($invoicePdfData)
|
||||||
|
{
|
||||||
|
$totalPrices = $invoicePdfData['totalPrices'] ?? [];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'total_ht' => number_format($totalPrices['TOTAL HT'] ?? 0, 2, ',', ' '),
|
||||||
|
'total_tva' => '0,00',
|
||||||
|
'total_ttc' => number_format($totalPrices['TOTAL TTC'] ?? 0, 2, ',', ' '),
|
||||||
|
'tva_label' => 'TVA (exonéré)'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prépare les données bancaires
|
||||||
|
*/
|
||||||
|
private function prepareBankData($invoicePdfData)
|
||||||
|
{
|
||||||
|
$config = $invoicePdfData['configuration'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'iban' => 'FR76 1670 6052 4453 9757 9734 871',
|
||||||
|
'swift' => 'AGRI FR PP867',
|
||||||
|
'rcs' => $config->legal_one ?? '901 115 931 R.C.S Lille Métropole'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Texte légal
|
||||||
|
*/
|
||||||
|
private function getLegalText()
|
||||||
|
{
|
||||||
|
return "Tout retard de paiement entraînera de plein droit une pénalité de retard de 3 fois le taux légal " .
|
||||||
|
"(Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40 EUR pour frais de recouvrement sera appliquée.\n" .
|
||||||
|
"Si les frais de recouvrement sont supérieurs à ce montant forfaitaire, une indemnisation complémentaire " .
|
||||||
|
"sera due sur présentation de justificatifs (articles L 441-3 et L 441-6 du code de commerce).";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fonction générique pour sauvegarder un fichier PDF dans plusieurs dossiers
|
||||||
|
*
|
||||||
|
* @param array $factureFolders Liste des dossiers où sauvegarder
|
||||||
|
* @param string $pdfFilename Nom du fichier PDF (sans extension)
|
||||||
|
* @param string $pdfContent Contenu binaire du PDF
|
||||||
|
* @param mixed $storage Instance de stockage Nextcloud
|
||||||
|
* @return array Liste des chemins des fichiers créés
|
||||||
|
*/
|
||||||
|
private function savePdfToFolders(array $factureFolders, string $pdfFilename, string $pdfContent, $storage): array
|
||||||
|
{
|
||||||
|
$filenames = [];
|
||||||
|
|
||||||
|
foreach ($factureFolders as $folder) {
|
||||||
|
// Créer le chemin complet étape par étape
|
||||||
|
$this->ensurePathExists($storage, $folder);
|
||||||
|
|
||||||
|
$ff_pdf = $folder . $pdfFilename . '.pdf';
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($storage->nodeExists($ff_pdf)) {
|
||||||
|
$file_pdf = $storage->get($ff_pdf);
|
||||||
|
} else {
|
||||||
|
$file_pdf = $storage->newFile($ff_pdf);
|
||||||
|
}
|
||||||
|
$file_pdf->putContent($pdfContent);
|
||||||
|
$filenames[] = $ff_pdf;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// Supprimez ce var_dump pour éviter l'erreur de headers
|
||||||
|
// var_dump("yyyyyyyyyyyyyyyyyyyy".$e->getMessage());
|
||||||
|
error_log("ERROR on file '$ff_pdf': " . $e->getMessage());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $filenames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function ensurePathExists($storage, $path)
|
||||||
|
{
|
||||||
|
$parts = explode('/', trim($path, '/'));
|
||||||
|
$currentPath = '';
|
||||||
|
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (empty($part)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentPath .= '/' . $part;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!$storage->nodeExists($currentPath)) {
|
||||||
|
$storage->newFolder($currentPath);
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
error_log("Cannot create folder '$currentPath': " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,8 +29,8 @@ namespace OCA\Gestion\Service;
|
|||||||
use OCA\Gestion\Constants\BddConstant;
|
use OCA\Gestion\Constants\BddConstant;
|
||||||
use OCP\Files\IRootFolder;
|
use OCP\Files\IRootFolder;
|
||||||
|
|
||||||
class MailerService {
|
class MailerService
|
||||||
|
{
|
||||||
private $adminStorage;
|
private $adminStorage;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -38,15 +38,18 @@ class MailerService {
|
|||||||
) {
|
) {
|
||||||
$this->adminStorage = $rootFolder->getUserFolder(BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD);
|
$this->adminStorage = $rootFolder->getUserFolder(BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD);
|
||||||
}
|
}
|
||||||
public function getFooterContent ($userName = "Johann"){
|
public function getFooterContent($userName = "DEKINDT Vanessa")
|
||||||
|
{
|
||||||
$wish = "<p>Vous en souhaitant bonne réception. </p>";
|
$wish = "<p>Vous en souhaitant bonne réception. </p>";
|
||||||
$cordialement = "<p> Cordialement,</p>";
|
$cordialement = "<p> Cordialement,</p>";
|
||||||
$userName = "<p> {$userName} </p>" ;
|
$userName = "<p> {$userName} </p>" ;
|
||||||
$signatureImage = $this->getSignatureHtmlEmailContent();
|
// $signatureImage = $this->getSignatureHtmlEmailContent();
|
||||||
return $wish . $cordialement .$userName . $signatureImage ;
|
// return $wish . $cordialement .$userName . $signatureImage ;
|
||||||
|
return $wish . $cordialement .$userName ;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSignatureHtmlEmailContent (){
|
private function getSignatureHtmlEmailContent()
|
||||||
|
{
|
||||||
$signatureImage = $this->getSignatureContent();
|
$signatureImage = $this->getSignatureContent();
|
||||||
if (!$signatureImage) {
|
if (!$signatureImage) {
|
||||||
return "";
|
return "";
|
||||||
@ -54,14 +57,15 @@ class MailerService {
|
|||||||
return "<img width='170' height='80' style= 'width: 170;height: 80px;display:block;' src='data:image/jpeg;base64,".base64_encode($signatureImage)."'>" ;
|
return "<img width='170' height='80' style= 'width: 170;height: 80px;display:block;' src='data:image/jpeg;base64,".base64_encode($signatureImage)."'>" ;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSignatureContent(){
|
private function getSignatureContent()
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
if(isset($this->adminStorage)) {
|
if(isset($this->adminStorage)) {
|
||||||
$file = $this->adminStorage->get('/.gestion/sign.jpg');
|
$file = $this->adminStorage->get('/.gestion/sign.jpg');
|
||||||
return $file->getContent();
|
return $file->getContent();
|
||||||
}
|
}
|
||||||
|
} catch(\OCP\Files\NotFoundException $e) {
|
||||||
}
|
}
|
||||||
catch(\OCP\Files\NotFoundException $e) {}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use OC\URLGenerator;
|
use OC\URLGenerator;
|
||||||
use OCA\Gestion\Helpers\PriceHelpers;
|
use OCA\Gestion\Helpers\PriceHelpers;
|
||||||
|
|
||||||
$facture = $_['facture'];
|
$facture = $_['facture'];
|
||||||
$factureOrderNumber = $facture->facture_order_number == '' ? '-' : $facture->facture_order_number;
|
$factureOrderNumber = $facture->facture_order_number == '' ? '-' : $facture->facture_order_number;
|
||||||
$factureCaseNumber = $facture->facture_case_number == '' ? '-' : $facture->facture_case_number;
|
$factureCaseNumber = $facture->facture_case_number == '' ? '-' : $facture->facture_case_number;
|
||||||
@ -125,10 +126,27 @@ $currentConfig = json_decode($_['configuration'])[0];
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><?php echo (PriceHelpers::formatDecimalPrice($facture->totalHt).'€'); ?></td>
|
<td class="text-center"><?php echo PriceHelpers::formatDecimalPrice($facture->totalHt).'€'; ?></td>
|
||||||
<td class="text-center"><?php echo (PriceHelpers::formatDecimalPrice($currentConfig->tva_default).'€'); ?></td>
|
<td class="text-center">
|
||||||
<td class="text-center"><?php echo (PriceHelpers::formatDecimalPrice($facture->totalTva).'€'); ?></td>
|
<?php
|
||||||
<td class="text-center"><?php echo (PriceHelpers::formatDecimalPrice($facture->totalTtc).'€'); ?></td>
|
// Affichage simple : Exonéré ou taux par défaut
|
||||||
|
if (isset($facture->tvaInfo) && $facture->tvaInfo->is_exempt) {
|
||||||
|
echo 'Exonéré';
|
||||||
|
} else {
|
||||||
|
echo PriceHelpers::formatDecimalPrice($facture->tvaInfo->rate).'%';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<?php
|
||||||
|
if (isset($facture->tvaInfo) && $facture->tvaInfo->is_exempt) {
|
||||||
|
echo '0,00€';
|
||||||
|
} else {
|
||||||
|
echo PriceHelpers::formatDecimalPrice($facture->totalTva).'€';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td class="text-center"><?php echo PriceHelpers::formatDecimalPrice($facture->totalTtc).'€'; ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
194
gestion/templates/pdf/facture_dv_thanato.php
Normal file
194
gestion/templates/pdf/facture_dv_thanato.php
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Facture DV Thanato</title>
|
||||||
|
<style>
|
||||||
|
@page { margin: 20mm 15mm; size: A4; }
|
||||||
|
body { font-family: Arial, sans-serif; font-size: 11px; line-height: 1.4; color: #000; margin: 0; padding: 0; }
|
||||||
|
.container { width: 100%; }
|
||||||
|
|
||||||
|
/* LOGO EN HAUT */
|
||||||
|
.logo-section { margin-bottom: 20px; }
|
||||||
|
.logo { width: 180px; height: auto; }
|
||||||
|
|
||||||
|
/* HEADER AVEC TABLE POUR ALIGNEMENT */
|
||||||
|
.header-table { width: 100%; margin-bottom: 30px; }
|
||||||
|
.header-table td { vertical-align: top; padding: 0; }
|
||||||
|
.header-left { width: 45%; }
|
||||||
|
.header-right { width: 55%; text-align: right; }
|
||||||
|
|
||||||
|
/* INFORMATIONS GAUCHE */
|
||||||
|
.invoice-info { line-height: 1.6; }
|
||||||
|
.info-line { margin: 5px 0; }
|
||||||
|
.info-line strong { display: inline-block; width: 140px; font-weight: bold; }
|
||||||
|
|
||||||
|
/* INFORMATIONS CLIENT DROITE */
|
||||||
|
.client-info { text-align: right; line-height: 1.5; font-size: 12px; }
|
||||||
|
.client-info strong { display: block; margin-bottom: 3px; font-size: 13px; }
|
||||||
|
|
||||||
|
.invoice-header { margin: 25px 0; }
|
||||||
|
.invoice-header h2 { font-size: 14px; margin: 5px 0; font-weight: bold; }
|
||||||
|
.invoice-period { font-size: 11px; margin: 5px 0; }
|
||||||
|
|
||||||
|
/* TABLEAU SERVICES */
|
||||||
|
.services-table { width: 100%; border-collapse: collapse; margin: 20px 0; }
|
||||||
|
.services-table th { background-color: #f0f0f0; border: 1px solid #ccc; padding: 8px; text-align: left; font-weight: bold; font-size: 11px; }
|
||||||
|
.services-table td { border: 1px solid #ccc; padding: 6px 8px; vertical-align: top; font-size: 10px; }
|
||||||
|
|
||||||
|
.ref-col { width: 12%; }
|
||||||
|
.label-col { width: 48%; }
|
||||||
|
.price-col { width: 13%; text-align: right; }
|
||||||
|
.qty-col { width: 10%; text-align: center; }
|
||||||
|
.amount-col { width: 17%; text-align: right; }
|
||||||
|
|
||||||
|
/* LIGNES SPÉCIALES */
|
||||||
|
.date-row { background-color: #f8f8f8; font-weight: bold; }
|
||||||
|
.date-row td { padding: 8px; border: none; border-bottom: 1px solid #ddd; text-align: center; }
|
||||||
|
|
||||||
|
.deceased-row { font-style: italic; background-color: #fafafa; }
|
||||||
|
.deceased-row td { padding: 8px; border: none; font-weight: bold; }
|
||||||
|
|
||||||
|
/* TOTAUX */
|
||||||
|
.totals-section { margin-top: 30px; }
|
||||||
|
.totals-table { width: 300px; float: right; border-collapse: collapse; }
|
||||||
|
.totals-table td { padding: 8px 12px; font-size: 12px; }
|
||||||
|
.total-label { text-align: right; font-weight: bold; width: 60%; }
|
||||||
|
.total-amount { text-align: right; font-weight: bold; width: 40%; }
|
||||||
|
.total-row-ht { border-top: 1px solid #ccc; }
|
||||||
|
.total-row-final { border-top: 2px solid #000; font-size: 13px; }
|
||||||
|
|
||||||
|
/* CLEAR FLOAT */
|
||||||
|
.clear { clear: both; }
|
||||||
|
|
||||||
|
/* MENTIONS LÉGALES */
|
||||||
|
.legal-section { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ccc; }
|
||||||
|
.legal-text { font-size: 9px; line-height: 1.4; margin-bottom: 20px; text-align: justify; }
|
||||||
|
.bank-info { margin: 20px 0; font-size: 10px; line-height: 1.5; }
|
||||||
|
.bank-info strong { display: inline-block; width: 150px; }
|
||||||
|
.company-footer { margin-top: 30px; padding: 15px; background-color: #f5f5f5; font-size: 10px; line-height: 1.5; }
|
||||||
|
.company-footer strong { display: block; margin-bottom: 5px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<!-- Logo en haut à gauche -->
|
||||||
|
<div class="logo-section">
|
||||||
|
<img src="data:image/png;base64,<?= $logo_base64 ?>" alt="<?= htmlspecialchars($company['name']) ?>" class="logo">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Header avec table pour compatibilité dompdf -->
|
||||||
|
<table class="header-table">
|
||||||
|
<tr>
|
||||||
|
<td class="header-left">
|
||||||
|
<div class="invoice-info">
|
||||||
|
<div class="info-line">
|
||||||
|
<strong>Date :</strong><?= htmlspecialchars($facture['date']) ?>
|
||||||
|
</div>
|
||||||
|
<div class="info-line">
|
||||||
|
<strong>Échéance :</strong><?= htmlspecialchars($facture['echeance']) ?>
|
||||||
|
</div>
|
||||||
|
<div class="info-line">
|
||||||
|
<strong>Mode de paiement :</strong>Virement
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="header-right">
|
||||||
|
<div class="client-info">
|
||||||
|
<strong><?= htmlspecialchars($client['name']) ?></strong>
|
||||||
|
<?= htmlspecialchars($client['address']) ?><br>
|
||||||
|
<?= htmlspecialchars($client['city']) ?><br>
|
||||||
|
<?php if (!empty($client['siret'])): ?>
|
||||||
|
SIRET: <?= htmlspecialchars($client['siret']) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- Numéro de facture -->
|
||||||
|
<div class="invoice-header">
|
||||||
|
<h2>Facture <?= htmlspecialchars($facture['number']) ?></h2>
|
||||||
|
<div class="invoice-period">Période : du <?= htmlspecialchars($facture['period_start']) ?> au <?= htmlspecialchars($facture['period_end']) ?></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tableau des services -->
|
||||||
|
<table class="services-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="ref-col">Référence</th>
|
||||||
|
<th class="label-col">Libellé</th>
|
||||||
|
<th class="price-col">P.U HT</th>
|
||||||
|
<th class="qty-col">Quantité</th>
|
||||||
|
<th class="amount-col">Montant HT</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($groupedArticles as $dateGroup): ?>
|
||||||
|
<!-- Ligne de date centrée -->
|
||||||
|
<tr class="date-row">
|
||||||
|
<td colspan="5"><strong><?= htmlspecialchars($dateGroup['date']) ?></strong></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<?php foreach ($dateGroup['defunts'] as $defunt): ?>
|
||||||
|
<!-- Ligne du défunt -->
|
||||||
|
<tr class="deceased-row">
|
||||||
|
<td colspan="5"><?= htmlspecialchars($defunt['nom']) ?></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Services pour ce défunt -->
|
||||||
|
<?php foreach ($defunt['services'] as $service): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="ref-col"><?= htmlspecialchars($service['reference']) ?></td>
|
||||||
|
<td class="label-col"><?= htmlspecialchars($service['description']) ?></td>
|
||||||
|
<td class="price-col"><?= htmlspecialchars($service['prix_ht']) ?> €</td>
|
||||||
|
<td class="qty-col"><?= htmlspecialchars($service['quantite']) ?></td>
|
||||||
|
<td class="amount-col"><?= htmlspecialchars($service['prix_ttc']) ?> €</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- Section totaux -->
|
||||||
|
<div class="totals-section">
|
||||||
|
<table class="totals-table">
|
||||||
|
<tr class="total-row-ht">
|
||||||
|
<td class="total-label">Total HT</td>
|
||||||
|
<td class="total-amount"><?= htmlspecialchars($totals['total_ht']) ?> €</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="total-label"><?= htmlspecialchars($totals['tva_label']) ?></td>
|
||||||
|
<td class="total-amount"><?= htmlspecialchars($totals['total_tva']) ?> €</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="total-row-final">
|
||||||
|
<td class="total-label">Montant total</td>
|
||||||
|
<td class="total-amount"><?= htmlspecialchars($totals['total_ttc']) ?> €</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clear"></div>
|
||||||
|
|
||||||
|
<!-- Mentions légales -->
|
||||||
|
<div class="legal-section">
|
||||||
|
<div class="legal-text">
|
||||||
|
<?= nl2br(htmlspecialchars($legal_text)) ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bank-info">
|
||||||
|
<div><strong>Coordonnées bancaires</strong></div>
|
||||||
|
<div><strong>IBAN:</strong> <?= htmlspecialchars($bank['iban']) ?></div>
|
||||||
|
<div><strong>BIC:</strong> <?= htmlspecialchars($bank['swift']) ?></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="company-footer">
|
||||||
|
<strong><?= htmlspecialchars($company['name']) ?></strong>
|
||||||
|
<?= htmlspecialchars($company['address']) ?>, <?= htmlspecialchars($company['city']) ?><br>
|
||||||
|
<?= htmlspecialchars($bank['rcs']) ?> - Code NAF 9603Z
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
303
gestion/vendor/composer/installed.json
vendored
303
gestion/vendor/composer/installed.json
vendored
@ -125,6 +125,240 @@
|
|||||||
],
|
],
|
||||||
"install-path": "../doctrine/instantiator"
|
"install-path": "../doctrine/instantiator"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/dompdf",
|
||||||
|
"version": "v3.1.0",
|
||||||
|
"version_normalized": "3.1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/dompdf.git",
|
||||||
|
"reference": "a51bd7a063a65499446919286fb18b518177155a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a",
|
||||||
|
"reference": "a51bd7a063a65499446919286fb18b518177155a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dompdf/php-font-lib": "^1.0.0",
|
||||||
|
"dompdf/php-svg-lib": "^1.0.0",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"masterminds/html5": "^2.0",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"mockery/mockery": "^1.3",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "Needed to process images",
|
||||||
|
"ext-gmagick": "Improves image processing performance",
|
||||||
|
"ext-imagick": "Improves image processing performance",
|
||||||
|
"ext-zlib": "Needed for pdf stream compression"
|
||||||
|
},
|
||||||
|
"time": "2025-01-15T14:09:04+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dompdf\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"lib/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The Dompdf Community",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||||
|
"source": "https://github.com/dompdf/dompdf/tree/v3.1.0"
|
||||||
|
},
|
||||||
|
"install-path": "../dompdf/dompdf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-font-lib",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"version_normalized": "1.0.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-font-lib.git",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
|
||||||
|
},
|
||||||
|
"time": "2024-12-02T14:37:59+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"FontLib\\": "src/FontLib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The FontLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse, export and make subsets of different types of font files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-font-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.1"
|
||||||
|
},
|
||||||
|
"install-path": "../dompdf/php-font-lib"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-svg-lib",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"version_normalized": "1.0.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"sabberworm/php-css-parser": "^8.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
|
||||||
|
},
|
||||||
|
"time": "2024-04-29T13:26:35+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Svg\\": "src/Svg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The SvgLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse and export to PDF SVG files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0"
|
||||||
|
},
|
||||||
|
"install-path": "../dompdf/php-svg-lib"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "masterminds/html5",
|
||||||
|
"version": "2.10.0",
|
||||||
|
"version_normalized": "2.10.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Masterminds/html5-php.git",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||||
|
},
|
||||||
|
"time": "2025-07-25T09:04:22+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.7-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"install-path": "../masterminds/html5"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "myclabs/deep-copy",
|
"name": "myclabs/deep-copy",
|
||||||
"version": "1.11.0",
|
"version": "1.11.0",
|
||||||
@ -1318,6 +1552,75 @@
|
|||||||
},
|
},
|
||||||
"install-path": "../psr/log"
|
"install-path": "../psr/log"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "sabberworm/php-css-parser",
|
||||||
|
"version": "v8.9.0",
|
||||||
|
"version_normalized": "8.9.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
|
||||||
|
"rawr/cross-data-providers": "^2.0.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||||
|
},
|
||||||
|
"time": "2025-07-11T13:20:48+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "9.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"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/v8.9.0"
|
||||||
|
},
|
||||||
|
"install-path": "../sabberworm/php-css-parser"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user