1<?php 2/* Copyright (C) 2018 Laurent Destailleur <eldy@users.sourceforge.net> 3 * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19/** 20 * \file htdocs/compta/stats/byratecountry.php 21 * \brief VAT by rate 22 */ 23 24require '../../main.inc.php'; 25require_once DOL_DOCUMENT_ROOT.'/core/lib/report.lib.php'; 26require_once DOL_DOCUMENT_ROOT.'/core/lib/tax.lib.php'; 27require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; 28require_once DOL_DOCUMENT_ROOT.'/compta/tva/class/tva.class.php'; 29require_once DOL_DOCUMENT_ROOT.'/compta/localtax/class/localtax.class.php'; 30require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; 31require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; 32require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php'; 33require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; 34require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php'; 35require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php'; 36require_once DOL_DOCUMENT_ROOT.'/expensereport/class/paymentexpensereport.class.php'; 37 38// Load translation files required by the page 39$langs->loadLangs(array("other", "compta", "banks", "bills", "companies", "product", "trips", "admin", "accountancy")); 40 41$modecompta = (GETPOST('modecompta', 'alpha') ? GETPOST('modecompta', 'alpha') : $conf->global->ACCOUNTING_MODE); 42 43// Date range 44$year = GETPOST("year", 'int'); 45$month = GETPOST("month", 'int'); 46if (empty($year)) { 47 $year_current = dol_print_date(dol_now(), '%Y'); 48 $month_current = dol_print_date(dol_now(), '%m'); 49 $year_start = $year_current; 50} else { 51 $year_current = $year; 52 $month_current = dol_print_date(dol_now(), '%m'); 53 $year_start = $year; 54} 55$date_start = dol_mktime(0, 0, 0, GETPOST("date_startmonth"), GETPOST("date_startday"), GETPOST("date_startyear"), 'tzserver'); // We use timezone of server so report is same from everywhere 56$date_end = dol_mktime(23, 59, 59, GETPOST("date_endmonth"), GETPOST("date_endday"), GETPOST("date_endyear"), 'tzserver'); // We use timezone of server so report is same from everywhere 57// Quarter 58if (empty($date_start) || empty($date_end)) { // We define date_start and date_end 59 $q = GETPOST("q", "int"); 60 if (empty($q)) { 61 // We define date_start and date_end 62 $month_start = GETPOST("month") ?GETPOST("month") : ($conf->global->SOCIETE_FISCAL_MONTH_START ? ($conf->global->SOCIETE_FISCAL_MONTH_START) : 1); 63 $year_end = $year_start; 64 $month_end = $month_start; 65 if (!GETPOST("month")) { // If month not forced 66 if (!GETPOST('year') && $month_start > $month_current) { 67 $year_start--; 68 $year_end--; 69 } 70 $month_end = $month_start - 1; 71 if ($month_end < 1) { 72 $month_end = 12; 73 } else { 74 $year_end++; 75 } 76 } 77 $date_start = dol_get_first_day($year_start, $month_start, false); 78 $date_end = dol_get_last_day($year_end, $month_end, false); 79 } else { 80 if ($q == 1) { 81 $date_start = dol_get_first_day($year_start, 1, false); 82 $date_end = dol_get_last_day($year_start, 3, false); 83 } 84 if ($q == 2) { 85 $date_start = dol_get_first_day($year_start, 4, false); 86 $date_end = dol_get_last_day($year_start, 6, false); 87 } 88 if ($q == 3) { 89 $date_start = dol_get_first_day($year_start, 7, false); 90 $date_end = dol_get_last_day($year_start, 9, false); 91 } 92 if ($q == 4) { 93 $date_start = dol_get_first_day($year_start, 10, false); 94 $date_end = dol_get_last_day($year_start, 12, false); 95 } 96 } 97} 98 99// $date_start and $date_end are defined. We force $year_start and $nbofyear 100$tmps = dol_getdate($date_start); 101$year_start = $tmps['year']; 102$tmpe = dol_getdate($date_end); 103$year_end = $tmpe['year']; 104 105$tmp_date_end = dol_time_plus_duree($date_start, 1, 'y') - 1; 106if ($tmp_date_end < $date_end || $date_end < $date_start) { 107 $date_end = $tmp_date_end; 108} 109 110$min = price2num(GETPOST("min", "alpha")); 111if (empty($min)) { 112 $min = 0; 113} 114 115// Define modetax (0 or 1) 116// 0=normal, 1=option vat for services is on debit, 2=option on payments for products 117$modetax = empty($conf->global->TAX_MODE) ? 0 : $conf->global->TAX_MODE; 118if (GETPOSTISSET("modetax")) { 119 $modetax = GETPOST("modetax", 'int'); 120} 121if (empty($modetax)) { 122 $modetax = 0; 123} 124 125// Security check 126$socid = GETPOST('socid', 'int'); 127if ($user->socid) { 128 $socid = $user->socid; 129} 130$result = restrictedArea($user, 'tax', '', '', 'charges'); 131 132 133 134/* 135 * View 136 */ 137 138$form = new Form($db); 139$company_static = new Societe($db); 140$invoice_customer = new Facture($db); 141$invoice_supplier = new FactureFournisseur($db); 142$expensereport = new ExpenseReport($db); 143$product_static = new Product($db); 144$payment_static = new Paiement($db); 145$paymentfourn_static = new PaiementFourn($db); 146$paymentexpensereport_static = new PaymentExpenseReport($db); 147 148$morequerystring = ''; 149$listofparams = array('date_startmonth', 'date_startyear', 'date_startday', 'date_endmonth', 'date_endyear', 'date_endday'); 150foreach ($listofparams as $param) { 151 if (GETPOST($param) != '') { 152 $morequerystring .= ($morequerystring ? '&' : '').$param.'='.GETPOST($param); 153 } 154} 155 156llxHeader('', $langs->trans("TurnoverReport"), '', '', 0, 0, '', '', $morequerystring); 157 158 159//print load_fiche_titre($langs->trans("VAT"),""); 160 161//$fsearch.='<br>'; 162$fsearch .= ' <input type="hidden" name="year" value="'.$year.'">'; 163$fsearch .= ' <input type="hidden" name="modetax" value="'.$modetax.'">'; 164//$fsearch.=' '.$langs->trans("SalesTurnoverMinimum").': '; 165//$fsearch.=' <input type="text" name="min" value="'.$min.'">'; 166 167 168// Show report header 169$name = $langs->trans("xxx"); 170$calcmode = ''; 171if ($modetax == 0) { 172 $calcmode = $langs->trans('OptionVATDefault'); 173} 174if ($modetax == 1) { 175 $calcmode = $langs->trans('OptionVATDebitOption'); 176} 177if ($modetax == 2) { 178 $calcmode = $langs->trans('OptionPaymentForProductAndServices'); 179} 180$calcmode .= '<br>('.$langs->trans("TaxModuleSetupToModifyRules", DOL_URL_ROOT.'/admin/taxes.php').')'; 181// Set period 182$period = $form->selectDate($date_start, 'date_start', 0, 0, 0, '', 1, 0, 0, '', '', '', '', 1, '', '', 'tzserver'); 183$period .= ' - '; 184$period .= $form->selectDate($date_end, 'date_end', 0, 0, 0, '', 1, 0, 0, '', '', '', '', 1, '', '', 'tzserver'); 185$prevyear = $year_start; 186$prevquarter = $q; 187if ($prevquarter > 1) { 188 $prevquarter--; 189} else { 190 $prevquarter = 4; 191 $prevyear--; 192} 193$nextyear = $year_start; 194$nextquarter = $q; 195if ($nextquarter < 4) { 196 $nextquarter++; 197} else { 198 $nextquarter = 1; 199 $nextyear++; 200} 201$description .= $fsearch; 202$builddate = dol_now(); 203 204if ($conf->global->TAX_MODE_SELL_PRODUCT == 'invoice') { 205 $description .= $langs->trans("RulesVATDueProducts"); 206} 207if ($conf->global->TAX_MODE_SELL_PRODUCT == 'payment') { 208 $description .= $langs->trans("RulesVATInProducts"); 209} 210if ($conf->global->TAX_MODE_SELL_SERVICE == 'invoice') { 211 $description .= '<br>'.$langs->trans("RulesVATDueServices"); 212} 213if ($conf->global->TAX_MODE_SELL_SERVICE == 'payment') { 214 $description .= '<br>'.$langs->trans("RulesVATInServices"); 215} 216if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { 217 $description .= '<br>'.$langs->trans("DepositsAreNotIncluded"); 218} 219if (!empty($conf->global->MAIN_MODULE_ACCOUNTING)) { 220 $description .= '<br>'.$langs->trans("ThisIsAnEstimatedValue"); 221} 222 223// Customers invoices 224$elementcust = $langs->trans("CustomersInvoices"); 225$productcust = $langs->trans("ProductOrService"); 226$amountcust = $langs->trans("AmountHT"); 227 228// Suppliers invoices 229$elementsup = $langs->trans("SuppliersInvoices"); 230$productsup = $productcust; 231$amountsup = $amountcust; 232$namesup = $namecust; 233 234 235 236// TODO Report from bookkeeping not yet available, so we switch on report on business events 237if ($modecompta == "BOOKKEEPING") { 238 $modecompta = "CREANCES-DETTES"; 239} 240if ($modecompta == "BOOKKEEPINGCOLLECTED") { 241 $modecompta = "RECETTES-DEPENSES"; 242} 243 244// Show report header 245if ($modecompta == "CREANCES-DETTES") { 246 $name = $langs->trans("Turnover").', '.$langs->trans("ByVatRate"); 247 $calcmode = $langs->trans("CalcModeDebt"); 248 //$calcmode.='<br>('.$langs->trans("SeeReportInInputOutputMode",'<a href="'.$_SERVER["PHP_SELF"].'?year='.$year_start.'&modecompta=RECETTES-DEPENSES">','</a>').')'; 249 250 $description = $langs->trans("RulesCADue"); 251 if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { 252 $description .= $langs->trans("DepositsAreNotIncluded"); 253 } else { 254 $description .= $langs->trans("DepositsAreIncluded"); 255 } 256 257 $builddate = dol_now(); 258} elseif ($modecompta == "RECETTES-DEPENSES") { 259 $name = $langs->trans("TurnoverCollected").', '.$langs->trans("ByVatRate"); 260 $calcmode = $langs->trans("CalcModeEngagement"); 261 //$calcmode.='<br>('.$langs->trans("SeeReportInDueDebtMode",'<a href="'.$_SERVER["PHP_SELF"].'?year='.$year_start.'&modecompta=CREANCES-DETTES">','</a>').')'; 262 263 $description = $langs->trans("RulesCAIn"); 264 $description .= $langs->trans("DepositsAreIncluded"); 265 266 $builddate = dol_now(); 267} elseif ($modecompta == "BOOKKEEPING") { 268} elseif ($modecompta == "BOOKKEEPINGCOLLECTED") { 269} 270$period = $form->selectDate($date_start, 'date_start', 0, 0, 0, '', 1, 0); 271$period .= ' - '; 272$period .= $form->selectDate($date_end, 'date_end', 0, 0, 0, '', 1, 0); 273if ($date_end == dol_time_plus_duree($date_start, 1, 'y') - 1) { 274 $periodlink = '<a href="'.$_SERVER["PHP_SELF"].'?year='.($year_start - 1).'&modecompta='.$modecompta.'">'.img_previous().'</a> <a href="'.$_SERVER["PHP_SELF"].'?year='.($year_start + 1).'&modecompta='.$modecompta.'">'.img_next().'</a>'; 275} else { 276 $periodlink = ''; 277} 278 279$description .= ' <input type="hidden" name="modecompta" value="'.$modecompta.'">'; 280 281report_header($name, '', $period, $periodlink, $description, $builddate, $exportlink, array(), $calcmode); 282 283if (!empty($conf->accounting->enabled) && $modecompta != 'BOOKKEEPING') { 284 print info_admin($langs->trans("WarningReportNotReliable"), 0, 0, 1); 285} 286 287 288if ($modecompta == 'CREANCES-DETTES') { 289 print '<table class="noborder centpercent">'; 290 print '<tr class="liste_titre"><td width="6%" class="right">'.$langs->trans("TurnoverbyVatrate").'</td>'; 291 print '<td class="left">'.$langs->trans("ProductOrService").'</td>'; 292 print '<td class="left">'.$langs->trans("Country").'</td>'; 293 $i = 0; 294 while ($i < 12) { 295 $j = $i + (empty($conf->global->SOCIETE_FISCAL_MONTH_START) ? 1 : $conf->global->SOCIETE_FISCAL_MONTH_START); 296 if ($j > 12) { 297 $j -= 12; 298 } 299 print '<td width="60" class="right">'.$langs->trans('MonthShort'.str_pad($j, 2, '0', STR_PAD_LEFT)).'</td>'; 300 $i++; 301 } 302 print '<td width="60" class="right"><b>'.$langs->trans("TotalHT").'</b></td></tr>'; 303 304 // Sales invoices 305 $sql = "SELECT fd.tva_tx AS vatrate,"; 306 $sql .= " fd.product_type AS product_type,"; 307 $sql .= " cc.code, cc.label AS country,"; 308 for ($i = 1; $i <= 12; $i++) { 309 $sql .= " SUM(".$db->ifsql('MONTH(f.datef)='.$i, 'fd.total_ht', '0').") AS month".str_pad($i, 2, '0', STR_PAD_LEFT).","; 310 } 311 $sql .= " SUM(fd.total_ht) as total"; 312 $sql .= " FROM ".MAIN_DB_PREFIX."facturedet as fd"; 313 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."facture as f ON f.rowid = fd.fk_facture"; 314 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe as soc ON soc.rowid = f.fk_soc"; 315 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as cc ON cc.rowid = soc.fk_pays"; 316 $sql .= " WHERE f.datef >= '".$db->idate($date_start)."'"; 317 $sql .= " AND f.datef <= '".$db->idate($date_end)."'"; 318 $sql .= " AND f.fk_statut in (1,2)"; 319 if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { 320 $sql .= " AND f.type IN (0,1,2,5)"; 321 } else { 322 $sql .= " AND f.type IN (0,1,2,3,5)"; 323 } 324 $sql .= " AND f.entity IN (".getEntity('invoice', 0).")"; 325 $sql .= " GROUP BY fd.tva_tx,fd.product_type, cc.label, cc.code "; 326 $sql .= " ORDER BY country, product_type, vatrate"; 327 328 dol_syslog("htdocs/compta/tva/index.php sql=".$sql, LOG_DEBUG); 329 $resql = $db->query($sql); 330 if ($resql) { 331 $num = $db->num_rows($resql); 332 $totalpermonth = array(); 333 while ($obj = $db->fetch_object($resql)) { 334 print '<tr class="oddeven"><td class="right">'.vatrate($obj->vatrate).'</td>'; 335 if ($obj->product_type == 0) { 336 print '<td class="left">'.$langs->trans("Product").'</td>'; 337 } else { 338 print '<td class="left">'.$langs->trans("Service").'</td>'; 339 } 340 // Country 341 print '<td>'; 342 print $langs->trans("Country".$obj->code) != "Country".$obj->code ? $langs->trans("Country".$obj->code) : $obj->country; 343 print '</td>'; 344 for ($i = 0; $i < 12; $i++) { 345 $j = $i + (empty($conf->global->SOCIETE_FISCAL_MONTH_START) ? 1 : $conf->global->SOCIETE_FISCAL_MONTH_START); 346 if ($j > 12) { 347 $j -= 12; 348 } 349 $monthj = 'month'.str_pad($j, 2, '0', STR_PAD_LEFT); 350 print '<td class="right" width="6%">'.price($obj->$monthj).'</td>'; 351 $totalpermonth[$j] = (empty($totalpermonth[$j]) ? 0 : $totalpermonth[$j]) + $obj->$monthj; 352 } 353 print '<td class="right" width="6%"><b>'.price($obj->total).'</b></td>'; 354 $totalpermonth['total'] = (empty($totalpermonth['total']) ? 0 : $totalpermonth['total']) + $obj->total; 355 print '</tr>'; 356 } 357 $db->free($resql); 358 359 // Total 360 print '<tr class="liste_total"><td class="right"></td>'; 361 print '<td class="left"></td>'; 362 print '<td></td>'; 363 for ($i = 0; $i < 12; $i++) { 364 $j = $i + (empty($conf->global->SOCIETE_FISCAL_MONTH_START) ? 1 : $conf->global->SOCIETE_FISCAL_MONTH_START); 365 if ($j > 12) { 366 $j -= 12; 367 } 368 $monthj = 'month'.str_pad($j, 2, '0', STR_PAD_LEFT); 369 print '<td class="right" width="6%">'.price($totalpermonth[$j]).'</td>'; 370 } 371 print '<td class="right" width="6%"><b>'.price($totalpermonth['total']).'</b></td>'; 372 print '</tr>'; 373 } else { 374 print $db->lasterror(); // Show last sql error 375 } 376 377 print '<tr class="liste_titre"><td width="6%" class="right">'.$langs->trans("PurchasebyVatrate").'</td>'; 378 print '<td class="left">'.$langs->trans("ProductOrService").'</td>'; 379 print '<td class="left">'.$langs->trans("Country").'</td>'; 380 $i = 0; 381 while ($i < 12) { 382 $j = $i + (empty($conf->global->SOCIETE_FISCAL_MONTH_START) ? 1 : $conf->global->SOCIETE_FISCAL_MONTH_START); 383 if ($j > 12) { 384 $j -= 12; 385 } 386 print '<td width="60" class="right">'.$langs->trans('MonthShort'.str_pad($j, 2, '0', STR_PAD_LEFT)).'</td>'; 387 $i++; 388 } 389 print '<td width="60" class="right"><b>'.$langs->trans("TotalHT").'</b></td></tr>'; 390 391 // Purchase invoices 392 $sql2 = "SELECT ffd.tva_tx AS vatrate,"; 393 $sql2 .= " ffd.product_type AS product_type,"; 394 $sql2 .= " cc.code, cc.label AS country,"; 395 for ($i = 1; $i <= 12; $i++) { 396 $sql2 .= " SUM(".$db->ifsql('MONTH(ff.datef)='.$i, 'ffd.total_ht', '0').") AS month".str_pad($i, 2, '0', STR_PAD_LEFT).","; 397 } 398 $sql2 .= " SUM(ffd.total_ht) as total"; 399 $sql2 .= " FROM ".MAIN_DB_PREFIX."facture_fourn_det as ffd"; 400 $sql2 .= " INNER JOIN ".MAIN_DB_PREFIX."facture_fourn as ff ON ff.rowid = ffd.fk_facture_fourn"; 401 $sql2 .= " INNER JOIN ".MAIN_DB_PREFIX."societe as soc ON soc.rowid = ff.fk_soc"; 402 $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as cc ON cc.rowid = soc.fk_pays"; 403 $sql2 .= " WHERE ff.datef >= '".$db->idate($date_start)."'"; 404 $sql2 .= " AND ff.datef <= '".$db->idate($date_end)."'"; 405 $sql .= " AND ff.fk_statut in (1,2)"; 406 if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { 407 $sql .= " AND ff.type IN (0,1,2,5)"; 408 } else { 409 $sql .= " AND ff.type IN (0,1,2,3,5)"; 410 } 411 $sql2 .= " AND ff.entity IN (".getEntity("facture_fourn", 0).")"; 412 $sql2 .= " GROUP BY ffd.tva_tx, ffd.product_type, cc.label, cc.code "; 413 $sql2 .= " ORDER BY country, product_type, vatrate"; 414 415 //print $sql2; 416 dol_syslog("htdocs/compta/tva/index.php sql=".$sql, LOG_DEBUG); 417 $resql2 = $db->query($sql2); 418 if ($resql2) { 419 $num = $db->num_rows($resql2); 420 $totalpermonth = array(); 421 while ($obj = $db->fetch_object($resql2)) { 422 print '<tr class="oddeven"><td class="right">'.vatrate($obj->vatrate).'</td>'; 423 if ($obj->product_type == 0) { 424 print '<td class="left">'.$langs->trans("Product").'</td>'; 425 } else { 426 print '<td class="left">'.$langs->trans("Service").'</td>'; 427 } 428 print '<td>'; 429 print $langs->trans("Country".$obj->code) != "Country".$obj->code ? $langs->trans("Country".$obj->code) : $obj->country; 430 print '</td>'; 431 for ($i = 0; $i < 12; $i++) { 432 $j = $i + (empty($conf->global->SOCIETE_FISCAL_MONTH_START) ? 1 : $conf->global->SOCIETE_FISCAL_MONTH_START); 433 if ($j > 12) { 434 $j -= 12; 435 } 436 $monthj = 'month'.str_pad($j, 2, '0', STR_PAD_LEFT); 437 print '<td class="right" width="6%">'.price($obj->$monthj).'</td>'; 438 $totalpermonth[$j] = (empty($totalpermonth[$j]) ? 0 : $totalpermonth[$j]) + $obj->$monthj; 439 } 440 print '<td class="right" width="6%"><b>'.price($obj->total).'</b></td>'; 441 $totalpermonth['total'] = (empty($totalpermonth['total']) ? 0 : $totalpermonth['total']) + $obj->total; 442 print '</tr>'; 443 } 444 $db->free($resql2); 445 446 // Total 447 print '<tr class="liste_total"><td class="right"></td>'; 448 print '<td class="left"></td>'; 449 print '<td></td>'; 450 for ($i = 0; $i < 12; $i++) { 451 $j = $i + (empty($conf->global->SOCIETE_FISCAL_MONTH_START) ? 1 : $conf->global->SOCIETE_FISCAL_MONTH_START); 452 if ($j > 12) { 453 $j -= 12; 454 } 455 $monthj = 'month'.str_pad($j, 2, '0', STR_PAD_LEFT); 456 print '<td class="right" width="6%">'.price($totalpermonth[$j]).'</td>'; 457 } 458 print '<td class="right" width="6%"><b>'.price($totalpermonth['total']).'</b></td>'; 459 print '</tr>'; 460 } else { 461 print $db->lasterror(); // Show last sql error 462 } 463 print "</table>\n"; 464} else { 465 // $modecompta != 'CREANCES-DETTES' 466 // "Calculation of part of each product for accountancy in this mode is not possible. When a partial payment (for example 5 euros) is done on an 467 // invoice with 2 product (product A for 10 euros and product B for 20 euros), what is part of paiment for product A and part of paiment for product B ? 468 // Because there is no way to know this, this report is not relevant. 469 print '<br>'.$langs->trans("TurnoverPerSaleTaxRateInCommitmentAccountingNotRelevant").'<br>'; 470} 471 472// End of page 473llxFooter(); 474$db->close(); 475