Compare commits
8 Commits
feat-tva-m
...
production
| Author | SHA1 | Date | |
|---|---|---|---|
| d2bb1a9cc6 | |||
| 8cacac1efc | |||
| a28b7f6ea6 | |||
| 03784fd8e6 | |||
| 411cc2d5a8 | |||
| 34717b772d | |||
| b6ea2550bc | |||
| 65d13d70f9 |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -332,8 +332,6 @@ OC.L10N.register(
|
||||
"Quantity" : "Quantity",
|
||||
"Unit price without VAT" : "Unit price (excluding VAT)",
|
||||
"Total without VAT" : "Total (excluding VAT)",
|
||||
"Unit price with VAT" : "Unit price (including VAT)",
|
||||
"Total with VAT" : "Total (including VAT)",
|
||||
"Add product" : "Add product",
|
||||
"Save in Nextcloud" : "Save in Nextcloud",
|
||||
"Send by email" : "Send by email",
|
||||
|
||||
@ -331,8 +331,6 @@ OC.L10N.register(
|
||||
"Offer valid for 1 month from" : "Offre valide 1 mois à compter du",
|
||||
"Quantity" : "Quantité",
|
||||
"Unit price without VAT" : "PU HT",
|
||||
"Unit price with VAT" : "PU TTC",
|
||||
"Total with VAT" : "Total TTC",
|
||||
"Total without VAT" : "Total HT",
|
||||
"Add product" : "Ajouter produit",
|
||||
"Save in Nextcloud" : "Sauvegarder dans nextcloud",
|
||||
|
||||
@ -2657,7 +2657,9 @@ class PageController extends Controller
|
||||
public function getTotalDevis($numdevis)
|
||||
{
|
||||
$total = $this->myDb->getTotalDevis($numdevis, $this->idNextcloud);
|
||||
return json_encode($total);
|
||||
$res = array();
|
||||
$res['total'] = $total;
|
||||
return json_encode($res);
|
||||
}
|
||||
|
||||
private function calculAge($dateNaissance)
|
||||
|
||||
@ -41,7 +41,7 @@ class Bdd
|
||||
public function __construct(IDbConnection $db, IL10N $l, LoggerInterface $logger)
|
||||
{
|
||||
$this->whiteColumn = array("date", "num", "id_client", "id_thanato", "entreprise", "nom", "prenom", "legal_one", "telephone", "mail", "adresse", "produit_id",
|
||||
"quantite", "date_paiement", "type_paiement", "id_devis", "reference", "description", "prix_unitaire", "tva", "unit_price", "legal_two", "path", "tva_default", "coefficient_ik",
|
||||
"quantite", "date_paiement", "type_paiement", "id_devis", "reference", "description", "prix_unitaire", "legal_two", "path", "tva_default", "coefficient_ik",
|
||||
"mentions_default", "version", "mentions", "comment", "status_paiement", "devise", "auto_invoice_number", "changelog", "format", "comment", "user_id",
|
||||
"facture_prefixe", "arrivee", "depart", "latitude", "longitude", "id_lieu", "rang", "mois", "annee", "id_trajet", "commentaire","source",
|
||||
"date_habilitation", "sexe", "observations_generales", "ref_pacemaker", "id_defunt", "article_id", "corpulence", "lieu_deces",
|
||||
@ -79,50 +79,14 @@ class Bdd
|
||||
{
|
||||
$articles = json_decode($this->getListArticle($iddevis, $idNextcloud));
|
||||
$produits = json_decode($this->getListProduit($iddevis, $idNextcloud));
|
||||
|
||||
// Grouper les totaux par taux de TVA
|
||||
$totalsByTva = array();
|
||||
|
||||
// Traiter les articles
|
||||
$total = 0;
|
||||
foreach($articles as $key => $article) {
|
||||
$tva = floatval($article->tva ?? 20.00);
|
||||
$totalHT = floatval($article->prix_unitaire) * floatval($article->quantite);
|
||||
|
||||
if (!isset($totalsByTva[$tva])) {
|
||||
$totalsByTva[$tva] = 0;
|
||||
}
|
||||
$totalsByTva[$tva] += $totalHT;
|
||||
$total += $article->prix_unitaire * $article->quantite;
|
||||
}
|
||||
|
||||
// Traiter les produits
|
||||
foreach($produits as $key => $produit) {
|
||||
$tva = floatval($produit->tva ?? 20.00);
|
||||
$totalHT = floatval($produit->prix_unitaire) * floatval($produit->quantite);
|
||||
|
||||
if (!isset($totalsByTva[$tva])) {
|
||||
$totalsByTva[$tva] = 0;
|
||||
}
|
||||
$totalsByTva[$tva] += $totalHT;
|
||||
$total += $produit->prix_unitaire * $produit->quantite;
|
||||
}
|
||||
|
||||
// Convertir en tableau de résultats
|
||||
$result = array();
|
||||
$totalGeneral = 0;
|
||||
|
||||
foreach($totalsByTva as $tva => $totalHT) {
|
||||
$result[] = array(
|
||||
'tva' => $tva,
|
||||
'totalHT' => round($totalHT, 2),
|
||||
'totalTVA' => round($totalHT * $tva / 100, 2),
|
||||
'totalTTC' => round($totalHT * (1 + $tva / 100), 2)
|
||||
);
|
||||
$totalGeneral += $totalHT;
|
||||
}
|
||||
|
||||
return array(
|
||||
'details' => $result,
|
||||
'totalGeneral' => round($totalGeneral, 2)
|
||||
);
|
||||
return $total;
|
||||
}
|
||||
|
||||
public function getClients($idNextcloud)
|
||||
@ -924,14 +888,12 @@ class Bdd
|
||||
public function getListProduit($numdevis, $idNextcloud)
|
||||
{
|
||||
$sql = "SELECT ".
|
||||
$this->tableprefix."produit.id as pid,"
|
||||
.$this->tableprefix."produit_devis.id as pdid, reference, description,"
|
||||
.$this->tableprefix."produit_devis.comment, quantite, "
|
||||
.$this->tableprefix."produit_devis.unit_price as prix_unitaire, "
|
||||
.$this->tableprefix."produit_devis.tva, "
|
||||
.$this->tableprefix."devis.id_client
|
||||
FROM ".$this->tableprefix."produit, ".$this->tableprefix."devis, ".$this->tableprefix."produit_devis
|
||||
WHERE ".$this->tableprefix."produit.id = produit_id AND ".$this->tableprefix."devis.id = devis_id AND ".$this->tableprefix."devis.id = ?";
|
||||
$this->tableprefix."produit.id as pid,"
|
||||
.$this->tableprefix."produit_devis.id as pdid, reference, description,"
|
||||
.$this->tableprefix."produit_devis.comment, quantite, prix_unitaire, "
|
||||
.$this->tableprefix."devis.id_client
|
||||
FROM ".$this->tableprefix."produit, ".$this->tableprefix."devis, ".$this->tableprefix."produit_devis
|
||||
WHERE ".$this->tableprefix."produit.id = produit_id AND ".$this->tableprefix."devis.id = devis_id AND ".$this->tableprefix."devis.id = ?";
|
||||
|
||||
$produits = $this->execSQLNoJsonReturn($sql, [$numdevis]);
|
||||
|
||||
@ -940,7 +902,7 @@ class Bdd
|
||||
$client = $this->getClientById($clientId);
|
||||
foreach($produits as &$produit) {
|
||||
$productPrice = $this->getProductPriceByClientGroupId($client['fk_client_group_id'], $produit['pid']);
|
||||
$produit['prix_unitaire'] = $produit['prix_unitaire'] ?? $productPrice;
|
||||
$produit['prix_unitaire'] = $productPrice ?? $produit['prix_unitaire'];
|
||||
}
|
||||
}
|
||||
return json_encode($produits);
|
||||
@ -948,13 +910,7 @@ class Bdd
|
||||
|
||||
public function getListArticle($numdevis, $idNextcloud)
|
||||
{
|
||||
$sql = "SELECT ".$this->tableprefix."article.id as aid,"
|
||||
.$this->tableprefix."article_devis.id as adid, reference, description,"
|
||||
.$this->tableprefix."article_devis.comment, quantite, "
|
||||
.$this->tableprefix."article_devis.unit_price as prix_unitaire, "
|
||||
.$this->tableprefix."article_devis.tva "
|
||||
."FROM "
|
||||
.$this->tableprefix."article, ".$this->tableprefix."devis, ".$this->tableprefix."article_devis WHERE ".$this->tableprefix."article.id = article_id AND ".$this->tableprefix."devis.id = devis_id AND ".$this->tableprefix."devis.id = ?";
|
||||
$sql = "SELECT ".$this->tableprefix."article.id as aid,".$this->tableprefix."article_devis.id as adid, reference, description,".$this->tableprefix."article_devis.comment, quantite, prix_unitaire FROM ".$this->tableprefix."article, ".$this->tableprefix."devis, ".$this->tableprefix."article_devis WHERE ".$this->tableprefix."article.id = article_id AND ".$this->tableprefix."devis.id = devis_id AND ".$this->tableprefix."devis.id = ?";
|
||||
return $this->execSQL($sql, array($numdevis));
|
||||
}
|
||||
|
||||
@ -2659,7 +2615,7 @@ class Bdd
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function getThanatoDevisListByDate($thanatoId, $date)
|
||||
private function getThanatoDevisListByDateSave($thanatoId, $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y-m-d');
|
||||
$sql = "SELECT
|
||||
@ -2700,6 +2656,42 @@ class Bdd
|
||||
return $devisList;
|
||||
}
|
||||
|
||||
private function getThanatoDevisListByDate($thanatoId, $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y-m-d');
|
||||
$sql = "SELECT
|
||||
devis.id,
|
||||
devis.date,
|
||||
devis.mentions,
|
||||
devis.num as calendar_uuid,
|
||||
devis.id_defunt as id_defunt,
|
||||
devis.id_lieu as id_lieu,
|
||||
devis.id_client as id_client,
|
||||
devis.id_thanato as id_thanato,
|
||||
thanato.nom as nom_thanato,
|
||||
thanato.prenom as prenom_thanato,
|
||||
defunt.nom as nom_defunt,
|
||||
lieu.nom as nom_lieu,
|
||||
lieu.latitude as lieu_latitude,
|
||||
lieu.longitude as lieu_longitude,
|
||||
client.nom as nom_client,
|
||||
client.entreprise as client_entreprise,
|
||||
client.adresse as client_adresse
|
||||
FROM ".$this->tableprefix."devis as devis
|
||||
LEFT JOIN ".$this->tableprefix."thanato as thanato on devis.id_thanato = thanato.id
|
||||
LEFT JOIN ".$this->tableprefix."lieu as lieu on devis.id_lieu = lieu.id
|
||||
LEFT JOIN ".$this->tableprefix."defunt as defunt on devis.id_defunt = defunt.id
|
||||
LEFT JOIN ".$this->tableprefix."client as client on devis.id_client = client.id
|
||||
WHERE devis.date = ? AND
|
||||
devis.id_thanato = ?
|
||||
ORDER BY devis.date ASC;";
|
||||
$devisList = $this->execSQLNoJsonReturn(
|
||||
$sql,
|
||||
[$dateFormatted,$thanatoId]
|
||||
);
|
||||
return $devisList;
|
||||
}
|
||||
|
||||
public function getThanatoById($thanatoId)
|
||||
{
|
||||
$sql = "SELECT id, nom, prenom,fk_user_uuid FROM ".$this->tableprefix."thanato WHERE id = ? LIMIT 1;";
|
||||
@ -3119,8 +3111,7 @@ class Bdd
|
||||
produit_devis.quantite,
|
||||
produit_devis.discount,
|
||||
produit_devis.devis_id,
|
||||
produit_devis.tva,
|
||||
produit_devis.unit_price as produit_price,
|
||||
produit.prix_unitaire as produit_price,
|
||||
produit.reference as produit_reference,
|
||||
produit.description as produit_description,
|
||||
produit.fk_product_type_id as fk_product_type_id,
|
||||
@ -3141,7 +3132,7 @@ class Bdd
|
||||
$client = $this->getClientById($clientId);
|
||||
foreach($produitList as &$produit) {
|
||||
$productPrice = $this->getProductPriceByClientGroupId($client['fk_client_group_id'], $produit['produit_id']);
|
||||
$produit['produit_price'] = $produit['produit_price'] ?? $productPrice;
|
||||
$produit['produit_price'] = $productPrice ?? $produit['produit_price'];
|
||||
}
|
||||
}
|
||||
|
||||
@ -3198,7 +3189,7 @@ class Bdd
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getClientFactureStatisticPerMonth($clientId, array $produitList)
|
||||
private function getClientFactureStatisticPerMonthSave($clientId, array $produitList)
|
||||
{
|
||||
$currentYear = date('Y');
|
||||
$monthLists = range(1, 12);
|
||||
@ -3219,12 +3210,11 @@ class Bdd
|
||||
LEFT JOIN ".$this->tableprefix."devis as devis on facture.id_devis = devis.id
|
||||
WHERE YEAR(facture.date_paiement) = ? AND
|
||||
MONTH(facture.date_paiement) = ? AND
|
||||
devis.id_client = ? AND
|
||||
(devis.mentions = ? OR devis.mentions = ?)
|
||||
devis.id_client = ?
|
||||
ORDER BY facture.date_paiement ASC;";
|
||||
$factureList = $this->execSQLNoJsonReturn(
|
||||
$sql,
|
||||
[$currentYear,$monthValue,$clientId,DevisMentionConstant::FACTURED,DevisMentionConstant::FACTURED_FORMATTED]
|
||||
[$currentYear,$monthValue,$clientId]
|
||||
);
|
||||
|
||||
$factureDevisIds = [];
|
||||
@ -3254,6 +3244,58 @@ class Bdd
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function getClientFactureStatisticPerMonth($clientId, array $produitList, $clientGroupId = null)
|
||||
{
|
||||
$currentYear = date('Y');
|
||||
$monthLists = range(1, 12);
|
||||
$data = [] ;
|
||||
foreach($monthLists as $monthValue) {
|
||||
if(!isset($data[$monthValue])) {
|
||||
$data[$monthValue] = [];
|
||||
}
|
||||
$sql = "SELECT
|
||||
devis.id as devis_id,
|
||||
devis.id_client as devis_client_id,
|
||||
devis.date as devis_date,
|
||||
devis.mentions as devis_mention
|
||||
FROM ".$this->tableprefix."devis as devis
|
||||
WHERE YEAR(devis.date) = ? AND
|
||||
MONTH(devis.date) = ? AND
|
||||
devis.id_client = ?
|
||||
ORDER BY devis.date ASC;";
|
||||
$factureList = $this->execSQLNoJsonReturn(
|
||||
$sql,
|
||||
[$currentYear,$monthValue,$clientId]
|
||||
);
|
||||
|
||||
$factureDevisIds = [];
|
||||
foreach($factureList as $facture) {
|
||||
$factureDevisIds[] = $facture['devis_id'];
|
||||
}
|
||||
|
||||
$defuntCount = count($factureList);
|
||||
$produitsPrice = 0;
|
||||
$statisticForeachProductPerMonth = [];
|
||||
foreach($produitList as $produit) {
|
||||
if(!isset($statisticForeachProductPerMonth[$produit['id']])) {
|
||||
$statisticForeachProductPerMonth[$produit['id']] = 0;
|
||||
}
|
||||
$productTotalCount = $this->getDevisProductsQuantityByDevisListAndProductId($factureDevisIds, $produit['id']);
|
||||
$prixUnitaire = is_null($clientGroupId) ? $produit["prix_unitaire"] : $this->getProductPriceByClientGroupId($clientGroupId, $produit['id']);
|
||||
$totalWithoutVat = $productTotalCount * $prixUnitaire;
|
||||
$statisticForeachProductPerMonth[$produit['id']] += $productTotalCount;
|
||||
$produitsPrice += $totalWithoutVat;
|
||||
}
|
||||
$data[$monthValue] = [
|
||||
"defunt_count" => $defuntCount,
|
||||
"total_price" => $produitsPrice,
|
||||
"year" => $currentYear,
|
||||
"products" => $statisticForeachProductPerMonth
|
||||
];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getExportClientStatData(array $clientIds)
|
||||
{
|
||||
$data = [];
|
||||
@ -3267,9 +3309,10 @@ class Bdd
|
||||
$client = $this->getClientById($clientId);
|
||||
if($client != null) {
|
||||
$clientName = trim($client["client_nom"]) . '-' .trim($client['client_entreprise']);
|
||||
$clientGroupId = $client['fk_client_group_id'];
|
||||
}
|
||||
$data[$clientId]["client_name"] = $clientName;
|
||||
$data[$clientId]["client_data"] = $this->getClientFactureStatisticPerMonth($clientId, $produitList);
|
||||
$data[$clientId]["client_data"] = $this->getClientFactureStatisticPerMonth($clientId, $produitList, $clientGroupId);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -74,26 +74,9 @@ class DevisDataProcessor
|
||||
// Variables pour gérer les articles comme dans les factures
|
||||
$produitsReferenceArray = [];
|
||||
|
||||
// ⭐ NOUVEAU: Réinitialiser les montants
|
||||
$devis_temp['montant_htc'] = 0;
|
||||
$devis_temp['montant_tva'] = 0;
|
||||
$devis_temp['montant_ttc'] = 0;
|
||||
|
||||
foreach ($produits as $produit) {
|
||||
$htPrice = $this->getProductPrice($produit, $devis, $filter);
|
||||
$totalHT = $htPrice * $produit->quantite;
|
||||
|
||||
// ⭐ NOUVEAU: Récupérer le taux de TVA spécifique du produit (défaut 20%)
|
||||
$tvaValue = isset($produit->tva) && $produit->tva !== null ? floatval($produit->tva) : 20.00;
|
||||
|
||||
// ⭐ NOUVEAU: Calculer le montant TTC avec le bon taux
|
||||
$totalTTC = $totalHT * (1 + $tvaValue / 100);
|
||||
$totalTVA = $totalTTC - $totalHT;
|
||||
|
||||
// ⭐ NOUVEAU: Additionner les montants
|
||||
$devis_temp['montant_htc'] += $totalHT;
|
||||
$devis_temp['montant_tva'] += $totalTVA;
|
||||
$devis_temp['montant_ttc'] += $totalTTC;
|
||||
$devis_temp['montant_htc'] += $htPrice * $produit->quantite;
|
||||
|
||||
// Collecter les références comme dans les factures
|
||||
if (isset($produit->reference) && !empty($produit->reference)) {
|
||||
@ -102,9 +85,12 @@ class DevisDataProcessor
|
||||
}
|
||||
|
||||
// Traitement identique aux factures
|
||||
$produitsReferenceArray = array_unique($produitsReferenceArray);
|
||||
// $produitsReferenceArray = array_unique($produitsReferenceArray);
|
||||
$produitsReferenceAsString = implode("-", $produitsReferenceArray);
|
||||
$devis_temp['article'] = !empty($produitsReferenceAsString) ? $produitsReferenceAsString : 'SOINS';
|
||||
$devis_temp['article'] = !empty($produitsReferenceAsString) ? $produitsReferenceAsString : '';
|
||||
|
||||
$devis_temp['montant_tva'] = ($devis_temp['montant_htc'] * $devis_temp['tva']) / 100;
|
||||
$devis_temp['montant_ttc'] = $devis_temp['montant_tva'] + $devis_temp['montant_htc'];
|
||||
|
||||
return $devis_temp;
|
||||
}
|
||||
|
||||
@ -81,16 +81,31 @@ class DevisPdfGenerator
|
||||
|
||||
private function calculatePagination($totalItems)
|
||||
{
|
||||
if ($totalItems <= 8) {
|
||||
// Tout sur 1 page
|
||||
return [
|
||||
'nb_pages' => 1,
|
||||
'items_per_page' => 15,
|
||||
'current_index' => 0
|
||||
];
|
||||
}
|
||||
|
||||
// Réserver 8 items pour dernière page
|
||||
$itemsAvantDernierePage = $totalItems - 8;
|
||||
$nbPagesNormales = ceil($itemsAvantDernierePage / 15);
|
||||
|
||||
return [
|
||||
'nb_pages' => ceil($totalItems / 12), // RÉDUIRE à 12 par page
|
||||
'items_per_page' => 12,
|
||||
'nb_pages' => $nbPagesNormales + 1,
|
||||
'items_per_page' => 15,
|
||||
'current_index' => 0
|
||||
];
|
||||
}
|
||||
|
||||
// VOICI LA FONCTION CORRIGÉE - 4 paramètres au lieu de 10
|
||||
private function generateSinglePage(PageContext $context, $num_page, &$pagination, &$totals)
|
||||
{
|
||||
$startIndex = $pagination['current_index'];
|
||||
$remainingItems = count($context->dataDevis) - $startIndex;
|
||||
|
||||
$context->pdf->AddPage();
|
||||
$context->pdf->SetAutoPagebreak(false);
|
||||
$context->pdf->SetMargins(0, 0, 10);
|
||||
@ -100,7 +115,17 @@ class DevisPdfGenerator
|
||||
$this->layoutManager->addClientInfoSection($context->pdf, $context->clientInfo, $context->dataDevis[0]);
|
||||
$this->layoutManager->addDocumentTitle($context->pdf, $context->dataDevis[0], $context->year);
|
||||
|
||||
$itemsToProcess = min($pagination['items_per_page'], count($context->dataDevis) - $pagination['current_index']);
|
||||
// ✅ Calculer items
|
||||
$isLastPage = ($num_page == $pagination['nb_pages']);
|
||||
$hasAmounts = !$context->montant;
|
||||
|
||||
if ($isLastPage && $hasAmounts) {
|
||||
// Dernière page avec totaux : max 8 items
|
||||
$itemsToProcess = min(8, $remainingItems);
|
||||
} else {
|
||||
// Pages normales : 15 items
|
||||
$itemsToProcess = min(15, $remainingItems);
|
||||
}
|
||||
|
||||
$config = [
|
||||
'pagination' => $pagination,
|
||||
@ -111,7 +136,7 @@ class DevisPdfGenerator
|
||||
'sansMontant' => $context->montant
|
||||
];
|
||||
|
||||
$this->tableRenderer->createDevisTable(
|
||||
$finalY = $this->tableRenderer->createDevisTable(
|
||||
$context->pdf,
|
||||
$context->dataDevis,
|
||||
$config
|
||||
|
||||
@ -63,17 +63,18 @@ class DevisPdfLayoutManager
|
||||
);
|
||||
}
|
||||
|
||||
public function addLegalFooter($pdf, $config)
|
||||
public function addLegalFooter($pdf, $config, $tableEndY = 0)
|
||||
{
|
||||
$y0 = 260;
|
||||
$y0 = 280;
|
||||
|
||||
$pageWidth = $pdf->GetPageWidth();
|
||||
|
||||
$pdf->SetFont('Arial', '', 6);
|
||||
$pdf->SetXY(1, $y0 + 4);
|
||||
$pdf->SetXY(1, $y0);
|
||||
$pdf->Cell($pageWidth, 5, mb_convert_encoding(html_entity_decode($config->legal_one), 'ISO-8859-1', 'UTF-8'), 0, 0, 'C');
|
||||
$pdf->SetXY(1, $y0 + 8);
|
||||
$pdf->SetXY(1, $y0 + 4);
|
||||
$pdf->Cell($pageWidth, 5, mb_convert_encoding(html_entity_decode($config->legal_two), 'ISO-8859-1', 'UTF-8'), 0, 0, 'C');
|
||||
$pdf->SetXY(1, $y0 + 12);
|
||||
$pdf->SetXY(1, $y0 + 8);
|
||||
$pdf->Cell($pageWidth, 5, mb_convert_encoding(html_entity_decode($config->telephone), 'ISO-8859-1', 'UTF-8'), 0, 0, 'C');
|
||||
}
|
||||
|
||||
|
||||
@ -13,40 +13,59 @@ class DevisPdfTableRenderer
|
||||
$totals = &$config['totals'];
|
||||
$sansMontant = $config['sansMontant'] ?? false;
|
||||
|
||||
// Système de pagination comme les factures
|
||||
$maxItemsPerPage = 22; // Nombre maximum d'éléments par page
|
||||
$startIndex = $pagination['current_index'];
|
||||
$itemsThisPage = min($itemsToProcess, count($dataDevis) - $startIndex);
|
||||
|
||||
$this->drawTableStructure($pdf, $numPage, $nbPage, $sansMontant);
|
||||
$tableEndY = $this->drawTableStructure($pdf, $numPage, $nbPage, $sansMontant, $itemsThisPage);
|
||||
$this->addTableHeaders($pdf, $sansMontant);
|
||||
$this->populateTableData($pdf, $dataDevis, $startIndex, $itemsThisPage, $totals, $sansMontant);
|
||||
|
||||
// Totaux seulement sur la dernière page
|
||||
if ($numPage == $nbPage && !$sansMontant) {
|
||||
$this->addTableTotals($pdf, $totals);
|
||||
$finalY = $this->addTableTotals($pdf, $totals, $tableEndY);
|
||||
} else {
|
||||
$finalY = $tableEndY;
|
||||
}
|
||||
|
||||
return $finalY;
|
||||
}
|
||||
|
||||
private function drawTableStructure($pdf, $numPage, $nbPage, $sansMontant)
|
||||
private function drawTableStructure($pdf, $numPage, $nbPage, $sansMontant, $itemsOnPage)
|
||||
{
|
||||
$pdf->SetLineWidth(0.2);
|
||||
$pdf->Rect(5, 105, 200, 130, "D");
|
||||
|
||||
$headerHeight = 10;
|
||||
$rowHeight = 10;
|
||||
|
||||
$tableHeight = $headerHeight + ($itemsOnPage * $rowHeight);
|
||||
$endY = 105 + $tableHeight;
|
||||
|
||||
$isLastPage = ($numPage == $nbPage);
|
||||
$hasAmounts = !$sansMontant;
|
||||
|
||||
if ($isLastPage && $hasAmounts) {
|
||||
// Dessiner 3 côtés seulement (haut, gauche, droite)
|
||||
$pdf->Line(5, 105, 205, 105); // Haut
|
||||
$pdf->Line(5, 105, 5, $endY); // Gauche
|
||||
$pdf->Line(205, 105, 205, $endY); // Droite
|
||||
// Pas de ligne du bas - elle sera tracée dans addTableTotals
|
||||
} else {
|
||||
// Dessiner rectangle complet
|
||||
$pdf->Rect(5, 105, 200, $tableHeight, "D");
|
||||
}
|
||||
|
||||
$pdf->Line(5, 115, 205, 115);
|
||||
|
||||
$endY = ($numPage == $nbPage && !$sansMontant) ? 225 : 235;
|
||||
|
||||
if (!$sansMontant) {
|
||||
// Ajout de la colonne Thanatopracteur entre Défunt et H.T.
|
||||
$verticalLines = [24, 41, 58, 77, 102, 127, 147, 167, 178, 189];
|
||||
} else {
|
||||
// Pour sans montant: ajout de Thanatopracteur à la fin
|
||||
$verticalLines = [27, 47, 67, 85, 110, 135, 160];
|
||||
}
|
||||
|
||||
foreach ($verticalLines as $x) {
|
||||
$pdf->Line($x, 105, $x, $endY);
|
||||
}
|
||||
|
||||
return $endY;
|
||||
}
|
||||
|
||||
private function addTableHeaders($pdf, $sansMontant)
|
||||
@ -176,43 +195,44 @@ class DevisPdfTableRenderer
|
||||
}
|
||||
}
|
||||
|
||||
private function addTableTotals($pdf, $totals)
|
||||
private function addTableTotals($pdf, $totals, $tableEndY)
|
||||
{
|
||||
$pdf->Line(5, 225, 205, 225);
|
||||
$totalEndY = $tableEndY + 8;
|
||||
|
||||
$pdf->SetLineWidth(0.2);
|
||||
|
||||
// Juste les lignes horizontales haut et bas
|
||||
$pdf->Line(5, $tableEndY, 205, $tableEndY);
|
||||
$pdf->Line(5, $totalEndY, 205, $totalEndY);
|
||||
|
||||
$pdf->Line(5, $tableEndY, 5, $totalEndY);
|
||||
$pdf->Line(205, $tableEndY, 205, $totalEndY);
|
||||
|
||||
$pdf->SetFont('Arial', 'B', 8);
|
||||
|
||||
// Alignement des totaux avec les colonnes HT, TVA, TTC avec espaces entre les valeurs
|
||||
$pdf->SetXY(5, 225);
|
||||
$pdf->SetXY(5, $tableEndY);
|
||||
$pdf->Cell(162, 8, 'TOTAL', 0, 0, 'C');
|
||||
|
||||
// POSITIONS avec espaces entre les valeurs - plus d'espace entre HT et TVA
|
||||
$pdf->SetXY(167, 225);
|
||||
$pdf->SetXY(167, $tableEndY);
|
||||
$pdf->Cell(9, 8, number_format($totals['ht'], 2, '.', '') . chr(128), 0, 0, 'R');
|
||||
|
||||
$pdf->SetXY(181, 225);
|
||||
$pdf->SetXY(181, $tableEndY);
|
||||
$pdf->Cell(9, 8, number_format($totals['tva'], 2, '.', '') . chr(128), 0, 0, 'R');
|
||||
|
||||
$pdf->SetXY(189, 225);
|
||||
$pdf->SetXY(189, $tableEndY);
|
||||
$pdf->Cell(16, 8, number_format($totals['ttc'], 2, '.', '') . chr(128), 0, 0, 'R');
|
||||
|
||||
// CADRE TOTAL TTC - Cadre encore plus agrandi
|
||||
$pdf->SetXY(170, 241);
|
||||
$cadreY = $totalEndY + 3;
|
||||
|
||||
$pdf->SetXY(170, $cadreY + 1);
|
||||
$pdf->Cell(19, 6, 'TOTAL TTC', 0, 0, 'C');
|
||||
|
||||
$pdf->SetXY(189, 241);
|
||||
$pdf->SetXY(189, $cadreY + 1);
|
||||
$pdf->Cell(16, 6, number_format($totals['ttc'], 2, '.', '') . chr(128), 0, 0, 'C');
|
||||
|
||||
// Cadre TOTAL TTC aligné avec la fin du tableau (205)
|
||||
$lines = [
|
||||
[170, 240, 170, 248], // Ligne verticale gauche (déplacée de 173 à 170 pour agrandir)
|
||||
[189, 240, 189, 248], // Ligne de séparation (alignée avec colonne T.T.C)
|
||||
[205, 240, 205, 248], // Ligne verticale droite (alignée avec fin du tableau)
|
||||
[170, 240, 205, 240], // Ligne horizontale haute
|
||||
[170, 248, 205, 248] // Ligne horizontale basse
|
||||
];
|
||||
$pdf->Rect(170, $cadreY, 35, 8, 'D');
|
||||
$pdf->Line(189, $cadreY, 189, $cadreY + 8);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$pdf->Line($line[0], $line[1], $line[2], $line[3]);
|
||||
}
|
||||
return $cadreY + 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,17 +27,18 @@ declare(strict_types=1);
|
||||
namespace OCA\Gestion\Service\Devis\Pdf;
|
||||
|
||||
use DateTime;
|
||||
use FPDF;
|
||||
use \FPDF;
|
||||
use OCA\Gestion\Helpers\FileExportHelpers;
|
||||
use OCA\Gestion\Helpers\PriceHelpers;
|
||||
|
||||
class DevisPdfHandler extends FPDF
|
||||
{
|
||||
|
||||
private $multipleDevisData = [];
|
||||
private $devisData = [];
|
||||
private $logo = null;
|
||||
private $logoPath = "/var/www/html/data/admin/files/.gestion/";
|
||||
public function Header()
|
||||
function Header()
|
||||
{
|
||||
if ($this->logo != "nothing") {
|
||||
$this->Image($this->logoPath . "logo.png", 4, 2, 36, 37);
|
||||
@ -45,7 +46,7 @@ class DevisPdfHandler extends FPDF
|
||||
$this->Cell(55, 30, '');
|
||||
}
|
||||
}
|
||||
public function Footer()
|
||||
function Footer()
|
||||
{
|
||||
$this->SetY(-40);
|
||||
$this->SetFont('Arial', '', 7);
|
||||
@ -117,6 +118,7 @@ class DevisPdfHandler extends FPDF
|
||||
|
||||
private function DrawArticlesTableHeader()
|
||||
{
|
||||
$tvaValue = $this->devisData["configuration"]->tva_default;
|
||||
$this->SetFont('Arial', '', 10);
|
||||
$this->SetXY(10, 106);
|
||||
$this->Cell(20, 8, "Date", 0, 0, 'C');
|
||||
@ -128,109 +130,56 @@ class DevisPdfHandler extends FPDF
|
||||
$this->Cell(20, 8, "Prix Uni. HT", 0, 0, 'C');
|
||||
|
||||
$this->SetXY(155, 106);
|
||||
$this->Cell(20, 8, 'TVA', 0, 0, 'C');
|
||||
$this->Cell(20, 8, 'TVA ' . $tvaValue . '%', 0, 0, 'C');
|
||||
|
||||
$this->SetXY(175, 106);
|
||||
$this->Cell(25, 8, "Prix Uni. TTC", 0, 0, 'C');
|
||||
|
||||
}
|
||||
|
||||
public function DrawArticlesTableValueAndReturnTotalPrice()
|
||||
{
|
||||
$this->SetFont('Arial', '', 10);
|
||||
|
||||
// Grouper les totaux par taux de TVA
|
||||
$totalsByTva = [];
|
||||
$tvaValue = $this->devisData["configuration"]->tva_default;
|
||||
$totalHt = 0;
|
||||
$totalTtc = 0;
|
||||
$totalTva = 0;
|
||||
$products = $this->devisData["products"];
|
||||
$yValue = 116;
|
||||
|
||||
foreach ($products as $product) {
|
||||
// Récupérer le taux de TVA du produit (défaut à 20% si non défini)
|
||||
$tvaValue = isset($product['tva']) ? floatval($product['tva']) : 20.00;
|
||||
|
||||
$valueHt = $product['produit_price'] * $product['quantite'];
|
||||
$valueTtc = PriceHelpers::calculPriceWithVatValue($valueHt, $tvaValue);
|
||||
$tvaAmount = $valueTtc - $valueHt;
|
||||
|
||||
// Grouper par taux de TVA
|
||||
if (!isset($totalsByTva[$tvaValue])) {
|
||||
$totalsByTva[$tvaValue] = [
|
||||
'totalHT' => 0,
|
||||
'totalTVA' => 0,
|
||||
'totalTTC' => 0
|
||||
];
|
||||
}
|
||||
|
||||
$totalsByTva[$tvaValue]['totalHT'] += $valueHt;
|
||||
$totalsByTva[$tvaValue]['totalTVA'] += $tvaAmount;
|
||||
$totalsByTva[$tvaValue]['totalTTC'] += $valueTtc;
|
||||
|
||||
// Affichage du produit
|
||||
$totalHt += $valueHt;
|
||||
$totalTtc += $valueTtc;
|
||||
$productDescription = $product["produit_description"];
|
||||
$dateValue = "";
|
||||
if ($product === end($products)) {
|
||||
$dateValue = $this->devisData['devis_date'];
|
||||
$productDescription .= " de " . FileExportHelpers::GetSexeLabel($this->devisData['defunt_sexe']) . ' ' . $this->devisData["defunt_nom"];
|
||||
}
|
||||
|
||||
$tvaAmount = $valueTtc - $valueHt;
|
||||
$this->SetXY(10, $yValue);
|
||||
$this->Cell(20, 6, $dateValue, 0, 0);
|
||||
|
||||
$this->SetXY(35, $yValue);
|
||||
$this->MultiAlignCell(100, 6, utf8_decode(html_entity_decode($productDescription)), 0, '0');
|
||||
$this->MultiAlignCell(100, 6, utf8_decode(html_entity_decode($productDescription)), 0, '0', );
|
||||
|
||||
$this->SetXY(135, $yValue);
|
||||
$this->Cell(20, 6, number_format($valueHt, 2, '.', '') . chr(128), 0, 0, 'C');
|
||||
|
||||
$this->SetXY(155, $yValue);
|
||||
$this->Cell(20, 6, $tvaValue . '%', 0, 0, 'C');
|
||||
$this->Cell(20, 6, number_format($tvaAmount, 2, '.', '') . chr(128), 0, 0, 'C');
|
||||
|
||||
$this->SetXY(175, $yValue);
|
||||
$this->Cell(25, 6, number_format($valueTtc, 2, '.', '') . chr(128), 0, 1, 'C');
|
||||
$yValue += 12;
|
||||
$totalTva += $tvaAmount;
|
||||
}
|
||||
|
||||
// Trier par taux de TVA
|
||||
ksort($totalsByTva);
|
||||
|
||||
// ⭐ NOUVEAU: Ajouter les lignes de totaux par TVA DANS le tableau
|
||||
$this->SetFont('Arial', 'B', 10);
|
||||
|
||||
// Ligne de séparation avant les totaux
|
||||
$this->Line(10, $yValue - 2, 200, $yValue - 2);
|
||||
$yValue += 2;
|
||||
|
||||
foreach ($totalsByTva as $tva => $totals) {
|
||||
$this->SetXY(35, $yValue);
|
||||
$this->Cell(100, 6, 'Total TVA ' . number_format($tva, 0) . '%', 0, 0, 'L');
|
||||
|
||||
$this->SetXY(135, $yValue);
|
||||
$this->Cell(20, 6, number_format($totals['totalHT'], 2, '.', '') . chr(128), 0, 0, 'C');
|
||||
|
||||
$this->SetXY(155, $yValue);
|
||||
$this->Cell(20, 6, number_format($totals['totalTVA'], 2, '.', '') . chr(128), 0, 0, 'C');
|
||||
|
||||
$this->SetXY(175, $yValue);
|
||||
$this->Cell(25, 6, number_format($totals['totalTTC'], 2, '.', '') . chr(128), 0, 0, 'C');
|
||||
|
||||
$yValue += 8;
|
||||
}
|
||||
|
||||
// Calculer les totaux généraux pour le cadre en bas à droite
|
||||
$totalGeneralHT = 0;
|
||||
$totalGeneralTVA = 0;
|
||||
$totalGeneralTTC = 0;
|
||||
|
||||
foreach ($totalsByTva as $totals) {
|
||||
$totalGeneralHT += $totals['totalHT'];
|
||||
$totalGeneralTVA += $totals['totalTVA'];
|
||||
$totalGeneralTTC += $totals['totalTTC'];
|
||||
}
|
||||
|
||||
// Retourner uniquement les totaux généraux
|
||||
return [
|
||||
'totalHT' => $totalGeneralHT,
|
||||
'totalTVA' => $totalGeneralTVA,
|
||||
'totalTTC' => $totalGeneralTTC
|
||||
"TOTAL HT" => $totalHt,
|
||||
"TVA " . $tvaValue . "%" => $totalTva,
|
||||
"TOTAL TTC" => $totalTtc
|
||||
];
|
||||
}
|
||||
|
||||
@ -251,27 +200,17 @@ class DevisPdfHandler extends FPDF
|
||||
$ibanCursorX = $this->GetX();
|
||||
$this->Cell($ibanWidth, 7, 'Code SWIFT : AGRI FR PP 836', 1, 1, 'C');
|
||||
|
||||
//TABLE DES TOTAUX GÉNÉRAUX UNIQUEMENT (3 lignes)
|
||||
//TABLE HT
|
||||
$ibanLastPositionX = $ibanCursorX + $ibanWidth + 20;
|
||||
$startOfArrayX = $ibanLastPositionX;
|
||||
$startOfArrayY = $ibanCursorY;
|
||||
|
||||
// Afficher les 3 totaux généraux
|
||||
$this->SetFont('Arial', 'B', 11);
|
||||
|
||||
$this->SetXY($startOfArrayX, $startOfArrayY);
|
||||
$this->Cell(40, 7, 'TOTAL HT', 1, 0, 'C');
|
||||
$this->Cell(40, 7, number_format($totalPriceArray['totalHT'], 2, '.', '') . chr(128), 1, 1, 'C');
|
||||
$startOfArrayY += 7;
|
||||
|
||||
$this->SetXY($startOfArrayX, $startOfArrayY);
|
||||
$this->Cell(40, 7, 'TOTAL TVA', 1, 0, 'C');
|
||||
$this->Cell(40, 7, number_format($totalPriceArray['totalTVA'], 2, '.', '') . chr(128), 1, 1, 'C');
|
||||
$startOfArrayY += 7;
|
||||
|
||||
$this->SetXY($startOfArrayX, $startOfArrayY);
|
||||
$this->Cell(40, 7, 'TOTAL TTC', 1, 0, 'C');
|
||||
$this->Cell(40, 7, number_format($totalPriceArray['totalTTC'], 2, '.', '') . chr(128), 1, 1, 'C');
|
||||
foreach ($totalPriceArray as $label => $price) {
|
||||
$this->SetXY($startOfArrayX, $startOfArrayY);
|
||||
$this->Cell(40, 7, $label, 1, 1, 'C');
|
||||
$this->SetXY($startOfArrayX + 40, $startOfArrayY);
|
||||
$this->Cell(40, 7, number_format($price, 2, '.', '') . chr(128), 1, 1, 'C');
|
||||
$startOfArrayY += 7;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetMultipleDevisContent()
|
||||
@ -294,7 +233,7 @@ class DevisPdfHandler extends FPDF
|
||||
$this->DrawBankAndTotalPriceInfo($totalPriceValue);
|
||||
}
|
||||
|
||||
public function MultiAlignCell($w, $h, $text, $border = 0, $ln = 0, $align = 'L', $fill = false)
|
||||
function MultiAlignCell($w, $h, $text, $border = 0, $ln = 0, $align = 'L', $fill = false)
|
||||
{
|
||||
// Store reset values for (x,y) positions
|
||||
$x = $this->GetX() + $w;
|
||||
@ -309,22 +248,19 @@ class DevisPdfHandler extends FPDF
|
||||
}
|
||||
}
|
||||
|
||||
public function NbLines($w, $txt)
|
||||
function NbLines($w, $txt)
|
||||
{
|
||||
// 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');
|
||||
}
|
||||
$cw = $this->CurrentFont['cw'];
|
||||
if ($w == 0) {
|
||||
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") {
|
||||
if ($nb > 0 && $s[$nb - 1] == "\n")
|
||||
$nb--;
|
||||
}
|
||||
$sep = -1;
|
||||
$i = 0;
|
||||
$j = 0;
|
||||
@ -340,25 +276,21 @@ class DevisPdfHandler extends FPDF
|
||||
$nl++;
|
||||
continue;
|
||||
}
|
||||
if ($c == ' ') {
|
||||
if ($c == ' ')
|
||||
$sep = $i;
|
||||
}
|
||||
$l += $cw[$c];
|
||||
if ($l > $wmax) {
|
||||
if ($sep == -1) {
|
||||
if ($i == $j) {
|
||||
if ($i == $j)
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
$i = $sep + 1;
|
||||
}
|
||||
$sep = -1;
|
||||
$j = $i;
|
||||
$l = 0;
|
||||
$nl++;
|
||||
} else {
|
||||
} else
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
return $nl;
|
||||
}
|
||||
|
||||
@ -30,94 +30,102 @@ use OCA\Gestion\Db\Bdd;
|
||||
use OCA\Gestion\Helpers\FileExportHelpers;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class ExportClientStatisticService {
|
||||
/** @var Bdd */
|
||||
private $gestionBdd;
|
||||
class ExportClientStatisticService
|
||||
{
|
||||
/** @var Bdd */
|
||||
private $gestionBdd;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
public function __construct(
|
||||
Bdd $gestionBdd,
|
||||
LoggerInterface $logger) {
|
||||
$this->logger = $logger;
|
||||
$this->gestionBdd = $gestionBdd;
|
||||
}
|
||||
public function __construct(
|
||||
Bdd $gestionBdd,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->gestionBdd = $gestionBdd;
|
||||
}
|
||||
|
||||
public function getFileName(array $clientIds){
|
||||
public function getFileName(array $clientIds)
|
||||
{
|
||||
$filename = "";
|
||||
$clients = $this->gestionBdd->getClientsByClientsID($clientIds);
|
||||
foreach($clients as $client){
|
||||
foreach($clients as $client) {
|
||||
$filename .= $client['client_nom'] . '-' . $client['client_entreprise'] . '--';
|
||||
}
|
||||
$filename = rtrim($filename, '-');
|
||||
$filename = str_replace(' ','-', $filename);
|
||||
$filename = str_replace(' ','-', $filename);
|
||||
$filename = str_replace(' ', '-', $filename);
|
||||
$filename = str_replace(' ', '-', $filename);
|
||||
return $filename;
|
||||
}
|
||||
|
||||
public function getExportClientFileHeader(): string{
|
||||
$fileHeader =
|
||||
'CLIENT'.';'.
|
||||
public function getExportClientFileHeader(): string
|
||||
{
|
||||
$fileHeader =
|
||||
'CLIENT'.';'.
|
||||
'MOIS'.';'.
|
||||
'ANNEE'.';'.
|
||||
'NB DE DEFUNTS'.';';
|
||||
'NB DE DEFUNTS'.';';
|
||||
|
||||
$produitList = $this->gestionBdd->getProduitsListAsArray();
|
||||
foreach($produitList as $produit){
|
||||
$fileHeader .= FileExportHelpers::FormatTextForExport($produit['reference']).';';
|
||||
}
|
||||
$fileHeader .= 'TOTAL HT'.';'."\n";
|
||||
return $fileHeader;
|
||||
}
|
||||
$produitList = $this->gestionBdd->getProduitsListAsArray();
|
||||
foreach($produitList as $produit) {
|
||||
$fileHeader .= FileExportHelpers::FormatTextForExport($produit['reference']).';';
|
||||
}
|
||||
$fileHeader .= 'TOTAL HT'.';'."\n";
|
||||
return $fileHeader;
|
||||
}
|
||||
|
||||
public function populateExportDataIntoFileContent(array $exportData,string $fileContent): string{
|
||||
foreach($exportData as $clientId => $clientData){
|
||||
$clientName = $clientData["client_name"];
|
||||
$clientStatPerMonth = $clientData["client_data"];
|
||||
$totalPrice = 0;
|
||||
if(!empty($clientStatPerMonth)){
|
||||
foreach($clientStatPerMonth as $month => $stat){
|
||||
$stat["client_name"] = $clientName;
|
||||
$totalPrice+=$stat["total_price"];
|
||||
$fileContent = $this->populateClientStatDataIntoFileContent($fileContent,$month,$stat);
|
||||
}
|
||||
$fileContent = $this->populateTotalPriceIntoFileContent($fileContent,$totalPrice,count($stat["products"]));
|
||||
}
|
||||
}
|
||||
return $fileContent;
|
||||
}
|
||||
public function populateExportDataIntoFileContent(array $exportData, string $fileContent): string
|
||||
{
|
||||
foreach($exportData as $clientId => $clientData) {
|
||||
$clientName = $clientData["client_name"];
|
||||
$clientStatPerMonth = $clientData["client_data"];
|
||||
$totalPrice = 0;
|
||||
if(!empty($clientStatPerMonth)) {
|
||||
foreach($clientStatPerMonth as $month => $stat) {
|
||||
$stat["client_name"] = $clientName;
|
||||
$totalPrice += $stat["total_price"];
|
||||
$fileContent = $this->populateClientStatDataIntoFileContent($fileContent, $month, $stat);
|
||||
}
|
||||
$fileContent = $this->populateTotalPriceIntoFileContent($fileContent, $totalPrice, count($stat["products"]));
|
||||
}
|
||||
}
|
||||
return $fileContent;
|
||||
}
|
||||
|
||||
private function populateTotalPriceIntoFileContent(string $fileContent,$totalPrice,$productsCount){
|
||||
$fileContent = $fileContent.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';';
|
||||
while($productsCount > 0){
|
||||
$fileContent .= ''.';';
|
||||
$productsCount--;
|
||||
}
|
||||
$fileContent .= "$totalPrice".";"."\n";
|
||||
return $fileContent;
|
||||
}
|
||||
private function populateTotalPriceIntoFileContent(string $fileContent, $totalPrice, $productsCount)
|
||||
{
|
||||
$fileContent = $fileContent.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';';
|
||||
while($productsCount > 0) {
|
||||
$fileContent .= ''.';';
|
||||
$productsCount--;
|
||||
}
|
||||
$fileContent .= "$totalPrice".";"."\n";
|
||||
return $fileContent;
|
||||
}
|
||||
|
||||
private function populateClientStatDataIntoFileContent(string $fileContent,$month,array $statPerMonth){
|
||||
$yearValue = $statPerMonth["year"];
|
||||
$defuntCount = $statPerMonth["defunt_count"];
|
||||
$products = $statPerMonth["products"];
|
||||
|
||||
$fileContent = $fileContent.
|
||||
FileExportHelpers::FormatTextForExport($statPerMonth['client_name']).';'.
|
||||
"$month".';'.
|
||||
"$yearValue".';'.
|
||||
"$defuntCount".';';
|
||||
private function populateClientStatDataIntoFileContent(string $fileContent, $month, array $statPerMonth)
|
||||
{
|
||||
$yearValue = $statPerMonth["year"];
|
||||
$defuntCount = $statPerMonth["defunt_count"];
|
||||
$products = $statPerMonth["products"];
|
||||
$priceTotal = $statPerMonth["total_price"];
|
||||
|
||||
foreach($products as $productCount){
|
||||
$fileContent .= "$productCount".";";
|
||||
}
|
||||
$fileContent .= "\n";
|
||||
return $fileContent;
|
||||
$fileContent = $fileContent.
|
||||
FileExportHelpers::FormatTextForExport($statPerMonth['client_name']).';'.
|
||||
"$month".';'.
|
||||
"$yearValue".';'.
|
||||
"$defuntCount".';';
|
||||
|
||||
}
|
||||
foreach($products as $productCount) {
|
||||
$fileContent .= "$productCount".";";
|
||||
}
|
||||
$fileContent .= "$priceTotal".';'."\n";
|
||||
return $fileContent;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,149 +34,158 @@ use OCA\Gestion\Constants\BddConstant;
|
||||
use OCA\Gestion\Helpers\FileExportHelpers;
|
||||
use OCA\Gestion\Constants\AbsenceTypeConstant;
|
||||
|
||||
class ExportThanatoStatisticService {
|
||||
/** @var Bdd */
|
||||
private $gestionBdd;
|
||||
class ExportThanatoStatisticService
|
||||
{
|
||||
/** @var Bdd */
|
||||
private $gestionBdd;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
/** @var IRootFolder */
|
||||
private $rootFolder;
|
||||
/** @var IRootFolder */
|
||||
private $rootFolder;
|
||||
|
||||
private $geoService;
|
||||
private $geoService;
|
||||
|
||||
public function __construct(
|
||||
Bdd $gestionBdd,
|
||||
LoggerInterface $logger,
|
||||
IRootFolder $rootFolder,
|
||||
GeoService $geoService) {
|
||||
$this->geoService = $geoService;
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->logger = $logger;
|
||||
$this->gestionBdd = $gestionBdd;
|
||||
}
|
||||
public function __construct(
|
||||
Bdd $gestionBdd,
|
||||
LoggerInterface $logger,
|
||||
IRootFolder $rootFolder,
|
||||
GeoService $geoService
|
||||
) {
|
||||
$this->geoService = $geoService;
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->logger = $logger;
|
||||
$this->gestionBdd = $gestionBdd;
|
||||
}
|
||||
|
||||
private function getFilename($thanatoName,$thanatoLastName,$month,$year){
|
||||
$filename = "$year-$month-";
|
||||
$filename .= $thanatoName . '-' . $thanatoLastName;
|
||||
$filename = str_replace(' ','-', $filename);
|
||||
$filename = str_replace(' ','-', $filename);
|
||||
private function getFilename($thanatoName, $thanatoLastName, $month, $year)
|
||||
{
|
||||
$filename = "$year-$month-";
|
||||
$filename .= $thanatoName . '-' . $thanatoLastName;
|
||||
$filename = str_replace(' ', '-', $filename);
|
||||
$filename = str_replace(' ', '-', $filename);
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
private function exportThanatoStatistic($thanatoId,$month,$year,$idNextcloud){
|
||||
$thanato = $this->gestionBdd->getThanatoById($thanatoId);
|
||||
if($thanato == null){
|
||||
return null;
|
||||
}
|
||||
$exportData = $this->gestionBdd->getExportThanatoStatisticData($thanatoId,$month,$year);
|
||||
if(empty($exportData)){
|
||||
return null;
|
||||
}
|
||||
$defaultConfig = json_decode($this->gestionBdd->getConfiguration(BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD));
|
||||
$racineFolder = html_entity_decode($defaultConfig[0]->path).'/';
|
||||
$thanatoFolder = $racineFolder.'STATISTIQUES/THANATOS/';
|
||||
$fileHeader = $this->getExportThanatoFileHeader();
|
||||
$fileContent = $this->populateExportDataIntoFileContent($exportData,$fileHeader);
|
||||
$storage = $this->rootFolder->getUserFolder($idNextcloud);
|
||||
try{
|
||||
$storage->newFolder($thanatoFolder);
|
||||
}
|
||||
catch(\OCP\Files\NotPermittedException $e) {
|
||||
|
||||
}
|
||||
$filename = $this->getFilename($thanato["nom"],$thanato["prenom"],$month,$year);
|
||||
$fileNamePath = $thanatoFolder."STAT-THANATO-" . $filename . '.csv';
|
||||
$storage->newFile($fileNamePath);
|
||||
$file = $storage->get($fileNamePath);
|
||||
$file->putContent($fileContent);
|
||||
return $fileNamePath;
|
||||
}
|
||||
private function exportThanatoStatistic($thanatoId, $month, $year, $idNextcloud)
|
||||
{
|
||||
$thanato = $this->gestionBdd->getThanatoById($thanatoId);
|
||||
if($thanato == null) {
|
||||
return null;
|
||||
}
|
||||
$exportData = $this->gestionBdd->getExportThanatoStatisticData($thanatoId, $month, $year);
|
||||
if(empty($exportData)) {
|
||||
return null;
|
||||
}
|
||||
$defaultConfig = json_decode($this->gestionBdd->getConfiguration(BddConstant::DEFAULT_ADMIN_ID_NEXTCLOUD));
|
||||
$racineFolder = html_entity_decode($defaultConfig[0]->path).'/';
|
||||
$thanatoFolder = $racineFolder.'STATISTIQUES/THANATOS/';
|
||||
$fileHeader = $this->getExportThanatoFileHeader();
|
||||
$fileContent = $this->populateExportDataIntoFileContent($exportData, $fileHeader);
|
||||
$storage = $this->rootFolder->getUserFolder($idNextcloud);
|
||||
try {
|
||||
$storage->newFolder($thanatoFolder);
|
||||
} catch(\OCP\Files\NotPermittedException $e) {
|
||||
|
||||
public function exportThanatosListStatistic(array $thanatoIds,$month,$year,$idNextcloud){
|
||||
$filenames = [];
|
||||
foreach($thanatoIds as $thanatoId){
|
||||
$filename = $this->exportThanatoStatistic($thanatoId,$month,$year,$idNextcloud);
|
||||
if($filename != null){
|
||||
$filenames[] = $filename;
|
||||
}
|
||||
}
|
||||
return $filenames;
|
||||
}
|
||||
}
|
||||
$filename = $this->getFilename($thanato["nom"], $thanato["prenom"], $month, $year);
|
||||
$fileNamePath = $thanatoFolder."STAT-THANATO-" . $filename . '.csv';
|
||||
$storage->newFile($fileNamePath);
|
||||
$file = $storage->get($fileNamePath);
|
||||
$file->putContent($fileContent);
|
||||
return $fileNamePath;
|
||||
}
|
||||
|
||||
public function getExportThanatoFileHeader(): string{
|
||||
$fileHeader =
|
||||
'FACTURE'.';'.
|
||||
'THANATOPRACTEUR'.';'.
|
||||
'DATE'.';'.
|
||||
'HEURE DE DEBUT'.';'.
|
||||
'HEURE DE FIN'.';'.
|
||||
'SOINS'.';'.
|
||||
'JOUR/FERIE'.';'.
|
||||
'CONGE'.';'.
|
||||
'REPOS'.';'.
|
||||
'MALADIE'.';'.
|
||||
'NOM ET PRENOM'.';'.
|
||||
'LIEU'.';'.
|
||||
'POMPES FUNEBRES'.';'.
|
||||
'ADRESSE'.';'.
|
||||
'DISTANCE TOTALE KM'.';'.
|
||||
'HEURES TOTAL DE SOIN'.';'.
|
||||
'HEURES TOTAL DE CONGE'.';'.
|
||||
'HEURES TOTAL DE REPOS'.';'.
|
||||
'HEURES TOTAL DE MALADIE'.';'.
|
||||
'HEURES TOTAL DE TRAVAIL'.';'.
|
||||
'HEURES TOTAL DE PARCOURS ENTRE DEVIS'.';'.
|
||||
'NOMBRE DE SOINS ET TOILETTES'.';'.
|
||||
"\n";
|
||||
return $fileHeader;
|
||||
}
|
||||
public function exportThanatosListStatistic(array $thanatoIds, $month, $year, $idNextcloud)
|
||||
{
|
||||
$filenames = [];
|
||||
foreach($thanatoIds as $thanatoId) {
|
||||
$filename = $this->exportThanatoStatistic($thanatoId, $month, $year, $idNextcloud);
|
||||
if($filename != null) {
|
||||
$filenames[] = $filename;
|
||||
}
|
||||
}
|
||||
return $filenames;
|
||||
}
|
||||
|
||||
private function populateNoDevisDataInADay(string $fileContent,$leave){
|
||||
$startTimeValue = "";
|
||||
$endTimeValue = "";
|
||||
$leaveValue = "Non";
|
||||
if($leave["onLeave"]){
|
||||
$startTimeValue = $leave["startTime"];
|
||||
$endTimeValue = $leave["endTime"];
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE){
|
||||
$leaveValue = "Oui";
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE){
|
||||
$diseaseValue = "Oui";
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST){
|
||||
$restValue = "Oui";
|
||||
}
|
||||
}
|
||||
$fileContent = $fileContent.
|
||||
''.';'.
|
||||
FileExportHelpers::FormatTextForExport($leave['thanatoName']).';'.
|
||||
$leave['date'].';'.
|
||||
$startTimeValue.';'.
|
||||
$endTimeValue.';'.
|
||||
''.';'.
|
||||
DateHelpers::getPublicHolidayText($leave['isPublicHoliday']).';'.
|
||||
$leaveValue.';'.
|
||||
$restValue.';'.
|
||||
$diseaseValue.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'."\n";
|
||||
return $fileContent;
|
||||
}
|
||||
public function getExportThanatoFileHeader(): string
|
||||
{
|
||||
$fileHeader =
|
||||
'DEVIS'.';'.
|
||||
'THANATOPRACTEUR'.';'.
|
||||
'DATE'.';'.
|
||||
'HEURE DE DEBUT'.';'.
|
||||
'HEURE DE FIN'.';'.
|
||||
'SOINS'.';'.
|
||||
'JOUR/FERIE'.';'.
|
||||
'CONGE'.';'.
|
||||
'REPOS'.';'.
|
||||
'MALADIE'.';'.
|
||||
'NOM ET PRENOM'.';'.
|
||||
'LIEU'.';'.
|
||||
'POMPES FUNEBRES'.';'.
|
||||
'ADRESSE'.';'.
|
||||
'DISTANCE TOTALE KM'.';'.
|
||||
'HEURES TOTAL DE SOIN'.';'.
|
||||
'HEURES TOTAL DE CONGE'.';'.
|
||||
'HEURES TOTAL DE REPOS'.';'.
|
||||
'HEURES TOTAL DE MALADIE'.';'.
|
||||
'HEURES TOTAL DE TRAVAIL'.';'.
|
||||
'HEURES TOTAL DE PARCOURS ENTRE DEVIS'.';'.
|
||||
'NOMBRE DE SOINS ET TOILETTES'.';'.
|
||||
"\n";
|
||||
return $fileHeader;
|
||||
}
|
||||
|
||||
public function populateExportDataIntoFileContent(array $exportData,string $fileContent): string{
|
||||
private function populateNoDevisDataInADay(string $fileContent, $leave)
|
||||
{
|
||||
$startTimeValue = "";
|
||||
$endTimeValue = "";
|
||||
$leaveValue = "Non";
|
||||
$restValue = "Non"; // AJOUTER CETTE LIGNE
|
||||
$diseaseValue = "Non"; // AJOUTER CETTE LIGNE
|
||||
if($leave["onLeave"]) {
|
||||
$startTimeValue = $leave["startTime"];
|
||||
$endTimeValue = $leave["endTime"];
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE) {
|
||||
$leaveValue = "Oui";
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE) {
|
||||
$diseaseValue = "Oui";
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST) {
|
||||
$restValue = "Oui";
|
||||
}
|
||||
}
|
||||
$fileContent = $fileContent.
|
||||
''.';'.
|
||||
FileExportHelpers::FormatTextForExport($leave['thanatoName']).';'.
|
||||
$leave['date'].';'.
|
||||
$startTimeValue.';'.
|
||||
$endTimeValue.';'.
|
||||
''.';'.
|
||||
DateHelpers::getPublicHolidayText($leave['isPublicHoliday']).';'.
|
||||
$leaveValue.';'.
|
||||
$restValue.';'.
|
||||
$diseaseValue.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'."\n";
|
||||
return $fileContent;
|
||||
}
|
||||
|
||||
public function populateExportDataIntoFileContent(array $exportData, string $fileContent): string
|
||||
{
|
||||
|
||||
$g_totalDistance = 0;
|
||||
$g_totalDevisHours = 0;
|
||||
@ -185,81 +194,81 @@ class ExportThanatoStatisticService {
|
||||
$g_totalTravelingHoursBetweenDevisLocation = 0;
|
||||
$g_totalDiseaseHours = 0;
|
||||
$g_totalRestHours = 0;
|
||||
$g_totalDevisCount = 0;
|
||||
$g_totalDevisCount = 0;
|
||||
|
||||
foreach($exportData as $devisDate => $devisData){
|
||||
$totalDevisHours = 0;
|
||||
$totalWorkedHours = 8;
|
||||
$totalLeaveHours = 0;
|
||||
$totalDiseaseHours = 0;
|
||||
$totalRestHours = 0;
|
||||
$totalDistance = 0;
|
||||
$totalDevisCount = 0;
|
||||
$totalTravelingHoursBetweenDevisLocation = 0;
|
||||
$hasDevisInTheCurrentDate = $devisData['hasDevis'];
|
||||
if($hasDevisInTheCurrentDate === false){
|
||||
$leaves = $devisData["leaves"];
|
||||
foreach($leaves as $leave){
|
||||
$fileContent = $this->populateNoDevisDataInADay($fileContent,$leave);
|
||||
if($leave["onLeave"]){
|
||||
$totalLeaveHoursInsideWorkingHours = $leave["totalWorkedHours"];
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE ){
|
||||
$totalLeaveHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST){
|
||||
$totalRestHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE){
|
||||
$totalDiseaseHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
}
|
||||
}
|
||||
$totalAbsenceHours = $totalLeaveHours + $totalRestHours + $totalDiseaseHours;
|
||||
$totalWorkedHours -= $totalAbsenceHours;
|
||||
}
|
||||
else{
|
||||
$totalDevisCount += count($devisData["devisId"]);
|
||||
$routeLines = $this->gestionBdd->getRouteLinesByDevisIdList($devisData["devisId"]);
|
||||
$totalDistanceAndTotalTravelingHoursBetweenDevis = $this->geoService->getTotalDistanceAndTotalTravelingHoursBetweenDevisLocationByRouteLines($routeLines);
|
||||
$totalDistance = $totalDistanceAndTotalTravelingHoursBetweenDevis["totalDistance"];
|
||||
$totalTravelingHoursBetweenDevisLocation = $totalDistanceAndTotalTravelingHoursBetweenDevis["totalTravelingHours"];
|
||||
$devisList = $devisData["devis"];
|
||||
$leaves = $devisData["leaves"];
|
||||
if(!empty($devisList)){
|
||||
foreach($devisList as $devis){
|
||||
$fileContent = $this->populateDevisDataIntoThanatoExportFileContent($fileContent,$devis);
|
||||
$totalDevisHours += $devis["totalHours"];
|
||||
}
|
||||
}
|
||||
foreach($leaves as $leave){
|
||||
$fileContent = $this->populateNoDevisDataInADay($fileContent,$leave);
|
||||
if($leave["onLeave"]){
|
||||
$totalLeaveHoursInsideWorkingHours = $leave["totalWorkedHours"];
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE){
|
||||
$totalLeaveHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST){
|
||||
$totalRestHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE){
|
||||
$totalDiseaseHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
}
|
||||
}
|
||||
$totalAbsenceHours = $totalLeaveHours + $totalRestHours + $totalDiseaseHours;
|
||||
$totalWorkedHours -= $totalAbsenceHours;
|
||||
}
|
||||
foreach($exportData as $devisDate => $devisData) {
|
||||
$totalDevisHours = 0;
|
||||
$totalWorkedHours = 8;
|
||||
$totalLeaveHours = 0;
|
||||
$totalDiseaseHours = 0;
|
||||
$totalRestHours = 0;
|
||||
$totalDistance = 0;
|
||||
$totalDevisCount = 0;
|
||||
$totalTravelingHoursBetweenDevisLocation = 0;
|
||||
$hasDevisInTheCurrentDate = $devisData['hasDevis'];
|
||||
if($hasDevisInTheCurrentDate === false) {
|
||||
$leaves = $devisData["leaves"];
|
||||
foreach($leaves as $leave) {
|
||||
$fileContent = $this->populateNoDevisDataInADay($fileContent, $leave);
|
||||
if($leave["onLeave"]) {
|
||||
$totalLeaveHoursInsideWorkingHours = $leave["totalWorkedHours"];
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE) {
|
||||
$totalLeaveHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST) {
|
||||
$totalRestHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE) {
|
||||
$totalDiseaseHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
}
|
||||
}
|
||||
$totalAbsenceHours = $totalLeaveHours + $totalRestHours + $totalDiseaseHours;
|
||||
$totalWorkedHours -= $totalAbsenceHours;
|
||||
} else {
|
||||
$totalDevisCount += count($devisData["devisId"]);
|
||||
$routeLines = $this->gestionBdd->getRouteLinesByDevisIdList($devisData["devisId"]);
|
||||
$totalDistanceAndTotalTravelingHoursBetweenDevis = $this->geoService->getTotalDistanceAndTotalTravelingHoursBetweenDevisLocationByRouteLines($routeLines);
|
||||
$totalDistance = $totalDistanceAndTotalTravelingHoursBetweenDevis["totalDistance"];
|
||||
$totalTravelingHoursBetweenDevisLocation = $totalDistanceAndTotalTravelingHoursBetweenDevis["totalTravelingHours"];
|
||||
$devisList = $devisData["devis"];
|
||||
$leaves = $devisData["leaves"];
|
||||
if(!empty($devisList)) {
|
||||
foreach($devisList as $devis) {
|
||||
$fileContent = $this->populateDevisDataIntoThanatoExportFileContent($fileContent, $devis);
|
||||
$totalDevisHours += $devis["totalHours"];
|
||||
}
|
||||
}
|
||||
foreach($leaves as $leave) {
|
||||
$fileContent = $this->populateNoDevisDataInADay($fileContent, $leave);
|
||||
if($leave["onLeave"]) {
|
||||
$totalLeaveHoursInsideWorkingHours = $leave["totalWorkedHours"];
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE) {
|
||||
$totalLeaveHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST) {
|
||||
$totalRestHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE) {
|
||||
$totalDiseaseHours += $totalLeaveHoursInsideWorkingHours;
|
||||
}
|
||||
}
|
||||
}
|
||||
$totalAbsenceHours = $totalLeaveHours + $totalRestHours + $totalDiseaseHours;
|
||||
$totalWorkedHours -= $totalAbsenceHours;
|
||||
}
|
||||
|
||||
$fileContent = $this->populateLastRecapForTheLine(
|
||||
$fileContent,
|
||||
$totalDistance,
|
||||
$totalDevisHours,
|
||||
$totalWorkedHours,
|
||||
$totalLeaveHours,
|
||||
$totalTravelingHoursBetweenDevisLocation,
|
||||
$totalDiseaseHours,
|
||||
$totalRestHours,$totalDevisCount
|
||||
);
|
||||
$fileContent = $this->populateLastRecapForTheLine(
|
||||
$fileContent,
|
||||
$totalDistance,
|
||||
$totalDevisHours,
|
||||
$totalWorkedHours,
|
||||
$totalLeaveHours,
|
||||
$totalTravelingHoursBetweenDevisLocation,
|
||||
$totalDiseaseHours,
|
||||
$totalRestHours,
|
||||
$totalDevisCount
|
||||
);
|
||||
|
||||
$g_totalDistance += $totalDistance;
|
||||
$g_totalDevisHours += $totalDevisHours;
|
||||
@ -268,8 +277,8 @@ class ExportThanatoStatisticService {
|
||||
$g_totalTravelingHoursBetweenDevisLocation += $totalTravelingHoursBetweenDevisLocation;
|
||||
$g_totalDiseaseHours += $totalDiseaseHours;
|
||||
$g_totalRestHours += $totalRestHours;
|
||||
$g_totalDevisCount += $totalDevisCount;
|
||||
}
|
||||
$g_totalDevisCount += $totalDevisCount;
|
||||
}
|
||||
|
||||
$fileContent = $this->populateLastRecapForTheLine(
|
||||
$fileContent,
|
||||
@ -279,77 +288,113 @@ class ExportThanatoStatisticService {
|
||||
$g_totalLeaveHours,
|
||||
$g_totalTravelingHoursBetweenDevisLocation,
|
||||
$g_totalDiseaseHours,
|
||||
$g_totalRestHours,$g_totalDevisCount
|
||||
$g_totalRestHours,
|
||||
$g_totalDevisCount
|
||||
);
|
||||
|
||||
return $fileContent;
|
||||
}
|
||||
return $fileContent;
|
||||
}
|
||||
|
||||
private function populateLastRecapForTheLine(string $fileContent,$distance,$totalDevisHours,$totalWorkedHours,$totalLeaveHours,$totalTravelingHours ,$totalDiseaseHours = 0,$totalRestHours = 0,$totalDevisCount = 0){
|
||||
$fileContent = $fileContent.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
"$distance".';'.
|
||||
"$totalDevisHours".';'.
|
||||
"$totalLeaveHours".';'.
|
||||
"$totalRestHours".';'.
|
||||
"$totalDiseaseHours".';'.
|
||||
"$totalWorkedHours".';'.
|
||||
"$totalTravelingHours".';'.
|
||||
"$totalDevisCount"."\n";
|
||||
return $fileContent;
|
||||
}
|
||||
private function populateLastRecapForTheLine(string $fileContent, $distance, $totalDevisHours, $totalWorkedHours, $totalLeaveHours, $totalTravelingHours, $totalDiseaseHours = 0, $totalRestHours = 0, $totalDevisCount = 0)
|
||||
{
|
||||
$fileContent = $fileContent.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
"$distance".';'.
|
||||
"$totalDevisHours".';'.
|
||||
"$totalLeaveHours".';'.
|
||||
"$totalRestHours".';'.
|
||||
"$totalDiseaseHours".';'.
|
||||
"$totalWorkedHours".';'.
|
||||
"$totalTravelingHours".';'.
|
||||
"$totalDevisCount"."\n";
|
||||
return $fileContent;
|
||||
}
|
||||
|
||||
private function getFormatDevisProduitsAsString($devisProduits){
|
||||
$result = '';
|
||||
foreach ($devisProduits as $produit) {
|
||||
$result .= $produit['produit_reference'] . '-' . $produit['produit_description'] . '--';
|
||||
}
|
||||
// Remove the trailing "--" at the end
|
||||
$result = rtrim($result, '-');
|
||||
return $result;
|
||||
}
|
||||
private function getFormatDevisProduitsAsString($devisProduits)
|
||||
{
|
||||
$result = '';
|
||||
foreach ($devisProduits as $produit) {
|
||||
$result .= $produit['produit_reference'] . '-' . $produit['produit_description'] . '--';
|
||||
}
|
||||
// Remove the trailing "--" at the end
|
||||
$result = rtrim($result, '-');
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function populateDevisDataIntoThanatoExportFileContent(string $fileContent,array $devis){
|
||||
$produitAsString = $this->getFormatDevisProduitsAsString($devis["produits"]);
|
||||
$factureNum = $devis["facture_num"] ?? $devis["facture_on_group_num"] ?? "";
|
||||
$fileContent = $fileContent.
|
||||
FileExportHelpers::FormatTextForExport($factureNum).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis['nom_thanato'] . ' ' . $devis['prenom_thanatho']).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["date"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["startTime"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["endTime"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($produitAsString).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["dayType"]).';'.
|
||||
FileExportHelpers::FormatTextForExport('Non').';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_defunt"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_lieu"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_client"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["client_adresse"] ?? "").
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'."\n";
|
||||
|
||||
return $fileContent;
|
||||
private function populateDevisDataIntoThanatoExportFileContentSave(string $fileContent, array $devis)
|
||||
{
|
||||
$produitAsString = $this->getFormatDevisProduitsAsString($devis["produits"]);
|
||||
$factureNum = $devis["facture_num"] ?? $devis["facture_on_group_num"] ?? "";
|
||||
$fileContent = $fileContent.
|
||||
FileExportHelpers::FormatTextForExport($factureNum).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis['nom_thanato'] . ' ' . $devis['prenom_thanatho']).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["date"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["startTime"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["endTime"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($produitAsString).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["dayType"]).';'.
|
||||
FileExportHelpers::FormatTextForExport('Non').';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_defunt"]).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_lieu"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_client"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["client_adresse"] ?? "").
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'."\n";
|
||||
|
||||
}
|
||||
return $fileContent;
|
||||
|
||||
}
|
||||
|
||||
private function populateDevisDataIntoThanatoExportFileContent(string $fileContent, array $devis)
|
||||
{
|
||||
$produitAsString = $this->getFormatDevisProduitsAsString($devis["produits"]);
|
||||
$devisNum = (string)($devis["calendar_uuid"] ?? "");
|
||||
|
||||
$fileContent = $fileContent.
|
||||
FileExportHelpers::FormatTextForExport($devisNum).';'.
|
||||
FileExportHelpers::FormatTextForExport(($devis['nom_thanato'] ?? '') . ' ' . ($devis['prenom_thanato'] ?? '')).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["date"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["startTime"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["endTime"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($produitAsString).';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["dayType"] ?? "").';'.
|
||||
'Non'.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_defunt"] ?? "").';'. // ICI
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_lieu"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["nom_client"] ?? "").';'.
|
||||
FileExportHelpers::FormatTextForExport($devis["client_adresse"] ?? "").';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'.
|
||||
''.';'."\n";
|
||||
|
||||
return $fileContent;
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,28 +30,31 @@ use Exception;
|
||||
use OCA\Gestion\Constants\GeoConstant;
|
||||
use OCA\Gestion\Helpers\GeoHelpers;
|
||||
|
||||
class GeoService {
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
class GeoService
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcul la distance entre les deux points à vol d'oiseau
|
||||
*/
|
||||
private function getDistanceInKmBetweenTwoPoints($lat1, $lon1, $lat2, $lon2) {
|
||||
private function getDistanceInKmBetweenTwoPoints($lat1, $lon1, $lat2, $lon2)
|
||||
{
|
||||
$R = 6371; // Rayon moyen de la Terre en kilomètres
|
||||
$dLat = deg2rad($lat2 - $lat1);
|
||||
$dLon = deg2rad($lon2 - $lon1);
|
||||
$a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon/2) * sin($dLon/2);
|
||||
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
|
||||
$a = sin($dLat / 2) * sin($dLat / 2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon / 2) * sin($dLon / 2);
|
||||
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
||||
$d = $R * $c;
|
||||
return round($d, 2);
|
||||
}
|
||||
|
||||
private function getTravelingHourBetweenTwoPoints(array $origin,array $destination,$mode = "driving"){
|
||||
private function getTravelingHourBetweenTwoPoints(array $origin, array $destination, $mode = "driving")
|
||||
{
|
||||
$baseUrl = "https://api.geoapify.com/v1/routing";
|
||||
$originPoints = GeoHelpers::getPointsTextFromLatitudeAndLongitude($origin["latitude"],$origin["longitude"]);
|
||||
$destinationPoints = GeoHelpers::getPointsTextFromLatitudeAndLongitude($destination["latitude"],$destination["longitude"]);
|
||||
$originPoints = GeoHelpers::getPointsTextFromLatitudeAndLongitude($origin["latitude"], $origin["longitude"]);
|
||||
$destinationPoints = GeoHelpers::getPointsTextFromLatitudeAndLongitude($destination["latitude"], $destination["longitude"]);
|
||||
|
||||
$fullUrl = $baseUrl."?waypoints=$originPoints|$destinationPoints&mode=$mode&apiKey=9e23d93e7f454c988344f9171bf867aa";
|
||||
$curl = curl_init();
|
||||
@ -66,11 +69,11 @@ class GeoService {
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => 'GET',
|
||||
));
|
||||
|
||||
|
||||
$response = curl_exec($curl);
|
||||
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
|
||||
if ($response === false) {
|
||||
return 0;
|
||||
} else {
|
||||
@ -79,45 +82,45 @@ class GeoService {
|
||||
$travelTimeHours = round($travelTimeHours, 2);
|
||||
return $travelTimeHours;
|
||||
}
|
||||
}
|
||||
catch(Exception $e){
|
||||
} catch(Exception $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public function getTotalDistanceAndTotalTravelingHoursBetweenDevisLocationByRouteLines(array $routeLines){
|
||||
public function getTotalDistanceAndTotalTravelingHoursBetweenDevisLocationByRouteLinesSave(array $routeLines)
|
||||
{
|
||||
$distanceCumul = 0;
|
||||
$totalTravelingHoursBetweenTwoDevisLocation = 0;
|
||||
$lastPoint = NULL;
|
||||
for ($i=0; $i < sizeof($routeLines); $i++) {
|
||||
$lastPoint = null;
|
||||
for ($i = 0; $i < sizeof($routeLines); $i++) {
|
||||
$currentDistance = 0;
|
||||
if($routeLines[$i]['lieu_id'] != NULL){
|
||||
if($routeLines[$i]['lieu_id'] != null) {
|
||||
$lastPoint = $routeLines[$i];
|
||||
}
|
||||
if($lastPoint['lieu_id'] != NULL && $routeLines[$i+1]['lieu_id'] != NULL){
|
||||
}
|
||||
if($lastPoint['lieu_id'] != null && $routeLines[$i + 1]['lieu_id'] != null) {
|
||||
$currentDistance = $this->getDistanceInKmBetweenTwoPoints(
|
||||
floatval(value: $lastPoint['latitude']),
|
||||
floatval($lastPoint['longitude']),
|
||||
floatval($routeLines[$i+1]['latitude']),
|
||||
floatval($routeLines[$i+1]['longitude'])
|
||||
floatval(value: $lastPoint['latitude']),
|
||||
floatval($lastPoint['longitude']),
|
||||
floatval($routeLines[$i + 1]['latitude']),
|
||||
floatval($routeLines[$i + 1]['longitude'])
|
||||
);
|
||||
$targetIsBetweenTwoDevisLocation = $lastPoint['source'] != "siege" && $routeLines[$i+1]["source"] != "siege";
|
||||
if($targetIsBetweenTwoDevisLocation){
|
||||
$targetIsBetweenTwoDevisLocation = $lastPoint['source'] != "siege" && $routeLines[$i + 1]["source"] != "siege";
|
||||
if($targetIsBetweenTwoDevisLocation) {
|
||||
$originPoints = [
|
||||
"latitude" => $lastPoint["latitude"],
|
||||
"longitude" => $lastPoint["longitude"]
|
||||
];
|
||||
$destinationPoints = [
|
||||
"latitude" => $routeLines[$i+1]["latitude"],
|
||||
"longitude" => $routeLines[$i+1]["longitude"]
|
||||
"latitude" => $routeLines[$i + 1]["latitude"],
|
||||
"longitude" => $routeLines[$i + 1]["longitude"]
|
||||
];
|
||||
$totalTravelingHoursBetweenTwoDevisLocation+= $this->getTravelingHourBetweenTwoPoints(
|
||||
$totalTravelingHoursBetweenTwoDevisLocation += $this->getTravelingHourBetweenTwoPoints(
|
||||
$originPoints,
|
||||
$destinationPoints,
|
||||
GeoConstant::DRIVING_MODE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$distanceCumul += $currentDistance;
|
||||
}
|
||||
return [
|
||||
@ -125,4 +128,65 @@ class GeoService {
|
||||
"totalTravelingHours" => $totalTravelingHoursBetweenTwoDevisLocation
|
||||
];
|
||||
}
|
||||
|
||||
public function getTotalDistanceAndTotalTravelingHoursBetweenDevisLocationByRouteLines(array $routeLines)
|
||||
{
|
||||
$distanceCumul = 0;
|
||||
$totalTravelingHoursBetweenTwoDevisLocation = 0;
|
||||
$lastPoint = null;
|
||||
|
||||
for ($i = 0; $i < sizeof($routeLines); $i++) {
|
||||
$currentDistance = 0;
|
||||
|
||||
// Vérifier que l'élément actuel existe
|
||||
if(!isset($routeLines[$i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if($routeLines[$i]['lieu_id'] != null) {
|
||||
$lastPoint = $routeLines[$i];
|
||||
}
|
||||
|
||||
// Vérifier que $i+1 existe ET que $lastPoint n'est pas null
|
||||
if($lastPoint !== null &&
|
||||
isset($routeLines[$i + 1]) &&
|
||||
isset($lastPoint['lieu_id']) &&
|
||||
isset($routeLines[$i + 1]['lieu_id']) &&
|
||||
$lastPoint['lieu_id'] != null &&
|
||||
$routeLines[$i + 1]['lieu_id'] != null) {
|
||||
|
||||
$currentDistance = $this->getDistanceInKmBetweenTwoPoints(
|
||||
floatval($lastPoint['latitude']),
|
||||
floatval($lastPoint['longitude']),
|
||||
floatval($routeLines[$i + 1]['latitude']),
|
||||
floatval($routeLines[$i + 1]['longitude'])
|
||||
);
|
||||
|
||||
$targetIsBetweenTwoDevisLocation = $lastPoint['source'] != "siege" && $routeLines[$i + 1]["source"] != "siege";
|
||||
|
||||
if($targetIsBetweenTwoDevisLocation) {
|
||||
$originPoints = [
|
||||
"latitude" => $lastPoint["latitude"],
|
||||
"longitude" => $lastPoint["longitude"]
|
||||
];
|
||||
$destinationPoints = [
|
||||
"latitude" => $routeLines[$i + 1]["latitude"],
|
||||
"longitude" => $routeLines[$i + 1]["longitude"]
|
||||
];
|
||||
$totalTravelingHoursBetweenTwoDevisLocation += $this->getTravelingHourBetweenTwoPoints(
|
||||
$originPoints,
|
||||
$destinationPoints,
|
||||
GeoConstant::DRIVING_MODE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$distanceCumul += $currentDistance;
|
||||
}
|
||||
|
||||
return [
|
||||
"totalDistance" => round($distanceCumul, 2),
|
||||
"totalTravelingHours" => round($totalTravelingHoursBetweenTwoDevisLocation, 2)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import "@nextcloud/dialogs/dist/index.css";
|
||||
import "datatables.net-dt/css/jquery.dataTables.css";
|
||||
import "../css/mycss.css";
|
||||
|
||||
import { getArticlesById, getMailServerFrom, getProduitsById, savePdfToNextcloud, exportDevisToPdf, updateDB} from "./modules/ajaxRequest.mjs";
|
||||
import { getArticlesById, getMailServerFrom, getProduitsById, savePdfToNextcloud,exportDevisToPdf} from "./modules/ajaxRequest.mjs";
|
||||
import { getGlobal, globalConfiguration } from "./modules/mainFunction.mjs";
|
||||
import "./listener/main_listener";
|
||||
import { Client } from "./objects/client.mjs";
|
||||
@ -34,23 +34,4 @@ window.addEventListener("DOMContentLoaded", function () {
|
||||
capture(sendMail);
|
||||
(document.getElementById("modalMail")).style.display = "none";
|
||||
});
|
||||
|
||||
$(document).on('change', '.tva-select', function() {
|
||||
var table = $(this).data('table');
|
||||
var column = $(this).data('column');
|
||||
var id = $(this).data('id');
|
||||
var value = $(this).val();
|
||||
|
||||
// Mettre à jour la base de données
|
||||
updateDB(table, column, value, id);
|
||||
|
||||
// Recharger les produits ou articles selon la table
|
||||
setTimeout(function() {
|
||||
if (table === 'produit_devis') {
|
||||
getProduitsById();
|
||||
} else if (table === 'article_devis') {
|
||||
getArticlesById();
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
@ -357,7 +357,7 @@ export function getProduitsByIdDevis(id_devis) {
|
||||
/**
|
||||
* Get a product in database using id
|
||||
*/
|
||||
export function getProduitsById() {
|
||||
export function getProduitsById() {
|
||||
var devis_id = $('#devisid').data('id');
|
||||
var myData = { numdevis: devis_id, };
|
||||
|
||||
@ -376,49 +376,12 @@ export function getProduitsById() {
|
||||
}
|
||||
|
||||
$.each(JSON.parse(response), function (arrayID, myresp) {
|
||||
var tvaValue = myresp.tva || 20.00;
|
||||
var prixUnitaireHT = parseFloat(myresp.prix_unitaire);
|
||||
var quantite = parseFloat(myresp.quantite);
|
||||
|
||||
// Calculs
|
||||
var prixUnitaireTTC = prixUnitaireHT * (1 + tvaValue / 100);
|
||||
var totalHT = prixUnitaireHT * quantite;
|
||||
var totalTTC = prixUnitaireTTC * quantite;
|
||||
|
||||
$('#produits tbody').append('<tr>' +
|
||||
// Colonne 1: Reference (avec delete et selectable)
|
||||
'<td><div data-html2canvas-ignore data-modifier="getProduitsById" data-id="' + myresp.pdid + '" data-table="produit_devis" class="' + deleteDisable + ' deleteItem icon-delete"></div><div style="display:inline;" data-val="' + myresp.pid + '" data-id="' + myresp.pdid + '" class="selectable">' + myresp.reference + '</div></td>' +
|
||||
|
||||
// Colonne 2: Designation
|
||||
$('#produits tbody').append('<tr><td><div data-html2canvas-ignore data-modifier="getProduitsById" data-id="' + myresp.pdid + '" data-table="produit_devis" class="' + deleteDisable + ' deleteItem icon-delete"></div><div style="display:inline;" data-val="' + myresp.pid + '" data-id="' + myresp.pdid + '" class="selectable">' + myresp.reference + '</div></td>' +
|
||||
'<td>' + myresp.description + '</td>' +
|
||||
|
||||
// Colonne 3: Comment (editable)
|
||||
'<td><div class="editable" data-table="produit_devis" data-column="comment" data-id="' + myresp.pdid + '">' + ((myresp.comment.length === 0) ? '-' : myresp.comment) + '</div></td>' +
|
||||
|
||||
// Colonne 4: TVA (select)
|
||||
'<td><select class="form-select tva-select" data-table="produit_devis" data-column="tva" data-id="' + myresp.pdid + '">' +
|
||||
'<option value="10"' + (tvaValue == 10 ? ' selected' : '') + '>10%</option>' +
|
||||
'<option value="15"' + (tvaValue == 15 ? ' selected' : '') + '>15%</option>' +
|
||||
'<option value="20"' + (tvaValue == 20 ? ' selected' : '') + '>20%</option>' +
|
||||
'</select></td>' +
|
||||
|
||||
// Colonne 5: Quantity (editable)
|
||||
'<td><div class="editableNumber getProduitsById" style="display:inline;" data-modifier="getProduitsById" data-table="produit_devis" data-column="quantite" data-id=' + myresp.pdid + '>' + myresp.quantite + '</div></td>' +
|
||||
|
||||
// Colonne 6: Unit price with VAT (Prix unitaire TTC)
|
||||
'<td>' + cur.format(prixUnitaireTTC) + '</td>' +
|
||||
|
||||
// Colonne 7: Unit price without VAT (Prix unitaire HT)
|
||||
'<td><div class="editableNumber getProduitsById" style="display:inline;" data-modifier="getProduitsById" data-table="produit_devis" data-column="unit_price" data-id="' + myresp.pdid + '">' + prixUnitaireHT.toFixed(2) + '</div><span> €</span></td>' +
|
||||
|
||||
// Colonne 8: Total with VAT (Total TTC)
|
||||
'<td>' + cur.format(totalTTC) + '</td>' +
|
||||
|
||||
// Colonne 9: Total without VAT (Total HT)
|
||||
'<td>' + cur.format(totalHT) + '</td>' +
|
||||
|
||||
'</tr>');
|
||||
|
||||
'<td><div class="editableNumber getProduitsById" style="display:inline;" data-modifier="getProduitsById" data-table="produit_devis" data-column="quantite" data-id=' + myresp.pdid + '>' + myresp.quantite + '</div> </td>' +
|
||||
'<td>' + cur.format(myresp.prix_unitaire) + '</td>' +
|
||||
'<td>' + cur.format((myresp.quantite * myresp.prix_unitaire)) + '</td></tr>');
|
||||
total += (myresp.quantite * myresp.prix_unitaire);
|
||||
});
|
||||
|
||||
@ -451,50 +414,12 @@ export function getArticlesById() {
|
||||
}
|
||||
|
||||
$.each(JSON.parse(response), function (arrayID, myresp) {
|
||||
var tvaValue = myresp.tva || 20.00;
|
||||
var prixUnitaireHT = parseFloat(myresp.prix_unitaire);
|
||||
var quantite = parseFloat(myresp.quantite);
|
||||
|
||||
// Calculs
|
||||
var prixUnitaireTTC = prixUnitaireHT * (1 + tvaValue / 100);
|
||||
var totalHT = prixUnitaireHT * quantite;
|
||||
var totalTTC = prixUnitaireTTC * quantite;
|
||||
|
||||
$('#articles tbody').append('<tr>' +
|
||||
// Colonne 1: Reference (avec delete et selectable)
|
||||
'<td><div data-html2canvas-ignore data-modifier="getArticlesById" data-id="' + myresp.adid + '" data-table="article_devis" class="' + deleteDisable + ' deleteItem icon-delete"></div><div style="display:inline;" data-val="' + myresp.aid + '" data-id="' + myresp.adid + '" class="articleSelectable">' + myresp.reference + '</div></td>' +
|
||||
|
||||
// Colonne 2: Designation
|
||||
$('#articles tbody').append('<tr><td><div data-html2canvas-ignore data-modifier="getArticlesById" data-id="' + myresp.adid + '" data-table="article_devis" class="' + deleteDisable + ' deleteItem icon-delete"></div><div style="display:inline;" data-val="' + myresp.aid + '" data-id="' + myresp.adid + '" class="articleSelectable">' + myresp.reference + '</div></td>' +
|
||||
'<td>' + myresp.description + '</td>' +
|
||||
|
||||
// Colonne 3: Comment (editable)
|
||||
'<td><div class="editable" data-table="article_devis" data-column="comment" data-id="' + myresp.adid + '">' + ((myresp.comment.length === 0) ? '-' : myresp.comment) + '</div></td>' +
|
||||
|
||||
// Colonne 4: TVA (select)
|
||||
'<td><select class="form-select tva-select" data-table="article_devis" data-column="tva" data-id="' + myresp.adid + '">' +
|
||||
'<option value="10"' + (tvaValue == 10 ? ' selected' : '') + '>10%</option>' +
|
||||
'<option value="15"' + (tvaValue == 15 ? ' selected' : '') + '>15%</option>' +
|
||||
'<option value="20"' + (tvaValue == 20 ? ' selected' : '') + '>20%</option>' +
|
||||
'</select></td>' +
|
||||
|
||||
// Colonne 5: Quantity (ml) (editable)
|
||||
'<td><div class="editableNumber getArticlesById" style="display:inline;" data-modifier="getArticlesById" data-table="article_devis" data-column="quantite" data-id=' + myresp.adid + '>' + myresp.quantite + '</div></td>' +
|
||||
|
||||
// Colonne 6: Unit price with VAT (Prix unitaire TTC)
|
||||
'<td>' + cur.format(prixUnitaireTTC) + '</td>' +
|
||||
|
||||
// Colonne 7: Unit price without VAT (Prix unitaire HT)
|
||||
'<td><div class="editableNumber getArticlesById" style="display:inline;" data-modifier="getArticlesById" data-table="article_devis" data-column="unit_price" data-id="' + myresp.adid + '">' + prixUnitaireHT.toFixed(2) + '</div><span> €</span></td>' +
|
||||
|
||||
// Colonne 8: Total with VAT (Total TTC)
|
||||
'<td>' + cur.format(totalTTC) + '</td>' +
|
||||
|
||||
// Colonne 9: Total without VAT (Total HT)
|
||||
'<td>' + cur.format(totalHT) + '</td>' +
|
||||
|
||||
'</tr>'
|
||||
);
|
||||
|
||||
'<td><div class="editableNumber getArticlesById" style="display:inline;" data-modifier="getArticlesById" data-table="article_devis" data-column="quantite" data-id=' + myresp.adid + '>' + myresp.quantite + '</div> </td>' +
|
||||
'<td>' + cur.format(myresp.prix_unitaire) + '</td>' +
|
||||
'<td>' + cur.format((myresp.quantite * myresp.prix_unitaire)) + '</td></tr>');
|
||||
total += (myresp.quantite * myresp.prix_unitaire);
|
||||
});
|
||||
|
||||
|
||||
@ -215,71 +215,10 @@ export function getGlobal(id_devis) {
|
||||
})
|
||||
}).done((function (res) {
|
||||
var myresp = JSON.parse(response)[0];
|
||||
var totaux = JSON.parse(res);
|
||||
|
||||
// Fonction de formatage locale
|
||||
function formatMoney(amount) {
|
||||
if (isNaN(amount)) return '0,00 €';
|
||||
return parseFloat(amount).toFixed(2).replace('.', ',') + ' €';
|
||||
}
|
||||
|
||||
var total = JSON.parse(res).total;
|
||||
var tva = parseFloat(myresp.tva_default);
|
||||
$('#totaldevis tbody').empty();
|
||||
|
||||
// Si on a des détails par TVA
|
||||
if (totaux.details && totaux.details.length > 0) {
|
||||
var totalGeneralHT = 0;
|
||||
var totalGeneralTVA = 0;
|
||||
var totalGeneralTTC = 0;
|
||||
|
||||
// Afficher une ligne par taux de TVA
|
||||
totaux.details.forEach(function(detail) {
|
||||
var totalHT = parseFloat(detail.totalHT);
|
||||
var totalTVA = parseFloat(detail.totalTVA);
|
||||
var totalTTC = parseFloat(detail.totalTTC);
|
||||
var tva = parseFloat(detail.tva);
|
||||
|
||||
$('#totaldevis tbody').append(
|
||||
'<tr>' +
|
||||
'<td class="text-center">' + formatMoney(totalHT) + '</td>' +
|
||||
'<td class="text-center">' + tva + ' %</td>' +
|
||||
'<td class="text-center">' + formatMoney(totalTVA) + '</td>' +
|
||||
'<td class="text-center">' + formatMoney(totalTTC) + '</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
|
||||
totalGeneralHT += totalHT;
|
||||
totalGeneralTVA += totalTVA;
|
||||
totalGeneralTTC += totalTTC;
|
||||
});
|
||||
|
||||
// Si plusieurs taux de TVA, afficher une ligne de total
|
||||
if (totaux.details.length > 1) {
|
||||
$('#totaldevis tbody').append(
|
||||
'<tr class="fw-bold bg-light">' +
|
||||
'<td class="text-center"><strong>' + formatMoney(totalGeneralHT) + '</strong></td>' +
|
||||
'<td class="text-center"><strong>TOTAL</strong></td>' +
|
||||
'<td class="text-center"><strong>' + formatMoney(totalGeneralTVA) + '</strong></td>' +
|
||||
'<td class="text-center"><strong>' + formatMoney(totalGeneralTTC) + '</strong></td>' +
|
||||
'</tr>'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Fallback si pas de détails (ancien format)
|
||||
var tva = parseFloat(myresp.tva_default);
|
||||
var total = parseFloat(totaux.totalGeneral) || 0;
|
||||
var montantTVA = (total * tva) / 100;
|
||||
var totalTTC = total * (1 + tva / 100);
|
||||
|
||||
$('#totaldevis tbody').append(
|
||||
'<tr>' +
|
||||
'<td class="text-center">' + formatMoney(total) + '</td>' +
|
||||
'<td class="text-center">' + tva + ' %</td>' +
|
||||
'<td class="text-center">' + formatMoney(montantTVA) + '</td>' +
|
||||
'<td class="text-center">' + formatMoney(totalTTC) + '</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
}
|
||||
|
||||
$('#totaldevis tbody').append('<tr><td>' + cur.format(total) + '</td><td id="tva">' + tva + ' %</td><td id="totaltva">' + cur.format(Math.round((total * tva)) / 100) + '</td><td>' + cur.format(Math.round((total * (tva + 100))) / 100) + '</td></tr>');
|
||||
$('#mentions_default').html(myresp.mentions_default);
|
||||
}));
|
||||
})
|
||||
|
||||
@ -146,25 +146,70 @@
|
||||
<h2 class="mt-3 mb-3 text-center"> <?php p($l->t('Quote')); ?>
|
||||
<div id="devisid" style="display:inline" data-table="devis" data-column="num"
|
||||
data-id="<?php echo $currentDevis->id; ?>">sur le defunt <?php echo $currentDevis->nom_defunt; ?></div>
|
||||
<span data-html2canvas-ignore>(</span>
|
||||
<div data-html2canvas-ignore id="devisversion" style="display:inline" data-table="devis"
|
||||
data-column="version" data-id="<?php echo $currentDevis->id; ?>"><?php echo $currentDevis->lieu; ?>)</div>
|
||||
</h2>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col col-md">
|
||||
<label class="fw-bold"><?php p($l->t('Number')); ?> : </label>
|
||||
<div class="col col-xl mb-3 text-center" style="display:inline">
|
||||
<?php echo $currentDevis->num; ?>
|
||||
</div>
|
||||
<div class="col-5 h-100 m-0" style="min-height:250px;">
|
||||
<?php $res = json_decode($_['configuration'])[0]; ?>
|
||||
<h5 class="p-3 m-0 text-dark text-center border border-2 border-dark"><?php p($l->t('FROM')); ?>
|
||||
<?php echo $res->entreprise; ?></h5>
|
||||
<p
|
||||
class="p-3 m-0 h-auto text-center text-dark text-center border border-top-0 border-2 border-dark">
|
||||
<?php echo $res->prenom . " " . $res->nom; ?><br />
|
||||
<?php echo $res->adresse; ?><br />
|
||||
<?php echo $res->mail; ?><br />
|
||||
<?php echo $res->telephone; ?><br />
|
||||
<span id="nothing"></span><br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="col col-md">
|
||||
<label class="fw-bold"><?php p($l->t('Date')); ?> : </label>
|
||||
<div class="col col-xl mb-3 text-center" style="display:inline">
|
||||
<?php echo $currentDevis->date; ?>
|
||||
</div>
|
||||
<div class="col-2 h-100 m-0" style="min-height:250px;">
|
||||
<?php
|
||||
if (isset($_['logo']) && $_['logo'] !== "nothing") {
|
||||
echo "<center><a><img alt='" . $l->t('Company logo') . "' class=\"img-fluid\" src=\"data:image/png;base64, " . $_['logo'] . "\"/></a></center>";
|
||||
} else {
|
||||
echo "<span style='font-size:12px' id='Company-logo' data-html2canvas-ignore><b><center>" . $l->t('You can add your company logo here.') . "</center></b><br/><i>" . $l->t('To add a logo, drop the logo.png file in ".gestion" folder at the root of your Nextcloud Files app. Remember to set "Show hidden files".') . "</i><br/><br/><center>" . $l->t('This message will not appear on generated PDF.') . "</center></span>";
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="col-5 h-100 m-0" style="min-height:250px;">
|
||||
<h5 class="p-3 m-0 text-dark text-center border border-2 border-dark"><?php p($l->t('TO')); ?>
|
||||
<span id="entreprise"><?php echo $currentDevis->entreprise ?></span></h6>
|
||||
<p
|
||||
class="p-3 m-0 h-auto text-center text-dark text-center border border-top-0 border-2 border-dark">
|
||||
<span id="nomprenom" data-id="0" data-table="devis"
|
||||
data-column="id_client"><?php echo $currentDevis->prenom . ' ' . $currentDevis->nom ?></span><br />
|
||||
<span id="adresse"><?php echo $currentDevis->adresse_cli ?></span><br />
|
||||
<span id="mail"><?php echo $currentDevis->mail_cli ?></span><br />
|
||||
<span id="telephone"><?php echo $currentDevis->telephone_cli ?></span><br />
|
||||
<span id="legal_one"><?php echo $currentDevis->legalone_cli ?></span><br />
|
||||
<span id="dateContext" style="display: none"><?php echo $facture->date ?></span>
|
||||
<span id="nomcli" style="display: none"><?php echo $currentDevis->prenom . ' ' . $currentDevis->nom ?></span>
|
||||
<span id="idcli" style="display: none"><?php echo $currentDevis->id_cli ?></span>
|
||||
<span id="etp" style="display: none"><?php echo $currentDevis->entreprise ?></span>
|
||||
<span class="pdf"
|
||||
style="display: none"><?php echo $currentDevis->entreprise . "_" . $currentDevis->id . "_v" . $currentDevis->version ?></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md">
|
||||
<div class="d-flex flex-column">
|
||||
<span>Defunt : <b><?php echo $currentDevis->nom_defunt; ?></b></span>
|
||||
<hr />
|
||||
<div class="col col-xl mb-3 text-center">
|
||||
<b><span><?php p($l->t('Offer valid for 1 month from')); ?> :
|
||||
</span><span><?php echo (new DateTime($currentDevis->date))->format('d-m-Y'); ?></span></b></div>
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md">
|
||||
<div class="col col-xl text-center">
|
||||
<span>Date de soin :
|
||||
<b><?php echo (new DateTime($currentDevis->date))->format('d-m-Y'); ?></b>,</span> <span
|
||||
id="devisid" data-id=<?php echo $currentDevis->id; ?>>Defunt associé :
|
||||
<b><?php echo $currentDevis->nom_defunt; ?></b></span><br />
|
||||
<span>Lieu : <b><?php echo $currentDevis->lieu; ?> (<?php echo $currentDevis->adresse_soin; ?>)</b>
|
||||
</div>
|
||||
</div>
|
||||
@ -200,72 +245,23 @@
|
||||
<th><?php p($l->t('Reference')); ?></th>
|
||||
<th><?php p($l->t('Designation')); ?></th>
|
||||
<th><?php p($l->t('Comment')); ?></th>
|
||||
<th><?php p($l->t('TVA'));?></th>
|
||||
<th><?php p($l->t('Quantity')); ?></th>
|
||||
<th><?php p($l->t('Unit price without VAT'));?></th>
|
||||
<th><?php p($l->t('Total without VAT'));?></th>
|
||||
<th>Total TTC</th>
|
||||
<th><?php p($l->t('Unit price without VAT')); ?></th>
|
||||
<th><?php p($l->t('Total without VAT')); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
// ⭐ NOUVEAU: Grouper par taux de TVA pour les calculs
|
||||
$totalsByTva = [];
|
||||
|
||||
foreach ($currentDevis->dproduits as $key => $produit) {
|
||||
// Récupérer le taux de TVA du produit (défaut 20%)
|
||||
$tvaValue = isset($produit->tva) && $produit->tva !== null ? floatval($produit->tva) : 20.00;
|
||||
$totalHT = $produit->prix_unitaire * $produit->quantite;
|
||||
$totalTTC = $totalHT * (1 + $tvaValue / 100);
|
||||
|
||||
// Grouper par taux
|
||||
if (!isset($totalsByTva[$tvaValue])) {
|
||||
$totalsByTva[$tvaValue] = [
|
||||
'totalHT' => 0,
|
||||
'totalTVA' => 0,
|
||||
'totalTTC' => 0
|
||||
];
|
||||
}
|
||||
$totalsByTva[$tvaValue]['totalHT'] += $totalHT;
|
||||
$totalsByTva[$tvaValue]['totalTVA'] += ($totalTTC - $totalHT);
|
||||
$totalsByTva[$tvaValue]['totalTTC'] += $totalTTC;
|
||||
?>
|
||||
<?php foreach ($currentDevis->dproduits as $key => $produit) { ?>
|
||||
<tr>
|
||||
<td><?php echo $produit->reference ?></td>
|
||||
<td><?php echo $produit->description ?></td>
|
||||
<td><?php echo $produit->comment ?></td>
|
||||
<td><?php echo number_format($tvaValue, 0) ?>%</td>
|
||||
<td><?php echo $produit->quantite ?></td>
|
||||
<td>€<?php echo number_format($produit->prix_unitaire, 2) ?></td>
|
||||
<td>€<?php echo number_format($totalHT, 2) ?></td>
|
||||
<td>€<?php echo number_format($totalTTC, 2) ?></td>
|
||||
<td>€<?php echo number_format($produit->prix_unitaire * $produit->quantite, 2) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php }
|
||||
|
||||
// ⭐ NOUVEAU: Trier par taux
|
||||
ksort($totalsByTva);
|
||||
|
||||
// ⭐ NOUVEAU: Afficher les totaux par TVA dans le tableau
|
||||
if (count($totalsByTva) > 0) {
|
||||
?>
|
||||
<tr class="table-secondary">
|
||||
<td colspan="8"><hr style="border-top: 2px solid #000; margin: 5px 0;"></td>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($totalsByTva as $tva => $totals) {
|
||||
?>
|
||||
<tr class="fw-bold">
|
||||
<td colspan="3">Total TVA <?php echo number_format($tva, 0) ?>%</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>€<?php echo number_format($totals['totalHT'], 2) ?></td>
|
||||
<td>€<?php echo number_format($totals['totalTTC'], 2) ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -274,27 +270,28 @@
|
||||
<thead class="bg-dark text-white">
|
||||
<tr>
|
||||
<th class="text-center"><?php p($l->t('Total without VAT')); ?></th>
|
||||
<th class="text-center"><?php p($l->t('VAT Rate')); ?></th>
|
||||
<th class="text-center"><?php p($l->t('Total VAT')); ?></th>
|
||||
<th class="text-center"><?php p($l->t('Total Price')); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
// ⭐ NOUVEAU: Calculer les totaux généraux
|
||||
$totalGeneralHT = 0;
|
||||
$totalGeneralTVA = 0;
|
||||
$totalGeneralTTC = 0;
|
||||
|
||||
foreach ($totalsByTva as $totals) {
|
||||
$totalGeneralHT += $totals['totalHT'];
|
||||
$totalGeneralTVA += $totals['totalTVA'];
|
||||
$totalGeneralTTC += $totals['totalTTC'];
|
||||
$totalhtc = 0;
|
||||
$tva = json_decode($_['configuration'])[0]->tva_default;
|
||||
$totalttc = 0;
|
||||
$totalprice = 0;
|
||||
foreach ($currentDevis->dproduits as $key => $produit) {
|
||||
$totalhtc = $totalhtc + ($produit->quantite * $produit->prix_unitaire);
|
||||
}
|
||||
$totalttc = ($totalhtc * $tva) / 100;
|
||||
$totalprice = $totalhtc + $totalttc;
|
||||
?>
|
||||
<tr class="fw-bold">
|
||||
<td class="text-center">€<?php echo number_format($totalGeneralHT, 2) ?></td>
|
||||
<td class="text-center">€<?php echo number_format($totalGeneralTVA, 2) ?></td>
|
||||
<td class="text-center">€<?php echo number_format($totalGeneralTTC, 2) ?></td>
|
||||
<tr>
|
||||
<td>€<?php echo number_format($totalhtc, 2) ?></td>
|
||||
<td><?php echo $tva ?> %</td>
|
||||
<td>€<?php echo number_format($totalttc, 2) ?></td>
|
||||
<td>€<?php echo number_format($totalprice, 2) ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -19,12 +19,12 @@
|
||||
</div>
|
||||
<div class="col-2 h-100 m-0" style="min-height:250px;">
|
||||
<?php
|
||||
if(isset($_['logo']) && $_['logo'] !== "nothing") {
|
||||
if(isset($_['logo']) && $_['logo'] !== "nothing"){
|
||||
echo "<center><a><img alt='".$l->t('Company logo')."' class=\"img-fluid\" src=\"data:image/png;base64, ".$_['logo']."\"/></a></center>";
|
||||
} else {
|
||||
}else{
|
||||
echo "<span style='font-size:12px' id='Company-logo' data-html2canvas-ignore><b><center>".$l->t('You can add your company logo here.')."</center></b><br/><i>".$l->t('To add a logo, drop the logo.png file in ".gestion" folder at the root of your Nextcloud Files app. Remember to set "Show hidden files".')."</i><br/><br/><center>".$l->t('This message will not appear on generated PDF.')."</center></span>";
|
||||
}
|
||||
?>
|
||||
?>
|
||||
</div>
|
||||
<div class="col-5 h-100 m-0" style="min-height:250px;">
|
||||
<h5 class="p-3 m-0 text-dark text-center border border-2 border-dark"><?php p($l->t('TO'));?> <span id="entreprise"></span></h5>
|
||||
@ -66,7 +66,7 @@
|
||||
style="display:inline"
|
||||
data-table="devis" data-column="order_number"
|
||||
data-id="<?php echo $_['devis'][0]->devisid;?>">
|
||||
<?php echo ($_['devis'][0]->order_number == "") ? "-" : $_['devis'][0]->order_number ; ?>
|
||||
<?php echo ($_['devis'][0]->order_number == "" ) ? "-" : $_['devis'][0]->order_number ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
@ -78,7 +78,7 @@
|
||||
style="display:inline"
|
||||
data-table="devis" data-column="case_number"
|
||||
data-id="<?php echo $_['devis'][0]->devisid;?>">
|
||||
<?php echo ($_['devis'][0]->case_number == "") ? "-" : $_['devis'][0]->case_number ; ?>
|
||||
<?php echo ($_['devis'][0]->case_number == "" ) ? "-" : $_['devis'][0]->case_number ; ?>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
@ -95,11 +95,8 @@
|
||||
<th><?php p($l->t('Reference'));?></th>
|
||||
<th><?php p($l->t('Designation'));?></th>
|
||||
<th><?php p($l->t('Comment'));?></th>
|
||||
<th><?php p($l->t('TVA'));?></th>
|
||||
<th><?php p($l->t('Quantity'));?></th>
|
||||
<th>PU TTC</th>
|
||||
<th><?php p($l->t('Unit price without VAT'));?></th>
|
||||
<th>Total TTC</th>
|
||||
<th><?php p($l->t('Total without VAT'));?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -119,11 +116,8 @@
|
||||
<th><?php p($l->t('Reference'));?></th>
|
||||
<th><?php p($l->t('Designation'));?></th>
|
||||
<th><?php p($l->t('Comment'));?></th>
|
||||
<th><?php p($l->t('TVA'));?></th>
|
||||
<th><?php p($l->t('Quantity'));?>(ml)</th>
|
||||
<th>PU TTC</th>
|
||||
<th><?php p($l->t('Unit price without VAT'));?></th>
|
||||
<th>Total TTC</th>
|
||||
<th><?php p($l->t('Total without VAT'));?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user