dolibarr 20.0.2
index.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2019-2023 Open-DSI <support@open-dsi.fr>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
24// Load Dolibarr environment
25require '../../main.inc.php';
26require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
27require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
28require_once DOL_DOCUMENT_ROOT.'/core/class/fiscalyear.class.php';
29require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
30require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php';
31
32// Load translation files required by the page
33$langs->loadLangs(array("compta", "bills", "other", "accountancy"));
34
35$action = GETPOST('action', 'aZ09');
36$confirm = GETPOST('confirm', 'aZ09');
37$fiscal_period_id = GETPOSTINT('fiscal_period_id');
38$validatemonth = GETPOSTINT('validatemonth');
39$validateyear = GETPOSTINT('validateyear');
40
41// Security check
42if (!isModEnabled('accounting')) {
44}
45if ($user->socid > 0) {
47}
48if (!$user->hasRight('accounting', 'fiscalyear', 'write')) {
50}
51
52// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
53$hookmanager->initHooks(array('accountancyclosure'));
54
55$object = new BookKeeping($db);
56
57$now = dol_now();
58$fiscal_periods = $object->getFiscalPeriods();
59if (!is_array($fiscal_periods)) {
60 setEventMessages($object->error, $object->errors, 'errors');
61}
62
63// Define the arrays of fiscal periods
64$active_fiscal_periods = array();
65$first_active_fiscal_period = null;
66$last_fiscal_period = null;
67$current_fiscal_period = null;
68$next_fiscal_period = null;
69$next_active_fiscal_period = null;
70if (is_array($fiscal_periods)) {
71 foreach ($fiscal_periods as $fiscal_period) { // List of fiscal periods sorted by date start
72 if (empty($first_active_fiscal_period) && empty($fiscal_period['status'])) {
73 $first_active_fiscal_period = $fiscal_period;
74 }
75 if (empty($fiscal_period['status'])) { // if not closed
76 $active_fiscal_periods[] = $fiscal_period;
77 }
78 if (isset($current_fiscal_period)) { // If we already reach then current fiscal period, then this one is the next one just after
79 if (!isset($next_fiscal_period)) {
80 $next_fiscal_period = $fiscal_period;
81 }
82 if (!isset($next_active_fiscal_period) && empty($fiscal_period['status'])) {
83 $next_active_fiscal_period = $fiscal_period;
84 }
85 } else { // If we did not found the current fiscal period
86 if ($fiscal_period_id == $fiscal_period['id'] || (empty($fiscal_period_id) && $fiscal_period['date_start'] <= $now && $now <= $fiscal_period['date_end'])) {
87 $current_fiscal_period = $fiscal_period;
88 } else {
89 $last_fiscal_period = $fiscal_period; // $last_fiscal_period is in fact $previous_fiscal_period
90 }
91 }
92 }
93}
94
95// If a current fiscal period open with an end and start date was not found, we autoselect the first one that is open and has a start and end date defined
96if (empty($current_fiscal_period) && !empty($first_active_fiscal_period)) {
97 $current_fiscal_period = $first_active_fiscal_period;
98 $last_fiscal_period = null;
99 $foundcurrent = false;
100 foreach ($fiscal_periods as $fiscal_period) { // List of fiscal periods sorted by date start
101 if ($foundcurrent) {
102 $next_fiscal_period = $fiscal_period;
103 break;
104 }
105 if ($fiscal_period['id'] == $current_fiscal_period['id']) {
106 $foundcurrent = true;
107 }
108 if (!$foundcurrent) {
109 $last_fiscal_period = $fiscal_period;
110 }
111 }
112}
113
114$accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen');
115$accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen');
116
117
118/*
119 * Actions
120 */
121
122$parameters = array('fiscal_periods' => $fiscal_periods, 'last_fiscal_period' => $last_fiscal_period, 'current_fiscal_period' => $current_fiscal_period, 'next_fiscal_period' => $next_fiscal_period);
123$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
124if ($reshook < 0) {
125 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
126}
127
128if (empty($reshook)) {
129 if (isset($current_fiscal_period) && $user->hasRight('accounting', 'fiscalyear', 'write')) {
130 if ($action == 'confirm_step_1' && $confirm == "yes") {
131 $date_start = dol_mktime(0, 0, 0, GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
132 $date_end = dol_mktime(23, 59, 59, GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
133
134 $result = $object->validateMovementForFiscalPeriod($date_start, $date_end);
135 if ($result > 0) {
136 setEventMessages($langs->trans("AllMovementsWereRecordedAsValidated"), null, 'mesgs');
137
138 header("Location: " . $_SERVER['PHP_SELF'] . (isset($current_fiscal_period) ? '?fiscal_period_id=' . $current_fiscal_period['id'] : ''));
139 exit;
140 } else {
141 setEventMessages($langs->trans("NotAllMovementsCouldBeRecordedAsValidated"), null, 'errors');
142 setEventMessages($object->error, $object->errors, 'errors');
143 $action = '';
144 }
145 } elseif ($action == 'confirm_step_2' && $confirm == "yes") {
146 $new_fiscal_period_id = GETPOSTINT('new_fiscal_period_id');
147 $separate_auxiliary_account = GETPOST('separate_auxiliary_account', 'aZ09');
148 $generate_bookkeeping_records = GETPOST('generate_bookkeeping_records', 'aZ09');
149
150 $error = 0;
151 if ($generate_bookkeeping_records) {
152 if (!getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT')) {
153 $error++;
154 setEventMessages($langs->trans("ErrorAccountingClosureSetupNotComplete"), null, 'errors');
155 } elseif (!getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) {
156 $error++;
157 setEventMessages($langs->trans("ErrorAccountingClosureSetupNotComplete"), null, 'errors');
158 }
159 }
160
161 if (!$error) {
162 $result = $object->closeFiscalPeriod($current_fiscal_period['id'], $new_fiscal_period_id, $separate_auxiliary_account, $generate_bookkeeping_records);
163 if ($result < 0) {
164 setEventMessages($object->error, $object->errors, 'errors');
165 } else {
166 setEventMessages($langs->trans("AccountancyClosureCloseSuccessfully"), null, 'mesgs');
167
168 header("Location: " . $_SERVER['PHP_SELF'] . (isset($current_fiscal_period) ? '?fiscal_period_id=' . $current_fiscal_period['id'] : ''));
169 exit;
170 }
171 }
172 } elseif ($action == 'confirm_step_3' && $confirm == "yes") {
173 $inventory_journal_id = GETPOSTINT('inventory_journal_id');
174 $new_fiscal_period_id = GETPOSTINT('new_fiscal_period_id');
175 $date_start = dol_mktime(0, 0, 0, GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
176 $date_end = dol_mktime(23, 59, 59, GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
177
178 $result = $object->insertAccountingReversal($current_fiscal_period['id'], $inventory_journal_id, $new_fiscal_period_id, $date_start, $date_end);
179 if ($result < 0) {
180 setEventMessages($object->error, $object->errors, 'errors');
181 } else {
182 setEventMessages($langs->trans("AccountancyClosureInsertAccountingReversalSuccessfully"), null, 'mesgs');
183
184 header("Location: " . $_SERVER['PHP_SELF'] . (isset($current_fiscal_period) ? '?fiscal_period_id=' . $current_fiscal_period['id'] : ''));
185 exit;
186 }
187 }
188 }
189}
190
191
192/*
193 * View
194 */
195
196$form = new Form($db);
197$formaccounting = new FormAccounting($db);
198
199$title = $langs->trans('Closure');
200
201$help_url = 'EN:Module_Double_Entry_Accounting|FR:Module_Comptabilit&eacute;_en_Partie_Double#Cl.C3.B4ture_annuelle';
202
203llxHeader('', $title, $help_url);
204
205$formconfirm = '';
206
207if (isset($current_fiscal_period)) {
208 if ($action == 'step_1') {
209 $form_question = array();
210
211 $form_question['date_start'] = array(
212 'name' => 'date_start',
213 'type' => 'date',
214 'label' => $langs->trans('DateStart'),
215 'value' => $current_fiscal_period['date_start']
216 );
217 $form_question['date_end'] = array(
218 'name' => 'date_end',
219 'type' => 'date',
220 'label' => $langs->trans('DateEnd'),
221 'value' => $current_fiscal_period['date_end']
222 );
223
224 $formconfirm = $form->formconfirm(
225 $_SERVER["PHP_SELF"] . '?fiscal_period_id=' . $current_fiscal_period['id'],
226 $langs->trans('ValidateMovements'),
227 $langs->trans('DescValidateMovements', $langs->transnoentitiesnoconv("RegistrationInAccounting")),
228 'confirm_step_1',
229 $form_question,
230 '',
231 1,
232 300
233 );
234 } elseif ($action == 'step_2') {
235 $form_question = array();
236
237 $fiscal_period_arr = array();
238 foreach ($active_fiscal_periods as $info) {
239 $fiscal_period_arr[$info['id']] = $info['label'];
240 }
241 $form_question['new_fiscal_period_id'] = array(
242 'name' => 'new_fiscal_period_id',
243 'type' => 'select',
244 'label' => $langs->trans('AccountancyClosureStep3NewFiscalPeriod'),
245 'values' => $fiscal_period_arr,
246 'default' => isset($next_active_fiscal_period) ? $next_active_fiscal_period['id'] : '',
247 );
248 $form_question['generate_bookkeeping_records'] = array(
249 'name' => 'generate_bookkeeping_records',
250 'type' => 'checkbox',
251 'label' => $langs->trans('AccountancyClosureGenerateClosureBookkeepingRecords'),
252 'value' => 1
253 );
254 $form_question['separate_auxiliary_account'] = array(
255 'name' => 'separate_auxiliary_account',
256 'type' => 'checkbox',
257 'label' => $langs->trans('AccountancyClosureSeparateAuxiliaryAccounts'),
258 'value' => 0
259 );
260
261 $formconfirm = $form->formconfirm(
262 $_SERVER["PHP_SELF"] . '?fiscal_period_id=' . $current_fiscal_period['id'],
263 $langs->trans('AccountancyClosureClose'),
264 $langs->trans('AccountancyClosureConfirmClose'),
265 'confirm_step_2',
266 $form_question,
267 '',
268 1,
269 300
270 );
271 } elseif ($action == 'step_3') {
272 $form_question = array();
273
274 $form_question['inventory_journal_id'] = array(
275 'name' => 'inventory_journal_id',
276 'type' => 'other',
277 'label' => $langs->trans('InventoryJournal'),
278 'value' => $formaccounting->select_journal(0, "inventory_journal_id", 8, 1, 0, 0)
279 );
280 $fiscal_period_arr = array();
281 foreach ($active_fiscal_periods as $info) {
282 $fiscal_period_arr[$info['id']] = $info['label'];
283 }
284 $form_question['new_fiscal_period_id'] = array(
285 'name' => 'new_fiscal_period_id',
286 'type' => 'select',
287 'label' => $langs->trans('AccountancyClosureStep3NewFiscalPeriod'),
288 'values' => $fiscal_period_arr,
289 'default' => isset($next_active_fiscal_period) ? $next_active_fiscal_period['id'] : '',
290 );
291 $form_question['date_start'] = array(
292 'name' => 'date_start',
293 'type' => 'date',
294 'label' => $langs->trans('DateStart'),
295 'value' => dol_time_plus_duree($current_fiscal_period['date_end'], -1, 'm')
296 );
297 $form_question['date_end'] = array(
298 'name' => 'date_end',
299 'type' => 'date',
300 'label' => $langs->trans('DateEnd'),
301 'value' => $current_fiscal_period['date_end']
302 );
303
304 $formconfirm = $form->formconfirm(
305 $_SERVER["PHP_SELF"] . '?fiscal_period_id=' . $current_fiscal_period['id'],
306 $langs->trans('AccountancyClosureAccountingReversal'),
307 $langs->trans('AccountancyClosureConfirmAccountingReversal'),
308 'confirm_step_3',
309 $form_question,
310 '',
311 1,
312 300
313 );
314 }
315}
316
317// Call Hook formConfirm
318$parameters = array('formConfirm' => $formconfirm, 'fiscal_periods' => $fiscal_periods, 'last_fiscal_period' => $last_fiscal_period, 'current_fiscal_period' => $current_fiscal_period, 'next_fiscal_period' => $next_fiscal_period);
319$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
320if (empty($reshook)) {
321 $formconfirm .= $hookmanager->resPrint;
322} elseif ($reshook > 0) {
323 $formconfirm = $hookmanager->resPrint;
324}
325
326// Print form confirm
327print $formconfirm;
328
329$fiscal_period_nav_text = $langs->trans("FiscalPeriod");
330
331$fiscal_period_nav_text .= '&nbsp;<a href="' . (isset($last_fiscal_period) ? $_SERVER["PHP_SELF"] . '?fiscal_period_id=' . $last_fiscal_period['id'] : '#" class="disabled') . '">' . img_previous() . '</a>';
332$fiscal_period_nav_text .= '&nbsp;<a href="' . (isset($next_fiscal_period) ? $_SERVER["PHP_SELF"] . '?fiscal_period_id=' . $next_fiscal_period['id'] : '#" class="disabled') . '">' . img_next() . '</a>';
333if (!empty($current_fiscal_period)) {
334 $fiscal_period_nav_text .= $current_fiscal_period['label'].' &nbsp;(' . (isset($current_fiscal_period) ? dol_print_date($current_fiscal_period['date_start'], 'day') . '&nbsp;-&nbsp;' . dol_print_date($current_fiscal_period['date_end'], 'day') . ')' : '');
335}
336
337print load_fiche_titre($langs->trans("Closure") . " - " . $fiscal_period_nav_text, '', 'title_accountancy');
338
339if (empty($current_fiscal_period)) {
340 print $langs->trans('ErrorNoFiscalPeriodActiveFound', $langs->transnoentitiesnoconv("Accounting"), $langs->transnoentitiesnoconv("Setup"), $langs->transnoentitiesnoconv("FiscalPeriod"));
341} else {
342 // Step 1
343 $head = array();
344 $head[0][0] = DOL_URL_ROOT . '/accountancy/closure/index.php?fiscal_period_id=' . $current_fiscal_period['id'];
345 $head[0][1] = $langs->trans("AccountancyClosureStep1");
346 $head[0][2] = 'step1';
347 print dol_get_fiche_head($head, 'step1', '', -1, '');
348
349 print '<span class="opacitymedium">' . $langs->trans("AccountancyClosureStep1Desc") . '</span><br>';
350
351 $count_by_month = $object->getCountByMonthForFiscalPeriod($current_fiscal_period['date_start'], $current_fiscal_period['date_end']);
352 if (!is_array($count_by_month)) {
353 setEventMessages($object->error, $object->errors, 'errors');
354 }
355
356 if (empty($count_by_month['total'])) {
357 $buttonvalidate = '<a class="butActionRefused classfortooltip" href="#">' . $langs->trans("ValidateMovements") . '</a>';
358 } else {
359 $buttonvalidate = '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=step_1&fiscal_period_id=' . $current_fiscal_period['id'] . '">' . $langs->trans("ValidateMovements") . '</a>';
360 }
361 print_barre_liste($langs->trans("OverviewOfMovementsNotValidated"), '', '', '', '', '', '', -1, '', '', 0, $buttonvalidate, '', 0, 1, 0);
362
363 print '<div class="div-table-responsive-no-min">';
364 print '<table class="noborder centpercent">';
365
366 print '<tr class="liste_titre">';
367 $nb_years = is_array($count_by_month['list']) ? count($count_by_month['list']) : 0;
368 if ($nb_years > 1) {
369 print '<td class="right">' . $langs->trans("Year") . '</td>';
370 }
371 for ($i = 1; $i <= 12; $i++) {
372 print '<td class="right">' . $langs->trans('MonthShort' . str_pad((string) $i, 2, '0', STR_PAD_LEFT)) . '</td>';
373 }
374 print '<td class="right"><b>' . $langs->trans("Total") . '</b></td>';
375 print '</tr>';
376
377 if (is_array($count_by_month['list'])) {
378 foreach ($count_by_month['list'] as $info) {
379 print '<tr class="oddeven">';
380 if ($nb_years > 1) {
381 print '<td class="right">' . $info['year'] . '</td>';
382 }
383 for ($i = 1; $i <= 12; $i++) {
384 print '<td class="right">' . ((int) $info['count'][$i]) . '</td>';
385 }
386 print '<td class="right"><b>' . $info['total'] . '</b></td></tr>';
387 }
388 }
389
390 print "</table>\n";
391 print '</div>';
392
393 print '<br>';
394
395 // Step 2
396 $head = array();
397 $head[0][0] = DOL_URL_ROOT . '/accountancy/closure/index.php?fiscal_period_id=' . $current_fiscal_period['id'];
398 $head[0][1] = $langs->trans("AccountancyClosureStep2");
399 $head[0][2] = 'step2';
400 print dol_get_fiche_head($head, 'step2', '', -1, '');
401
402 // print '<span class="opacitymedium">' . $langs->trans("AccountancyClosureStep2Desc") . '</span><br>';
403
404 if (empty($count_by_month['total']) && empty($current_fiscal_period['status'])) {
405 $button = '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=step_2&fiscal_period_id=' . $current_fiscal_period['id'] . '">' . $langs->trans("AccountancyClosureClose") . '</a>';
406 } else {
407 $button = '<a class="butActionRefused classfortooltip" href="#" title="This fiscal period already has the status Closed. Feature disabled.">' . $langs->trans("AccountancyClosureClose") . '</a>';
408 }
409 print_barre_liste('', '', '', '', '', '', '', -1, '', '', 0, $button, '', 0, 1, 0);
410
411 print '<br>';
412
413 // Step 3
414 $head = array();
415 $head[0][0] = DOL_URL_ROOT . '/accountancy/closure/index.php?fiscal_period_id=' . $current_fiscal_period['id'];
416 $head[0][1] = $langs->trans("AccountancyClosureStep3");
417 $head[0][2] = 'step3';
418 print dol_get_fiche_head($head, 'step3', '', -1, '');
419
420 // print '<span class="opacitymedium">' . $langs->trans("AccountancyClosureStep3Desc") . '</span><br>';
421
422 if (empty($current_fiscal_period['status'])) {
423 $button = '<a class="butActionRefused classfortooltip" href="#">' . $langs->trans("AccountancyClosureAccountingReversal") . '</a>';
424 } else {
425 $button = '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=step_3&fiscal_period_id=' . $current_fiscal_period['id'] . '">' . $langs->trans("AccountancyClosureAccountingReversal") . '</a>';
426 }
427 print_barre_liste('', '', '', '', '', '', '', -1, '', '', 0, $button, '', 0, 1, 0);
428}
429
430// End of page
431llxFooter();
432$db->close();
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:55
llxFooter()
Empty footer.
Definition wrapper.php:69
Class to manage Ledger (General Ledger and Subledger)
Class to manage generation of HTML components for accounting management.
Class to manage generation of HTML components Only common components must be here.
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_now($mode='auto')
Return date for now.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
img_previous($titlealt='default', $moreatt='')
Show previous logo.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
img_next($titlealt='default', $moreatt='')
Show next logo.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.