* * GPL v3 (siehe COPYING). */ /** * \file htdocs/custom/mahnung/ajax/createmahnung.php * \ingroup mahnung * \brief AJAX-Endpoint: Mahnung(en) zu Rechnung(en) erzeugen + PDF generieren. * * Akzeptiert sowohl klassische Form-POSTs (Browser-Submit aus list.php) * als auch AJAX-Calls. Antwortet je nach Accept-Header HTML-Redirect * oder JSON. * * POST: * - facture_ids[] Array Rechnungs-IDs (oder einzelne facture_id) * - stufe Optional: Stufe erzwingen (sonst Vorschlag-Logik) * - token CSRF */ if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); ob_start(); require_once $_SERVER['DOCUMENT_ROOT'].'/main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php'; require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php'; require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungvorschlag.class.php'; require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungpdf.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; global $db, $user, $langs, $conf; $langs->loadLangs(array('mahnung@mahnung')); /** * @param bool $success * @param string $message * @param array $extra */ function respond($success, $message, $extra = array()) { $wantsJson = false; if (!empty($_SERVER['HTTP_ACCEPT']) && stripos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false) { $wantsJson = true; } if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') { $wantsJson = true; } while (ob_get_level() > 0) { ob_end_clean(); } if ($wantsJson) { header('Content-Type: application/json; charset=utf-8'); echo json_encode(array_merge(array('success' => (bool) $success, 'message' => $message), $extra)); exit; } // Klassischer Submit -> Redirect zur Liste mit Flash-Message global $user; if (function_exists('setEventMessages')) { setEventMessages($message, null, $success ? 'mesgs' : 'errors'); } header('Location: '.DOL_URL_ROOT.'/custom/mahnung/list.php?mode=vorschlag'); exit; } // 1) CSRF $postedToken = GETPOST('token', 'alphanohtml'); if (empty($postedToken) || empty($_SESSION['newtoken']) || $postedToken !== $_SESSION['newtoken']) { respond(false, 'Token-Verifikation fehlgeschlagen (CSRF).', array('code' => 'csrf')); } // 2) Permission if (!$user->hasRight('mahnung', 'write')) { respond(false, $langs->transnoentities('NotEnoughPermissions') ?: 'Nicht berechtigt.', array('code' => 'forbidden')); } // 3) Input $factureIds = GETPOST('facture_ids', 'array:int'); if (empty($factureIds)) { $single = GETPOSTINT('facture_id'); if (!empty($single)) { $factureIds = array($single); } } $factureIds = array_values(array_unique(array_map('intval', $factureIds))); $factureIds = array_filter($factureIds, function ($v) { return $v > 0; }); if (empty($factureIds)) { respond(false, 'Keine Rechnungen ausgewaehlt.', array('code' => 'noinput')); } $forceStufe = GETPOSTINT('stufe'); $forceStufe = ($forceStufe >= 1 && $forceStufe <= 3) ? $forceStufe : 0; // 4) Verarbeitung — pro Rechnung Vorschlag holen, Mahnung erzeugen, PDF generieren $service = new MahnungVorschlag($db); $pdfGen = new MahnungPdf($db); $basiszins = (float) getDolGlobalString('MAHNUNG_BASISZINS', '1.27'); $created = 0; $skipped = 0; $failed = array(); foreach ($factureIds as $fid) { $rows = $service->getVorschlaege(array('soc_id' => 0)); // ohne Filter holen $row = null; foreach ($rows as $r) { if ((int) $r['facture_id'] === (int) $fid) { $row = $r; break; } } if ($row === null) { // Keine offene Mahnungs-Empfehlung — z.B. weil Wartefrist noch laeuft $skipped++; continue; } $stufeNr = $forceStufe ?: (int) $row['vorgeschlagene_stufe']; $stufe = $service->getStufe($stufeNr); if ($stufe === null) { $failed[] = 'Rechnung #'.$fid.': Stufe '.$stufeNr.' nicht konfiguriert'; continue; } $mahnung = new Mahnung($db); $mahnung->fk_facture = $fid; $mahnung->fk_soc = (int) $row['soc_id']; $mahnung->stufe = $stufeNr; $mahnung->date_mahnung = dol_now(); $mahnung->date_lim_reglement_alt = $row['facture_date_lim_reglement']; $mahnung->date_lim_reglement_neu = dol_time_plus_duree(dol_now(), (int) $stufe->neue_frist_tage, 'd'); $mahnung->betrag_offen = (float) $row['betrag_offen']; $mahnung->customertype = $row['kundentyp']; $mahnung->basiszins_snapshot = $basiszins; $mahnung->versandart = $stufe->versandart_default ?: Mahnung::VERSAND_PDF; // Gebuehren + Pauschale $mahnung->mahngebuehr = $stufe->getMahngebuehr($mahnung->customertype); // §288 Abs. 5 Pauschale: nur einmal pro Rechnung B2B (in Stufe mit pauschale_b2b_einmalig=1) if ($mahnung->customertype === Mahnung::KUNDENTYP_B2B && (int) $stufe->pauschale_b2b_einmalig === 1) { $alreadyApplied = pauschaleBereitsAngewendet($db, (int) $fid); if (!$alreadyApplied) { $mahnung->pauschale_b2b = (float) getDolGlobalString('MAHNUNG_PAUSCHALE_B2B', '40.00'); } } // Verzugszinsen $override = $stufe->getZinssatzOverride($mahnung->customertype); $mahnung->verzugszinsen = Mahnung::berechneVerzugszinsen( $mahnung->betrag_offen, (int) $row['tage_verzug'], $mahnung->customertype, $basiszins, $override ); $mahnung->rechneSumme(); $mahnung->status = Mahnung::STATUS_ERSTELLT; $newId = $mahnung->create($user); if ($newId <= 0) { $failed[] = 'Rechnung #'.$fid.': '.$mahnung->error; continue; } $pdfPath = $pdfGen->generate($mahnung, $user); if ($pdfPath === false) { $failed[] = 'Rechnung #'.$fid.' (Mahnung '.$mahnung->ref.'): PDF-Fehler '.$pdfGen->error; continue; } $created++; } $msg = $created.' Mahnung(en) erstellt'; if ($skipped > 0) { $msg .= ', '.$skipped.' uebersprungen (Wartefrist)'; } if (!empty($failed)) { $msg .= ' — Fehler: '.implode(' | ', $failed); respond(false, $msg, array('created' => $created, 'failed' => $failed)); } respond(true, $msg, array('created' => $created, 'skipped' => $skipped)); /** * Prueft, ob fuer eine Rechnung bereits in einer aktiven Mahnung die §288-B2B-Pauschale gesetzt wurde. * * @param DoliDB $db * @param int $factureId * @return bool */ function pauschaleBereitsAngewendet($db, $factureId) { $sql = "SELECT 1 FROM ".MAIN_DB_PREFIX."mahnung_mahnung"; $sql .= " WHERE fk_facture = ".((int) $factureId); $sql .= " AND status NOT IN (".Mahnung::STATUS_STORNIERT.")"; $sql .= " AND pauschale_b2b > 0"; $sql .= " LIMIT 1"; $resql = $db->query($sql); if (!$resql) { return false; } $has = (bool) $db->num_rows($resql); $db->free($resql); return $has; }