dolibarr 25.0.0-alpha
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2013-2014 Olivier Geffroy <jeff@jeffinfo.com>
3 * Copyright (C) 2013-2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
4 * Copyright (C) 2014 Florian Henry <florian.henry@open-concept.pro>
5 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
6 * Copyright (C) 2025 MDW <mdeweerd@users.noreply.github.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
28// Load Dolibarr environment
29require '../../main.inc.php';
30require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
31require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
32require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
34
43$error = 0;
44
45// Load translation files required by the page
46$langs->loadLangs(array('accountancy', 'bills', 'compta'));
47
48$action = GETPOST('action', 'aZ09');
49$backtopage = GETPOST('backtopage', 'alpha');
50$id = GETPOSTINT('id');
51$ref = GETPOST('ref', 'alpha');
52$rowid = GETPOSTINT('rowid');
53$cancel = GETPOST('cancel', 'alpha');
54
55$account_number = GETPOST('account_number', 'alphanohtml');
56$label = GETPOST('label', 'alpha');
57
58// Security check
59if ($user->socid > 0) {
61}
62if (!$user->hasRight('accounting', 'chartofaccount')) {
64}
65
66
67$object = new AccountingAccount($db);
68
69
70/*
71 * Action
72 */
73
74if (GETPOST('cancel', 'alpha')) {
75 $urltogo = (!empty($backtopage) ? $backtopage : DOL_URL_ROOT.'/accountancy/admin/account.php');
76 header("Location: ".$urltogo);
77 exit;
78}
79
80if ($action == 'add' /* && $user->hasRight('accounting', 'chartofaccount') // already checked */) {
81 if (!$cancel) {
82 if ((string) $account_number === '') {
83 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountNumber")), null, 'errors');
84 $action = 'create';
85 } elseif ((string) $label === '') {
86 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
87 $action = 'create';
88 } else {
89 $sql = "SELECT pcg_version FROM " . MAIN_DB_PREFIX . "accounting_system WHERE rowid = ".((int) getDolGlobalInt('CHARTOFACCOUNTS'));
90
91 dol_syslog('accountancy/admin/card.php:: $sql=' . $sql);
92 $result = $db->query($sql);
93 $obj = $db->fetch_object($result);
94
95 // Clean code
96
97 // To manage zero or not at the end of the accounting account
98 if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
99 $account_number = clean_account($account_number);
100 }
101
102 $account_parent = (GETPOSTINT('account_parent') > 0) ? GETPOSTINT('account_parent') : 0;
103
104 $object->fk_pcg_version = $obj->pcg_version;
105 $object->pcg_type = GETPOST('pcg_type', 'alpha');
106 $object->account_number = $account_number;
107 $object->account_parent = $account_parent;
108 $object->account_category = GETPOSTINT('account_category');
109 $object->label = $label;
110 $object->labelshort = GETPOST('labelshort', 'alpha');
111 $object->active = 1;
112
113 $res = $object->create($user);
114 if ($res == -3) {
115 $error = 1;
116 $action = "create";
117 setEventMessages($object->error, $object->errors, 'errors');
118 } elseif ($res == -4) {
119 $error = 2;
120 $action = "create";
121 setEventMessages($object->error, $object->errors, 'errors');
122 } elseif ($res < 0) {
123 $error++;
124 setEventMessages($object->error, $object->errors, 'errors');
125 $action = "create";
126 }
127 if (!$error) {
128 setEventMessages("RecordCreatedSuccessfully", null, 'mesgs');
129 $urltogo = (!empty($backtopage) ? $backtopage : DOL_URL_ROOT.'/accountancy/admin/account.php');
130 header("Location: " . $urltogo);
131 exit;
132 }
133 }
134 }
135} elseif ($action == 'edit' /* && $user->hasRight('accounting', 'chartofaccount') // already checked */) {
136 if (!$cancel) {
137 if ((string) $account_number === '') {
138 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountNumber")), null, 'errors');
139 $action = 'update';
140 } elseif ((string) $label === '') {
141 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
142 $action = 'update';
143 } else {
144 $result = $object->fetch($id);
145
146 $sql = "SELECT pcg_version FROM ".MAIN_DB_PREFIX."accounting_system WHERE rowid=".((int) getDolGlobalInt('CHARTOFACCOUNTS'));
147
148 dol_syslog('accountancy/admin/card.php:: $sql=' . $sql);
149 $result2 = $db->query($sql);
150 $obj = $db->fetch_object($result2);
151
152 // Clean code
153
154 // To manage zero or not at the end of the accounting account
155 if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
156 $account_number = clean_account($account_number);
157 }
158
159 $account_parent = (GETPOSTINT('account_parent') > 0) ? GETPOSTINT('account_parent') : 0;
160
161 $object->fk_pcg_version = $obj->pcg_version;
162 $object->pcg_type = GETPOST('pcg_type', 'alpha');
163 $object->account_number = $account_number;
164 $object->account_parent = $account_parent;
165 $object->account_category = GETPOSTINT('account_category');
166 $object->label = $label;
167 $object->labelshort = GETPOST('labelshort', 'alpha');
168
169 $result = $object->update($user);
170
171 if ($result > 0) {
172 $urltogo = (!empty($backtopage) ? $backtopage : ($_SERVER["PHP_SELF"] . "?id=" . $id));
173 header("Location: " . $urltogo);
174 exit();
175 } elseif ($result == -2) {
176 setEventMessages($langs->trans("ErrorAccountNumberAlreadyExists", $object->account_number), null, 'errors');
177 } else {
178 setEventMessages($object->error, null, 'errors');
179 }
180 }
181 } else {
182 $urltogo = (!empty($backtopage) ? $backtopage : ($_SERVER["PHP_SELF"]."?id=".$id));
183 header("Location: ".$urltogo);
184 exit();
185 }
186} elseif ($action == 'delete' && $user->hasRight('accounting', 'chartofaccount')) {
187 $result = $object->fetch($id);
188
189 if (!empty($object->id)) {
190 $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
191 $result = $object->delete($user);
192
193 if ($result > 0) {
194 $urltogo = (!empty($backtopage) ? $backtopage : DOL_URL_ROOT.'/accountancy/admin/account.php');
195 header("Location: ".$urltogo);
196 exit;
197 }
198 }
199
200 if ($result < 0) {
201 setEventMessages($object->error, $object->errors, 'errors');
202 }
203}
204
205
206/*
207 * View
208 */
209
210$form = new Form($db);
211$formaccounting = new FormAccounting($db);
212
213$accountsystem = new AccountancySystem($db);
214$accountsystem->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
215
216$title = $langs->trans('AccountAccounting')." - ".$langs->trans('Card');
217
218$help_url = 'EN:Module_Double_Entry_Accounting#Setup|FR:Module_Comptabilit&eacute;_en_Partie_Double#Configuration';
219
220llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-accountancy page-admin_card');
221
222
223// Create mode
224if ($action == 'create') {
225 print load_fiche_titre($langs->trans('NewAccountingAccount'));
226
227 print '<form name="add" action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
228 print '<input type="hidden" name="token" value="'.newToken().'">';
229 print '<input type="hidden" name="action" value="add">';
230
231 print dol_get_fiche_head();
232
233 print '<table class="border centpercent">';
234
235 // Chart of account
236 print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("Chartofaccounts").'</span></td>';
237 print '<td>';
238 print $accountsystem->ref;
239 print '</td></tr>';
240
241 // Account number
242 print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("AccountNumber").'</span></td>';
243 print '<td><input name="account_number" size="30" value="'.$account_number.'"></td></tr>';
244
245 // Label
246 print '<tr><td><span class="fieldrequired">'.$langs->trans("Label").'</span></td>';
247 print '<td><input name="label" size="70" value="'.$object->label.'"></td></tr>';
248
249 // Label short
250 print '<tr><td>'.$langs->trans("ShortLabel").'</td>';
251 print '<td><input name="labelshort" size="70" value="'.$object->labelshort.'"></td></tr>';
252
253 // Account parent
254 print '<tr><td>'.$langs->trans("Accountparent").'</td>';
255 print '<td>';
256 print $formaccounting->select_account((string) $object->account_parent, 'account_parent', 1, [], 0, 0, 'minwidth200');
257 print '</td></tr>';
258
259 // Chart of accounts type
260 print '<tr><td>';
261 print $form->textwithpicto($langs->trans("Pcgtype"), $langs->transnoentitiesnoconv("PcgtypeDesc"));
262 print '</td>';
263 print '<td>';
264 print '<input type="text" name="pcg_type" list="pcg_type_datalist" value="'.dol_escape_htmltag(GETPOSTISSET('pcg_type') ? GETPOST('pcg_type', 'alpha') : $object->pcg_type).'">';
265 // autosuggest from existing account types if found
266 print '<datalist id="pcg_type_datalist">';
267 $sql = "SELECT DISTINCT pcg_type FROM " . MAIN_DB_PREFIX . "accounting_account";
268 $sql .= " WHERE fk_pcg_version = '" . $db->escape($accountsystem->ref) . "'";
269 $sql .= ' AND entity in ('.getEntity('accounting_account', 0).')'; // Always limit to current entity. No sharing in accountancy.
270 $sql .= ' LIMIT 50000'; // just as a sanity check
271 $resql = $db->query($sql);
272 if ($resql) {
273 while ($obj = $db->fetch_object($resql)) {
274 print '<option value="' . dol_escape_htmltag($obj->pcg_type) . '">';
275 }
276 }
277 print '</datalist>';
278 print '</td></tr>';
279
280 // Category
281 print '<tr><td>';
282 print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
283 print '</td>';
284 print '<td>';
285 print $formaccounting->select_accounting_category($object->account_category, 'account_category', 1, 0, 1);
286 print '</td></tr>';
287
288 print '</table>';
289
290 print dol_get_fiche_end();
291
292 print '<div class="center">';
293 print '<input class="button button-save" type="submit" value="'.$langs->trans("Save").'">';
294 print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
295 print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
296 print '</div>';
297
298 print '</form>';
299} elseif ($id > 0 || $ref) {
300 $result = $object->fetch($id, $ref, 1);
301
302 if ($result > 0) {
303 $head = accounting_prepare_head($object);
304
305 // Edit mode
306 if ($action == 'update') {
307 print dol_get_fiche_head($head, 'card', $langs->trans('AccountAccounting'), 0, 'accounting_account');
308
309 print '<form name="update" action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
310 print '<input type="hidden" name="token" value="'.newToken().'">';
311 print '<input type="hidden" name="action" value="edit">';
312 print '<input type="hidden" name="id" value="'.$id.'">';
313 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
314
315 print '<table class="border centpercent">';
316
317 // Account number
318 print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("AccountNumber").'</span></td>';
319 print '<td><input class="minwidth300" name="account_number" value="'.$object->account_number.'"></td></tr>';
320
321 // Label
322 print '<tr><td><span class="fieldrequired">'.$langs->trans("Label").'</span></td>';
323 print '<td><input class="minwidth500" name="label" value="'.$object->label.'"></td></tr>';
324
325 // Label short
326 print '<tr><td>'.$langs->trans("ShortLabel").'</td>';
327 print '<td><input class="minwidth300" name="labelshort" value="'.$object->labelshort.'"></td></tr>';
328
329 // Account parent
330 print '<tr><td>'.$langs->trans("Accountparent").'</td>';
331 print '<td>';
332 // Note: We accept disabled account as parent account so we can build a hierarchy and use only children
333 print $formaccounting->select_account((string) $object->account_parent, 'account_parent', 1, array(), 0, 0, 'minwidth100 maxwidth300 maxwidthonsmartphone', '1', '');
334 print '</td></tr>';
335
336 // Chart of accounts type
337 print '<tr><td>';
338 print $form->textwithpicto($langs->trans("Pcgtype"), $langs->transnoentitiesnoconv("PcgtypeDesc"));
339 print '</td>';
340 print '<td>';
341 print '<input type="text" name="pcg_type" list="pcg_type_datalist" value="'.dol_escape_htmltag(GETPOSTISSET('pcg_type') ? GETPOST('pcg_type', 'alpha') : $object->pcg_type).'">';
342 // autosuggest from existing account types if found
343 print '<datalist id="pcg_type_datalist">';
344 $sql = 'SELECT DISTINCT pcg_type FROM ' . MAIN_DB_PREFIX . 'accounting_account';
345 $sql .= " WHERE fk_pcg_version = '" . $db->escape($accountsystem->ref) . "'";
346 $sql .= ' AND entity in ('.getEntity('accounting_account', 0).')'; // Always limit to current entity. No sharing in accountancy.
347 $sql .= ' LIMIT 50000'; // just as a sanity check
348 $resql = $db->query($sql);
349 if ($resql) {
350 while ($obj = $db->fetch_object($resql)) {
351 print '<option value="' . dol_escape_htmltag($obj->pcg_type) . '">';
352 }
353 }
354 print '</datalist>';
355 print '</td></tr>';
356
357 // Category
358 print '<tr><td>';
359 print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
360 print '</td>';
361 print '<td>';
362 print $formaccounting->select_accounting_category($object->account_category, 'account_category', 1);
363 print '</td></tr>';
364
365 print '</table>';
366
367 print dol_get_fiche_end();
368
369 print $form->buttonsSaveCancel();
370
371 print '</form>';
372 } else {
373 // View mode
374 $linkback = '<a href="'.DOL_URL_ROOT.'/accountancy/admin/account.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
375
376 print dol_get_fiche_head($head, 'card', $langs->trans('AccountAccounting'), -1, 'accounting_account');
377
378 dol_banner_tab($object, 'ref', $linkback, 1, 'account_number', 'ref');
379
380
381 print '<div class="fichecenter">';
382 print '<div class="underbanner clearboth"></div>';
383
384 print '<table class="border centpercent tableforfield">';
385
386 // Label
387 print '<tr><td class="titlefield">'.$langs->trans("Label").'</td>';
388 print '<td colspan="2">'.$object->label.'</td></tr>';
389
390 // Label to show
391 print '<tr><td class="titlefield">'.$langs->trans("ShortLabel").'</td>';
392 print '<td colspan="2">'.$object->labelshort.'</td></tr>';
393
394 // Account parent
395 $accp = new AccountingAccount($db);
396 if (!empty($object->account_parent)) {
397 $accp->fetch($object->account_parent, '');
398 }
399 print '<tr><td>'.$langs->trans("Accountparent").'</td>';
400 print '<td colspan="2">'.$accp->account_number.' - '.$accp->label.'</td></tr>';
401
402 // Group of accounting account
403 print '<tr><td>';
404 print $form->textwithpicto($langs->trans("Pcgtype"), $langs->transnoentitiesnoconv("PcgtypeDesc"));
405 print '</td>';
406 print '<td colspan="2">'.$object->pcg_type.'</td></tr>';
407
408 // Custom group of accounting account
409 print "<tr><td>";
410 print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
411 print "</td><td colspan='2'>".$object->account_category_label."</td>";
412
413 print '</table>';
414
415 print '</div>';
416
417 print dol_get_fiche_end();
418
419 /*
420 * Actions buttons
421 */
422 print '<div class="tabsAction">';
423
424 // if ($user->hasRight('accounting', 'chartofaccount')) { // already checked
425 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=update&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Modify').'</a>';
426 // } else {
427 // print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotAllowed")).'">'.$langs->trans('Modify').'</a>';
428 // }
429
430 // Delete
431 $permissiontodelete = $user->hasRight('accounting', 'chartofaccount');
432 print dolGetButtonAction($langs->trans("Delete"), $langs->trans("Delete"), 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete, array('attr' => array('class' => 'reposition')))."\n";
433
434 print '</div>';
435 }
436 } else {
437 dol_print_error($db, $object->error, $object->errors);
438 }
439}
440
441// End of page
442llxFooter();
443$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
accounting_prepare_head(AccountingAccount $object)
Prepare array with list of tabs.
clean_account($account)
Return accounting account without zero on the right.
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to manage accountancy systems.
Class to manage accounting accounts.
Class to manage generation of HTML components for accounting management.
Class to manage generation of HTML components Only common components must be here.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
Definition html.lib.php:540
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition html.lib.php:738
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Definition html.lib.php:181
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.