All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Vollstaendiges 3-stufiges Mahnwesen nach BGB §288: - SQL-Schema (llx_mahnung_mahnung, llx_mahnung_stufe) - CRUD-Klassen (Mahnung, MahnungStufe, MahnungVorschlag) - TCPDF DIN-5008 PDF-Generierung - Verzugszinsberechnung B2C/B2B + §288 Abs.5 Pauschale - Trigger: offene Mahnungen bei Zahlungseingang schliessen - Hook: Tab + Button auf Rechnungs-/Kundenkarte - Cron: taegl. Vorschlagsliste + Ntfy-Push - Deploy-Pipeline (.forgejo/workflows/deploy.yml) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
154 lines
4.5 KiB
PHP
154 lines
4.5 KiB
PHP
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* GPL v3 (siehe COPYING).
|
|
*/
|
|
|
|
/**
|
|
* \file htdocs/custom/mahnung/ajax/sendmail.php
|
|
* \ingroup mahnung
|
|
* \brief AJAX-Endpoint: Mahnung per E-Mail an Kunde senden.
|
|
*
|
|
* POST:
|
|
* mahnung_id ID des Mahnvorgangs (PDF muss existieren)
|
|
* token CSRF
|
|
*
|
|
* Response: JSON {success, message}
|
|
*/
|
|
|
|
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.'/core/class/CMailFile.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php';
|
|
|
|
global $db, $user, $langs, $conf, $mysoc;
|
|
$langs->loadLangs(array('mahnung@mahnung'));
|
|
|
|
/**
|
|
* @param bool $success
|
|
* @param string $message
|
|
*/
|
|
function jsonExit($success, $message)
|
|
{
|
|
while (ob_get_level() > 0) {
|
|
ob_end_clean();
|
|
}
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
echo json_encode(array('success' => (bool) $success, 'message' => $message));
|
|
exit;
|
|
}
|
|
|
|
// CSRF
|
|
$postedToken = GETPOST('token', 'alphanohtml');
|
|
if (empty($postedToken) || empty($_SESSION['newtoken']) || $postedToken !== $_SESSION['newtoken']) {
|
|
jsonExit(false, 'CSRF-Token ungueltig.');
|
|
}
|
|
|
|
if (!$user->hasRight('mahnung', 'send')) {
|
|
jsonExit(false, 'Nicht berechtigt (mahnung.send).');
|
|
}
|
|
|
|
$mahnungId = GETPOSTINT('mahnung_id');
|
|
if ($mahnungId <= 0) {
|
|
jsonExit(false, 'mahnung_id fehlt.');
|
|
}
|
|
|
|
$mahnung = new Mahnung($db);
|
|
if ($mahnung->fetch($mahnungId) <= 0) {
|
|
jsonExit(false, 'Mahnung '.$mahnungId.' nicht gefunden.');
|
|
}
|
|
|
|
if (empty($mahnung->pdf_path) || !file_exists($mahnung->pdf_path)) {
|
|
jsonExit(false, 'PDF zur Mahnung '.$mahnung->ref.' fehlt — bitte zuerst Mahnung erzeugen.');
|
|
}
|
|
|
|
$societe = new Societe($db);
|
|
if ($societe->fetch((int) $mahnung->fk_soc) <= 0) {
|
|
jsonExit(false, 'Kunde nicht ladbar.');
|
|
}
|
|
$toEmail = trim((string) ($societe->email ?? ''));
|
|
if (empty($toEmail)) {
|
|
jsonExit(false, 'Kunde hat keine E-Mail-Adresse hinterlegt.');
|
|
}
|
|
|
|
$facture = new Facture($db);
|
|
$facture->fetch((int) $mahnung->fk_facture);
|
|
|
|
$stufeObj = new MahnungStufe($db);
|
|
$stufeObj->fetchByStufe((int) $mahnung->stufe);
|
|
|
|
$replacements = array(
|
|
'{ref}' => $mahnung->ref,
|
|
'{stufe}' => (string) (int) $mahnung->stufe,
|
|
'{summe}' => price((float) $mahnung->summe_mahnung).' EUR',
|
|
'{rechnung}' => $facture->ref ?? '',
|
|
'{frist}' => dol_print_date($mahnung->date_lim_reglement_neu, 'day'),
|
|
'{kunde}' => $societe->name ?? '',
|
|
);
|
|
|
|
$subject = strtr($stufeObj->email_subject ?: 'Mahnung {stufe} zu Rechnung {rechnung}', $replacements);
|
|
$body = strtr($stufeObj->email_body ?: defaultMailBody((int) $mahnung->stufe), $replacements);
|
|
|
|
$fromEmail = $mysoc->email ?? getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
|
|
$fromName = $mysoc->name ?? '';
|
|
$from = !empty($fromName) ? $fromName.' <'.$fromEmail.'>' : $fromEmail;
|
|
|
|
$attachments = array($mahnung->pdf_path);
|
|
$mimes = array('application/pdf');
|
|
$names = array(basename($mahnung->pdf_path));
|
|
|
|
$mailFile = new CMailFile(
|
|
$subject,
|
|
$toEmail,
|
|
$from,
|
|
$body,
|
|
$attachments,
|
|
$mimes,
|
|
$names,
|
|
'',
|
|
'',
|
|
0,
|
|
1
|
|
);
|
|
|
|
if (!$mailFile->error) {
|
|
if ($mailFile->sendfile()) {
|
|
$mahnung->status = Mahnung::STATUS_VERSENDET;
|
|
$mahnung->update($user);
|
|
jsonExit(true, 'E-Mail an '.$toEmail.' gesendet.');
|
|
}
|
|
}
|
|
jsonExit(false, 'E-Mail-Versand fehlgeschlagen: '.$mailFile->error);
|
|
|
|
/**
|
|
* Default-Body je Stufe.
|
|
*
|
|
* @param int $stufe
|
|
* @return string
|
|
*/
|
|
function defaultMailBody($stufe)
|
|
{
|
|
switch ((int) $stufe) {
|
|
case 1:
|
|
return "Sehr geehrter Kunde,\n\nanbei senden wir Ihnen eine freundliche Zahlungserinnerung zu Rechnung {rechnung}.\n"
|
|
. "Offener Betrag inkl. evtl. Zinsen: {summe}.\n"
|
|
. "Wir bitten um Begleichung bis spaetestens {frist}.\n\n"
|
|
. "Mit freundlichen Gruessen";
|
|
case 2:
|
|
return "Sehr geehrter Kunde,\n\nanbei die 1. Mahnung zur Rechnung {rechnung}.\n"
|
|
. "Bitte ueberweisen Sie {summe} bis zum {frist}.\n\n"
|
|
. "Mit freundlichen Gruessen";
|
|
case 3:
|
|
default:
|
|
return "Sehr geehrter Kunde,\n\nanbei die letzte Mahnung zur Rechnung {rechnung}.\n"
|
|
. "Falls der Betrag von {summe} nicht bis zum {frist} eingeht, leiten wir gerichtliche Schritte ein.\n\n"
|
|
. "Mit freundlichen Gruessen";
|
|
}
|
|
}
|