dolibarr 24.0.0-beta
pdf_standard_salary.modules.php
1<?php
2
3/* Copyright (C) 2026 Alain CIS
4 * Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
5 * Inspired by the standard stock and invoice PDF models
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13require_once DOL_DOCUMENT_ROOT.'/core/modules/salaries/modules_salary.php';
14require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
15require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
16require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
17if (isModEnabled('project')) {
18 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
19}
20require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
21
22
27{
29 public $db;
30
32 public $name;
33
35 public $description;
36
38 public $type;
39
41 public $page_largeur;
42
44 public $page_hauteur;
45
47 public $format;
48
50 public $marge_gauche;
51
53 public $marge_droite;
54
56 public $marge_haute;
57
59 public $marge_basse;
60
62 public $posxdesc;
63
65 public $posxearning;
66
68 public $posxdeduction;
69
71 public $emetteur;
72
78 public function __construct(\DoliDB $db)
79 {
80 global $conf, $langs, $mysoc;
81
82 $langs->loadLangs(array("main", "companies", "bills", "salaries", "projects"));
83
84 $this->db = $db;
85 $this->name = "standard_salary";
86 $this->description = $langs->trans("StandardSalaryDocModel");
87
88 // Page dimensions
89 $this->type = 'pdf';
90 $formatarray = pdf_getFormat();
91 $this->page_largeur = $formatarray['width'];
92 $this->page_hauteur = $formatarray['height'];
93 $this->format = array($this->page_largeur, $this->page_hauteur);
94 $this->marge_gauche = getDolGlobalInt('MAIN_PDF_MARGIN_LEFT', 10);
95 $this->marge_droite = getDolGlobalInt('MAIN_PDF_MARGIN_RIGHT', 10);
96 $this->marge_haute = getDolGlobalInt('MAIN_PDF_MARGIN_TOP', 10);
97 $this->marge_basse = getDolGlobalInt('MAIN_PDF_MARGIN_BOTTOM', 10);
98
99 // Define position of columns for the table body
100 $this->posxdesc = $this->marge_gauche;
101 $this->posxearning = $this->page_largeur - $this->marge_droite - 80;
102 $this->posxdeduction = $this->page_largeur - $this->marge_droite - 40;
103
104 $this->emetteur = $mysoc;
105 }
106
107
119 public function writeFile($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
120 {
121 global $conf, $langs;
122
123 $outputlangs = is_object($outputlangs) ? $outputlangs : $langs;
124 if (getDolGlobalString('MAIN_USE_FPDF')) {
125 $outputlangs->charset_output = 'ISO-8859-1';
126 }
127
128 $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "salaries"));
129
130 if (!$conf->salaries->dir_output) {
131 $this->error = $langs->trans("ErrorConstantNotDefined", "SALARIES_OUTPUTDIR");
132 return 0;
133 }
134
135 $objref = dol_sanitizeFileName($object->ref);
136 $dir = $conf->salaries->dir_output . "/salary/" . $objref;
137 $file = $dir . "/" . $objref . ".pdf";
138
139 if (!dol_is_dir($dir)) {
140 if (dol_mkdir($dir) < 0) {
141 $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir);
142 return -1;
143 }
144 }
145
146 if (is_writable($dir)) {
147 $pdf = pdf_getInstance($this->format);
148 $pdf->setAutoPageBreak(true, 0);
149
150 if (class_exists('TCPDF')) {
151 $pdf->setPrintHeader(false);
152 $pdf->setPrintFooter(false);
153 }
154 $pdf->SetFont(pdf_getPDFFont($outputlangs));
155 $pdf->Open();
156
157 $pdf->AddPage();
158 $this->_pagehead($pdf, $object, $outputlangs);
159 $this->body($pdf, $object, $outputlangs);
160 $this->_pagefoot($pdf, $object, $outputlangs);
161
162 $pdf->Close();
163 $pdf->Output($file, 'F');
164 dolChmod($file);
165
166 return 1;
167 } else {
168 $this->error = $langs->trans("ErrorDirIsNotWritable", $dir);
169 return 0;
170 }
171 }
172
173 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
183 protected function _pagehead(&$pdf, $object, $outputlangs, $showaddress = 1)
184 {
185 global $conf;
186 $default_font_size = pdf_getPDFFontSize($outputlangs);
187
188 pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
189
190 $posy = $this->marge_haute;
191 $posx = $this->page_largeur - $this->marge_droite - 100;
192
193 $pdf->SetXY($this->marge_gauche, $posy);
194
195 // Logo
196 $logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
197 if ($this->emetteur->logo && is_readable($logo)) {
198 $height = pdf_getHeightForLogo($logo);
199 $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
200 } else {
201 $pdf->SetFont('', 'B', $default_font_size + 2);
202 $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L');
203 }
204 $yafterleft = $pdf->GetY();
205
206 // Company Address
207 $pdf->SetFont('', '', $default_font_size);
208 $pdf->SetXY($this->marge_gauche, $yafterleft + 1);
209 pdf_build_address($outputlangs, $this->emetteur, null, 'target');
210 $yafterleft = $pdf->GetY();
211
212
213 // Document Title
214 $pdf->SetFont('', 'B', $default_font_size + 4);
215 $pdf->SetXY($posx, $posy);
216 $pdf->SetTextColor(0, 0, 60);
217 $pdf->MultiCell(100, 5, $outputlangs->transnoentities("SalarySlip") . ' ' . $outputlangs->convToOutputCharset($object->ref), '', 'R');
218
219 $posy = $pdf->GetY() + 8;
220
221 // Employee Information
222 $employee = new User($this->db);
223
224 $fk_user = 0;
225 if (!empty($object->fk_user)) {
226 $fk_user = $object->fk_user;
227 } elseif (!empty($object->fk_user_author)) {
228 $fk_user = $object->fk_user_author;
229 }
230
231 if ($fk_user > 0 && $employee->fetch($fk_user) > 0) {
232 $pdf->SetFont('', '', $default_font_size);
233 $pdf->SetXY($posx, $posy);
234
235 $text = $employee->getFullName($outputlangs) . "\n";
236
237 if (!empty($employee->job)) {
238 $text .= $employee->job . "\n";
239 }
240 if (!empty($employee->address)) {
241 $text .= $employee->address . "\n";
242 }
243 if (!empty($employee->zip) || !empty($employee->town)) {
244 $text .= trim($employee->zip . ' ' . $employee->town) . "\n";
245 }
246 if (!empty($employee->email)) {
247 $text .= $employee->email;
248 }
249 $yafterright = $pdf->GetY();
250 } else {
251 $yafterright = $posy;
252 }
253
254
255 // Move cursor to below the taller of the two columns
256 $pdf->SetY(max($yafterleft, $yafterright) + 8);
257
258 // Info box
259 $pdf->SetFont('', 'B', $default_font_size - 1);
260 $pdf->SetTextColor(0, 0, 0);
261
262 // Build info array
263 $info_array = [];
264
265 // Add employee information to info box
266 if (!empty($employee->id)) {
267 $info_array[$outputlangs->transnoentitiesnoconv("Employee")]
268 = $employee->getFullName($outputlangs);
269
270 if (!empty($employee->job)) {
271 $info_array[$outputlangs->transnoentitiesnoconv("Job")]
272 = $employee->job;
273 }
274
275 if (!empty($employee->email)) {
276 $info_array[$outputlangs->transnoentitiesnoconv("Email")]
277 = $employee->email;
278 }
279 }
280
281 $info_array[$outputlangs->transnoentitiesnoconv("PayPeriod")] = dol_print_date($object->datesp, 'day') . " - " . dol_print_date($object->dateep, 'day');
282 $payment_date = $object->datesp;
283 $info_array[$outputlangs->transnoentitiesnoconv("DatePayment")] = dol_print_date($payment_date, 'day');
284
285 if ($object->type_payment && !empty($object->type_payment_code)) {
286 $info_array[$outputlangs->transnoentitiesnoconv("PaymentMode")] = $outputlangs->trans("PaymentType".$object->type_payment_code);
287 }
288
289 if (!empty($object->num_payment)) {
290 $info_array[$outputlangs->transnoentitiesnoconv("Numero")] = $object->num_payment;
291 }
292 if (isModEnabled('project') && !empty($object->fk_project)) {
293 $project = new Project($this->db);
294 if ($project->fetch($object->fk_project) > 0) {
295 $info_array[$outputlangs->transnoentitiesnoconv("Project")] = $project->ref;
296 }
297 }
298
299 // Print info box
300 $col1_width = 40;
301 foreach ($info_array as $label => $value) {
302 $pdf->SetFont('', 'B', $default_font_size - 1);
303 $pdf->Cell($col1_width, 5, $label . " :", 0, 0, 'L');
304 $pdf->SetFont('', '', $default_font_size - 1);
305 $pdf->MultiCell(0, 5, $value, 0, 'L');
306 }
307 $pdf->Ln(5);
308 }
309
310
319 protected function body(&$pdf, $object, $outputlangs)
320 {
321 $default_font_size = pdf_getPDFFontSize($outputlangs);
322 $tab_top = $pdf->GetY();
323
324 $this->tableauHeader($pdf, $tab_top, $outputlangs);
325 $curY = $tab_top + 7;
326
327 // --- EARNINGS ---
328 $pdf->SetFont('', '', $default_font_size);
329 $pdf->SetXY($this->posxdesc, $curY);
330 $pdf->MultiCell($this->posxearning - $this->posxdesc, 5, $outputlangs->convToOutputCharset($object->label));
331 $y_after_label = $pdf->GetY();
332
333 $pdf->SetXY($this->posxearning, $curY);
334 $pdf->MultiCell($this->posxdeduction - $this->posxearning, 5, price($object->amount, 0, $outputlangs, 1), 0, 'R');
335
336 $gross_pay = $object->amount;
337
338 // --- DEDUCTIONS ---
339 // This section is ready for when the salary object supports deductions.
340 $total_deductions = 0.00;
341
342 // --- PUBLIC NOTE ---
343 if (!empty($object->note_public)) {
344 $pdf->SetY($y_after_label + 5);
345 $pdf->SetFont('', 'B', $default_font_size - 1);
346 $pdf->Cell(0, 5, $outputlangs->transnoentitiesnoconv("Note"), 0, 1, 'L');
347 $pdf->SetFont('', '', $default_font_size - 1);
348 $pdf->writeHTMLCell($this->page_largeur - $this->marge_gauche - $this->marge_droite, 5, $this->marge_gauche, $pdf->GetY(), $object->note_public, 'B', 1);
349 }
350
351 // --- TOTALS ---
352 $net_pay = $gross_pay - $total_deductions;
353 $totals_y_pos = $this->page_hauteur - $this->marge_basse - 30;
354 $pdf->SetY(max($pdf->GetY() + 5, $totals_y_pos));
355
356 $pdf->SetFont('', '', $default_font_size);
357 $pdf->SetX($this->posxearning - 30);
358 $pdf->Cell(40, 5, $outputlangs->transnoentitiesnoconv("TotalEarnings") . " :", 0, 0, 'R');
359 $pdf->Cell(30, 5, price($gross_pay, 0, $outputlangs, 1), 0, 1, 'R');
360
361 $pdf->SetX($this->posxearning - 30);
362 $pdf->Cell(40, 5, $outputlangs->transnoentitiesnoconv("TotalDeductions") . " :", 0, 0, 'R');
363 $pdf->Cell(30, 5, price($total_deductions, 0, $outputlangs, 1), 0, 1, 'R');
364
365 $pdf->SetLineStyle(array('width' => 0.3, 'color' => array(0, 0, 0)));
366 $pdf->Line($this->posxearning - 30, $pdf->GetY(), $this->page_largeur - $this->marge_droite, $pdf->GetY());
367 $pdf->Ln(1);
368
369 $pdf->SetFont('', 'B', $default_font_size + 1);
370 $pdf->SetX($this->posxearning - 30);
371 $pdf->Cell(40, 6, $outputlangs->transnoentitiesnoconv("NetPaid") . " :", 0, 0, 'R');
372 $pdf->Cell(30, 6, price($net_pay, 0, $outputlangs, 1), 0, 1, 'R');
373 }
374
375
384 protected function tableauHeader(&$pdf, $tab_top, $outputlangs)
385 {
386 $default_font_size = pdf_getPDFFontSize($outputlangs);
387
388 $pdf->SetXY($this->posxdesc, $tab_top);
389 $pdf->SetFont('', 'B', $default_font_size - 1);
390 $pdf->SetFillColor(240, 240, 240);
391 $pdf->SetTextColor(0, 0, 0);
392
393 $pdf->Cell($this->posxearning - $this->posxdesc, 7, $outputlangs->transnoentitiesnoconv("Description"), 0, 0, 'L', true);
394 $pdf->Cell($this->posxdeduction - $this->posxearning, 7, $outputlangs->transnoentitiesnoconv("Earnings"), 0, 0, 'R', true);
395 $pdf->Cell($this->page_largeur - $this->marge_droite - $this->posxdeduction, 7, $outputlangs->transnoentitiesnoconv("Deductions"), 0, 1, 'R', true);
396
397 $pdf->SetDrawColor(128, 128, 128);
398 $pdf->Line($this->marge_gauche, $tab_top + 7, $this->page_largeur - $this->marge_droite, $tab_top + 7);
399 }
400
401 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
410 protected function _pagefoot(&$pdf, $object, $outputlangs)
411 {
412 $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0);
413 pdf_pagefoot($pdf, $outputlangs, 'SALARY_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails);
414 }
415}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class to manage Dolibarr database access.
Base class for Salary PDF document models.
Class to manage projects.
Class to manage Dolibarr users.
Class to build a standard salary slip PDF.
body(&$pdf, $object, $outputlangs)
Show the lines of the salary slip.
writeFile($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
Function to build the salary slip document.
tableauHeader(&$pdf, $tab_top, $outputlangs)
Show table header.
__construct(\DoliDB $db)
Constructor.
_pagefoot(&$pdf, $object, $outputlangs)
Show footer of page.
_pagehead(&$pdf, $object, $outputlangs, $showaddress=1)
Show top header of page.
global $mysoc
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_is_dir($folder)
Test if filename is a directory.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:294
pdf_getHeightForLogo($logo, $url=false)
Return height to use for Logo onto PDF.
Definition pdf.lib.php:317
pdf_pagehead($pdf, $outputlangs, $page_height)
Show header of page for PDF generation.
Definition pdf.lib.php:747
pdf_pagefoot($pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_basse, $marge_gauche, $page_hauteur, $object, $showdetails=0, $hidefreetext=0, $page_largeur=0, $watermark='')
Show footer of page for PDF generation.
Definition pdf.lib.php:1421
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:273
pdf_build_address($outputlangs, $sourcecompany, $targetcompany='', $targetcontact='', $usecontact=0, $mode='source', $object=null)
Return a string with full address formatted for output on PDF documents.
Definition pdf.lib.php:438
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:129
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133