diff --git a/gestion/appinfo/routes.php b/gestion/appinfo/routes.php index dd1ca6a..19a7d2a 100644 --- a/gestion/appinfo/routes.php +++ b/gestion/appinfo/routes.php @@ -31,6 +31,7 @@ return [ ['name' => 'page#getThanatopracteurs', 'url' => '/getThanatopracteurs', 'verb' => 'PROPFIND'], ['name' => 'page#insertThanatopracteur', 'url' => '/thanatopracteur/insert', 'verb' => 'POST'], ['name' => 'page#exportThanatoStatistic', 'url' => '/thanatopracteur/exportThanatoStatistic', 'verb' => 'POST'], + ['name' => 'page#generateSamplePdf', 'url' => '/generateSamplePdf', 'verb' => 'POST'], ['name' => 'page#getDevis', 'url' => '/getDevis', 'verb' => 'PROPFIND'], ['name' => 'page#getDevisDelphine', 'url' => '/getDevisDelphine/{idtrajetdetails}', 'verb' => 'PROPFIND'], diff --git a/gestion/lib/Controller/PageController.php b/gestion/lib/Controller/PageController.php index b07dc12..86c2a55 100644 --- a/gestion/lib/Controller/PageController.php +++ b/gestion/lib/Controller/PageController.php @@ -1,5 +1,7 @@ config = $config; $this->exportThanatoStatisticService = $exportThanatoStatisticService; $this->exportClientStatisticService = $exportClientStatisticService; + $this->invoicePdfService = $invoicePdfService; //$this->fpdf = $fpdf; if ($userSession->isLoggedIn()) { @@ -1652,7 +1660,8 @@ class PageController extends Controller { * @param array $devisToFacture */ public function exportDevisToFacture($devisToFacture) { - $result = $this->myDb->insertFactureForeEachDevisId($this->idNextcloud,$devisToFacture); + $factureIdsGenerated = $this->myDb->insertFactureForeEachDevisId($this->idNextcloud,$devisToFacture); + $this->invoicePdfService->generateFacturePdfByFactureIds($factureIdsGenerated,$this->idNextcloud); $this->refreshFEC(); return true; } @@ -1931,13 +1940,18 @@ class PageController extends Controller { private function getLogo(){ - try { - if(isset($this->storage)){ - $file = $this->storage->get('/.gestion/logo.png'); - }else{ - return "nothing"; + try{ + try { + if(isset($this->storage)){ + $file = $this->storage->get('/.gestion/logo.png'); + }else{ + return "nothing"; + } + } catch(\OCP\Files\NotFoundException $e) { + $file = $this->storage->get('/.gestion/logo.jpeg'); } - } catch(\OCP\Files\NotFoundException $e) { + } + catch(\OCP\Files\NotFoundException $e) { return "nothing"; } @@ -2616,4 +2630,47 @@ class PageController extends Controller { catch(\OCP\Files\NotFoundException $e) { } } + + /** + * @NoAdminRequired + * @NoCSRFRequired + * @param int $factureId + * + */ + + public function generateSamplePdf($factureId){ + $factureId = 1; + $configs = json_decode($this->myDb->getConfiguration($this->idNextcloud)); + $currentConfig = $configs[0]; + $logo = $this->getLogo(); + $invoicePdfData = $this->myDb->getInvoicePdfData($factureId,$currentConfig); + if($invoicePdfData == null){ + return ""; + } + try{ + $clean_folder = html_entity_decode($currentConfig->path).'/'; + $_clean_folder = $clean_folder.'SAMPLES/'; + try { + $this->storage->newFolder($_clean_folder); + } + catch(\OCP\Files\NotPermittedException $e) { + + } + $pdf = new InvoicePdfHandler(); + $pdf->InvoicePdfFactory($invoicePdfData,$logo); + $pdfContent = $pdf->GetFactureContent(); + + $pdf->Output(); + $ff_pdf = $_clean_folder.Uuid::uuid4()->toString().'.pdf'; + $this->storage->newFile($ff_pdf); + $file_pdf = $this->storage->get($ff_pdf); + $file_pdf->putContent($pdfContent); + + $res = array(); + $res['path'] = $_clean_folder; + return json_encode($res); + } + catch(\OCP\Files\NotFoundException $e) { } + + } } diff --git a/gestion/lib/Db/Bdd.php b/gestion/lib/Db/Bdd.php index 57f211b..ed13455 100644 --- a/gestion/lib/Db/Bdd.php +++ b/gestion/lib/Db/Bdd.php @@ -959,10 +959,12 @@ class Bdd { $this->logger->debug($devisIdarrayToString); $mentionToNotInclude = 'facturé'; $devisIdListFiltered = $this->getDevisIdListFilteredByMentionAndDevisListId($mentionToNotInclude,$devisIdArray); + $factureIdsGenerated = []; foreach($devisIdListFiltered as $devis){ - $this->insertFactureByDevisId($idNextCloud,devisId: $devis['id']); + $factureId = $this->insertFactureByDevisId($idNextCloud,devisId: $devis['id']); + $factureIdsGenerated[] = $factureId; } - return true; + return $factureIdsGenerated; } /** @@ -971,8 +973,6 @@ class Bdd { public function insertFactureByDevisId($idNextcloud,$devisId){ $last = 0; $last = $this->lastNumFacture($idNextcloud); - $pref = $this->execSQLNoJsonReturn("SELECT * FROM ".$this->tableprefix."configuration WHERE id_nextcloud LIKE ?",array($idNextcloud)); - $sql = "INSERT INTO `".$this->tableprefix."facture` (`date`,`id_nextcloud`,`num`,`date_paiement`,`type_paiement`,`id_devis`,`user_id`, `version`) VALUES (?,?,?,NOW(),?,?,?,?);"; $date_temp = new DateTime(); $date = $date_temp->format('Y-m-d'); @@ -986,9 +986,25 @@ class Bdd { $last+1, "Ajouter un lieu")); + $factureId = $this->getFactureIdByDevisId($devisId); //update devis status $this->gestion_update('devis','mentions','facturé',$devisId,$idNextcloud); - return $last; + return $factureId; + } + + private function getFactureIdByDevisId($devisId){ + $sql = "SELECT + facture.id + FROM ".$this->tableprefix."facture as facture + WHERE facture.id_devis = ? + ORDER BY facture.id DESC;"; + $facture = $this->execSQLNoJsonReturn( + $sql, + [$devisId]); + if(!empty($facture)){ + return $facture[0]['id']; + } + return null; } @@ -1964,22 +1980,29 @@ class Bdd { return null; } - private function getProduitsDevisStatistic($devisId){ + private function getDevisProduits($devisId){ $sql = "SELECT produit_devis.id, produit_devis.produit_id, produit_devis.quantite, produit_devis.discount, - produit.prix_unitaire as produit_price + produit.prix_unitaire as produit_price, + produit.reference as produit_reference, + produit.description as produit_description, + produit.vat as produit_vat FROM ".$this->tableprefix ."produit_devis as produit_devis LEFT JOIN ".$this->tableprefix."produit as produit on produit_devis.produit_id = produit.id WHERE produit_devis.devis_id = ?;"; - $produitList = $this->execSQLNoJsonReturn( $sql, [$devisId]); + return $produitList; + } + + private function getProduitsDevisStatistic($devisId){ + $produitList = $this->getDevisProduits($devisId); $productsCount = count($produitList); $productsPrice = 0; @@ -2006,7 +2029,8 @@ class Bdd { facture.date, facture.date_paiement, devis.id as devis_id, - devis.id_client as devis_client_id + devis.id_client as devis_client_id, + devis.date as devis_date FROM ".$this->tableprefix."facture as facture LEFT JOIN ".$this->tableprefix."devis as devis on facture.id_devis = devis.id WHERE YEAR(facture.date_paiement) = ? AND @@ -2092,4 +2116,51 @@ class Bdd { return $clientList; } + public function getInvoicePdfData($factureId,$configuration){ + $factureData = $this->getFactureByIdWithDevis($factureId); + if($factureData == null){ + return null; + } + $products = $this->getDevisProduits($factureData["devis_id"]); + $factureData = $this->setDevisStartAndEndTime($factureData); + $factureData["products"] = $products; + $factureData["configuration"] = $configuration; + return $factureData; + } + + private function getFactureByIdWithDevis($factureId){ + $sql = "SELECT + facture.id, + facture.date, + facture.date_paiement, + facture.num, + devis.id as devis_id, + devis.date as devis_date, + devis.num as calendar_uuid, + devis.comment as devis_comment, + client.nom as client_nom, + client.entreprise as client_entreprise, + client.adresse as client_adresse, + defunt.nom as defunt_nom, + lieu.nom as lieu_nom, + lieu.adresse as lieu_adresse, + thanato.nom as thanato_nom, + thanato.prenom as thanato_prenom + FROM ".$this->tableprefix."facture as facture + LEFT JOIN ".$this->tableprefix."devis as devis on facture.id_devis = devis.id + LEFT JOIN ".$this->tableprefix."client as client on devis.id_client = client.id + LEFT JOIN ".$this->tableprefix."defunt as defunt on devis.id_defunt = defunt.id + LEFT JOIN ".$this->tableprefix."lieu as lieu on devis.id_lieu = lieu.id + LEFT JOIN ".$this->tableprefix."thanato as thanato on devis.id_thanato = thanato.id + WHERE facture.id = ? + ;"; + $facture = $this->execSQLNoJsonReturn( + $sql, + [$factureId]); + if(!empty($facture)){ + return $facture[0]; + } + return null; + } + } \ No newline at end of file diff --git a/gestion/lib/Helpers/DateHelpers.php b/gestion/lib/Helpers/DateHelpers.php index b266531..a009161 100644 --- a/gestion/lib/Helpers/DateHelpers.php +++ b/gestion/lib/Helpers/DateHelpers.php @@ -20,4 +20,16 @@ class DateHelpers } } + public static function GetDateWithFormatDayAndMonthPlainString(string $date){ + $dateTime = new DateTime($date); + $formattedDate = $dateTime->format('d F'); + $formattedDate = str_replace( + array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + array('JANVIER', 'FEVRIER', 'MARS', 'AVRIL', 'MAI', 'JUIN', 'JUILLET', 'AOUT', 'SEPTEMBRE', 'OCTOBRE', 'NOVEMBRE', 'DECEMBRE'), + $formattedDate + ); + + return $formattedDate; + } + } diff --git a/gestion/lib/Helpers/PriceHelpers.php b/gestion/lib/Helpers/PriceHelpers.php new file mode 100644 index 0000000..fa6abc9 --- /dev/null +++ b/gestion/lib/Helpers/PriceHelpers.php @@ -0,0 +1,16 @@ + + * + * @author Anna Larch + * @author Richard Steinmetz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OCA\Gestion\Service; + +use \FPDF; +use OCA\Gestion\Helpers\PriceHelpers; + +class InvoicePdfHandler extends FPDF { + + private $factureData = []; + private $logo = null; + private $logoPath = "/var/www/html/custom_apps/gestion/img/"; + + function Header() + { + if($this->logo != "nothing"){ + $this->Image($this->logoPath."logo.png", 10, 10, 55, 30); + } + else{ + $this->Cell(55,30,''); + } + $this->Ln(30); + } + + // Page footer + function Footer() + { + $this->SetY(-15); + $this->SetFont('Arial', '', 11); + $this->Cell(0, 10, utf8_decode(html_entity_decode($this->factureData['configuration']->legal_one)), 0, 0, 'C'); + } + + public function InvoicePdfFactory(array $factureData,$logo = null){ + $this->factureData = $factureData; + $this->logo = $logo; + } + + public function GetFilename(){ + $factureNum = $this->factureData['num']; + $factureNum = str_replace('/','-',$factureNum); + return $this->factureData['configuration']->facture_prefixe.'_'.$factureNum.'_'.strtoupper($this->factureData['defunt_nom']); + } + + public function GetFactureContent(){ + $this->AddPage(); + $this->SetFont('Arial', '', 12); + $this->Cell(0, 7, utf8_decode(html_entity_decode($this->factureData['configuration']->entreprise)), 0, 0); + $this->Cell(0, 7, utf8_decode(html_entity_decode($this->factureData['client_nom'] . ' ' . $this->factureData['client_entreprise'])), 0, 1,'R'); + $this->Cell(0, 7, utf8_decode(html_entity_decode($this->factureData['configuration']->adresse)), 0, 0);border: + $this->Cell(0, 7, utf8_decode(html_entity_decode($this->factureData['client_adresse'])), 0, 1,'R'); + $this->Cell(0, 7, utf8_decode(html_entity_decode('Tél : ')) . utf8_decode(html_entity_decode($this->factureData['configuration']->telephone)) , 0, 1); + $this->Cell(0, 7, 'Mail : ' . $this->factureData['configuration']->mail, 0, 1); + + $this->Ln(3); + + //facture infos + $this->SetFont('Arial', 'B', 11); + $this->Cell(30, 7, 'DATE', 1, 0, 'C'); + $this->Cell(30, 7, 'CLIENT', 1, 0, 'C'); + $this->Cell(30, 7, 'FACTURE', 1, 0, 'C'); + $this->Cell(30, 7, 'ECHEANCE', 1, 1, 'C'); + + $this->SetFont('Arial', '', 10); + $this->Cell(30, 7, $this->factureData['date'], 1, 0, 'C'); + $this->Cell(30, 7, utf8_decode(html_entity_decode($this->factureData['client_nom'])), 1, 0, 'C'); + $this->Cell(30, 7, $this->factureData['num'], 1, 0, 'C'); + $this->Cell(30, 7, $this->factureData['date_paiement'], 1, 1, 'C'); + + $this->Ln(8); + + //Articles info + $this->SetFont('Arial', 'B', 11); + $this->Cell(20, 8, 'Date', 1, 0); + $this->Cell(20, 8, 'Heure', 1, 0,'C'); + $this->Cell(80, 8, 'Description', 1, 0,'C'); + $this->Cell(30, 8, 'Prix Uni. HT', 1, 0, 'C'); + $this->Cell(30, 8, 'Prix Uni. TTC', 1, 1, 'C'); + + $totalHt = 0; + $totalTtc = 0; + foreach($this->factureData["products"] as $product){ + $tvaValue = $product['produit_vat']; + $valueHt = $product['produit_price']; + $valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt,$tvaValue); + $totalHt+=$valueHt; + $totalTtc+=$valueTtc; + $descriptionLineNumber = $this->NbLines(80,$product["produit_description"]); + $articleListMaxHeight = $descriptionLineNumber * 10; + $this->SetFont('Arial', '', 10); + $this->Cell(20, $articleListMaxHeight, $this->factureData['date'], 'LR',0); + $this->Cell(20, $articleListMaxHeight, $this->factureData['startTime'], 'LR',0,'C'); + $this->MultiAlignCell(80, $articleListMaxHeight, utf8_decode(html_entity_decode($product["produit_description"])),'LR','0',); + $this->Cell(30, $articleListMaxHeight, $valueHt, 'LR', 0, 'C'); + $this->Cell(30, $articleListMaxHeight, $valueTtc, 'LR', 1, 'C'); + } + $this->Cell(180,0,'','T'); + $this->Ln(8); + $this->SetFont('Arial', '', 9); + $this->MultiCell(0,5,utf8_decode(html_entity_decode("Paiement à votre convenance par chèque à l'ordre d'Hytha 35 + en indiquant le numéro de facture, ou par virement :")),0,'J'); + + $this->Ln(1); + + //Table IBAN + $this->SetFont('Arial', '', 11); + $ibanWidth = 90; + $this->Cell($ibanWidth, 7, 'IBAN : FR76 1360 6000 1436 5418 1800 038', 1, 1, 'C'); + $ibanCursorX = $this->GetX(); + $ibanCursorY = $this->GetY(); + $this->Cell($ibanWidth, 7, 'Code SWIFT : AGRI FR PP 836', 1, 1, 'C'); + + //TABLE HT + $ibanLastPositionX = $ibanCursorX+$ibanWidth + 20; + $this->SetXY($ibanLastPositionX,$ibanCursorY); + $this->SetFont('Arial', 'B', 12); + $totalHtArrayWidth = 30; + $this->Cell($totalHtArrayWidth, 7, 'TOTAL HT', 1, 1, 'C'); + $this->SetXY($ibanLastPositionX,$ibanCursorY); + $this->SetFont('Arial', '', 11); + $this->Cell($totalHtArrayWidth, 20, $totalHt, 1, 1, 'C'); + + $tableHTLastPostionX = $ibanLastPositionX + $totalHtArrayWidth + 10; + //TABLE TTC + $this->SetXY($tableHTLastPostionX,$ibanCursorY+7); + $this->SetFont('Arial', 'B', 12); + $this->Cell(30, 7, 'TOTAL TTC', 1, 1, 'C'); + $this->SetXY($tableHTLastPostionX,$ibanCursorY+14); + $this->SetFont('Arial', '', 11); + $this->Cell(30, 7, $totalTtc, 1, 1, 'C'); + + $this->Ln(2); + + $this->SetFont('Arial', '', 9); + $this->MultiCell(100,5,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 +( Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40€ pour frais de recouvrement +sera appliquée.'))); + $this->Ln(1); + $this->MultiCell(100,5,utf8_decode(html_entity_decode('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 ). +'))); + + $pdfContent = $this->Output('','S'); + + return $pdfContent; + } + + function MultiAlignCell($w,$h,$text,$border=0,$ln=0,$align='L',$fill=false) + { + // Store reset values for (x,y) positions + $x = $this->GetX() + $w; + $y = $this->GetY(); + + // Make a call to FPDF's MultiCell + $this->MultiCell($w,$h,$text,$border,$align,$fill); + + // Reset the line position to the right, like in Cell + if( $ln==0 ) + { + $this->SetXY($x,$y); + } + } + + function NbLines($w, $txt) + { + // Compute the number of lines a MultiCell of width w will take + if(!isset($this->CurrentFont)) + $this->Error('No font has been set'); + $cw = $this->CurrentFont['cw']; + if($w==0) + $w = $this->w-$this->rMargin-$this->x; + $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize; + $s = str_replace("\r",'',(string)$txt); + $nb = strlen($s); + if($nb>0 && $s[$nb-1]=="\n") + $nb--; + $sep = -1; + $i = 0; + $j = 0; + $l = 0; + $nl = 1; + while($i<$nb) + { + $c = $s[$i]; + if($c=="\n") + { + $i++; + $sep = -1; + $j = $i; + $l = 0; + $nl++; + continue; + } + if($c==' ') + $sep = $i; + $l += $cw[$c]; + if($l>$wmax) + { + if($sep==-1) + { + if($i==$j) + $i++; + } + else + $i = $sep+1; + $sep = -1; + $j = $i; + $l = 0; + $nl++; + } + else + $i++; + } + return $nl; + } +} diff --git a/gestion/lib/Service/InvoicePdfService.php b/gestion/lib/Service/InvoicePdfService.php new file mode 100644 index 0000000..1be9654 --- /dev/null +++ b/gestion/lib/Service/InvoicePdfService.php @@ -0,0 +1,121 @@ + + * + * @author Anna Larch + * @author Richard Steinmetz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OCA\Gestion\Service; + +use DateTime; +use OCA\Gestion\Db\Bdd; +use OCA\Gestion\Helpers\DateHelpers; +use OCP\Files\IRootFolder; + +class InvoicePdfService { + /** @var Bdd */ + private $gestionBdd; + + /** @var IRootStorage */ + private $storage; + + public function __construct( + Bdd $gestionBdd, + IRootFolder $rootFolder) { + $this->gestionBdd = $gestionBdd; + try{ + $this->storage = $rootFolder->getUserFolder('admin'); + }catch(\OC\User\NoUserException $e){ + + } + } + + private function getLogo(){ + try{ + try { + if(isset($this->storage)){ + $file = $this->storage->get('/.gestion/logo.png'); + }else{ + return "nothing"; + } + } catch(\OCP\Files\NotFoundException $e) { + $file = $this->storage->get('/.gestion/logo.jpeg'); + } + } + catch(\OCP\Files\NotFoundException $e) { + return "nothing"; + } + + return base64_encode($file->getContent()); + } + + public function generateFacturePdfByFactureId($factureId,$idNextCloud){ + $configs = json_decode($this->gestionBdd->getConfiguration($idNextCloud)); + $currentConfig = $configs[0]; + $logo = $this->getLogo(); + $invoicePdfData = $this->gestionBdd->getInvoicePdfData($factureId,$currentConfig); + if($invoicePdfData == null){ + return ""; + } + $clean_folder = html_entity_decode($currentConfig->path).'/'; + $factureFolders = $this->getFacturesFolder($invoicePdfData,$clean_folder); + $pdf = new InvoicePdfHandler(); + $pdf->InvoicePdfFactory($invoicePdfData,$logo); + $pdfContent = $pdf->GetFactureContent(); + $pdfFilename = $pdf->GetFilename(); + $filenames = []; + foreach($factureFolders as $folder){ + try { + $this->storage->newFolder($folder); + $ff_pdf = $folder.$pdfFilename.'.pdf'; + $this->storage->newFile($ff_pdf); + $file_pdf = $this->storage->get($ff_pdf); + $file_pdf->putContent($pdfContent); + $filenames[] = $ff_pdf; + } + catch(\OCP\Files\NotPermittedException $e) { + + } + } + return $filenames; + } + + private function getFacturesFolder(array $factureData,$racinePath){ + $clientRacineFolder = $racinePath.'CLIENTS/'.strtoupper($factureData["client_entreprise"]).'/'; + $defuntsFolder = $clientRacineFolder.'DEFUNTS/'.strtoupper($factureData['defunt_nom']).'/'.'FACTURES'.'/'; + $devisDate = $factureData['devis_date']; + $devisDatetime = new DateTime($devisDate); + $devisDateYear = $devisDatetime->format('Y'); + $devisMonth = DateHelpers::GetDateWithFormatDayAndMonthPlainString($factureData['devis_date']); + $factureByYearFolder = $clientRacineFolder."$devisDateYear".'/'.$devisMonth.'/'.'FACTURES'.'/'; + return [ + $defuntsFolder, + $factureByYearFolder + ]; + } + + public function generateFacturePdfByFactureIds(array $factureIds,$idNextCloud){ + foreach( $factureIds as $factureId ){ + $this->generateFacturePdfByFactureId($factureId,$idNextCloud); + } + } +}