Die Marke stand bisher nur in der Web-Ansicht; auf dem Ausdruck, den die Mitglieder taeglich vor sich haben, fehlte sie. Sie erscheint jetzt unten rechts im Seitenfuss - nach derselben Regel wie im Web: im kostenlosen Tarif fest, sonst nach Mandant-Einstellung. Die Tasse wird mit TCPDFs Zeichenbefehlen gemalt statt als SVG oder Bild eingebettet: ImageSVG braucht die XML-Extension, ein Rasterbild GD - beides ist auf einem Webspace nicht garantiert. Der Schriftzug sitzt in einer Cell() statt in Text(): dessen y-Bezug haengt an Schriftmetriken und ergab in der Probe einen um Millimeter versetzten Schriftzug. Steht die Marke, reserviert export_page_row_budget_mm() 6 mm am Seitenfuss, damit die Tabelle nicht hineinlaeuft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
121 lines
4.1 KiB
PHP
121 lines
4.1 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
require_once __DIR__ . '/bootstrap.php';
|
||
|
||
/**
|
||
* Wasserzeichen des kostenlosen Tarifs: eine kleine Marke unten rechts, die
|
||
* auf die Kaffeeliste verweist. Sie erscheint nur im Tarif "free" - wer
|
||
* zahlt, bekommt seine Oberflaeche ohne fremdes Logo.
|
||
*
|
||
* Bewusst getrennt von app/branding.php: dort geht es um das Logo *des
|
||
* Mandanten*, hier um das Logo *des Anbieters*. Beide koennen gleichzeitig
|
||
* sichtbar sein (Kopfzeile oben, Wasserzeichen unten rechts).
|
||
*/
|
||
|
||
/**
|
||
* Tarif eines Mandanten, ohne Seiteneffekt. Absichtlich nicht
|
||
* billing_fetch_or_init(): das Wasserzeichen wird auf jeder Seite geprueft
|
||
* und darf dabei keine Zeile anlegen. Fehlt der Datensatz, gilt - wie beim
|
||
* Anlegen - "free".
|
||
*/
|
||
function plan_watermark_plan_code(PDO $pdo, int $tenantId): string
|
||
{
|
||
static $cache = [];
|
||
|
||
if (array_key_exists($tenantId, $cache)) {
|
||
return $cache[$tenantId];
|
||
}
|
||
|
||
try {
|
||
$stmt = $pdo->prepare('SELECT plan_code FROM tenant_billing WHERE tenant_id = ?');
|
||
$stmt->execute([$tenantId]);
|
||
$planCode = $stmt->fetchColumn();
|
||
$cache[$tenantId] = $planCode === false ? 'free' : (string)$planCode;
|
||
} catch (Throwable $e) {
|
||
// Laesst sich der Tarif nicht lesen, bleibt die Oberflaeche sauber -
|
||
// ein Wasserzeichen bei einem zahlenden Kunden waere der schlimmere
|
||
// Fehler als ein fehlendes bei einem kostenlosen.
|
||
$cache[$tenantId] = 'unknown';
|
||
}
|
||
|
||
return $cache[$tenantId];
|
||
}
|
||
|
||
/**
|
||
* Zeigt dieser Mandant das Wasserzeichen? Im kostenlosen Tarif immer - es ist
|
||
* der Gegenwert fuer die kostenlose Nutzung und deshalb nicht abschaltbar.
|
||
* Alle anderen entscheiden ueber die Mandant-Einstellung
|
||
* `watermark_enabled` (Standard: an).
|
||
*/
|
||
function plan_watermark_visible(PDO $pdo, int $tenantId): bool
|
||
{
|
||
if ($tenantId <= 0) {
|
||
return false;
|
||
}
|
||
|
||
$planCode = plan_watermark_plan_code($pdo, $tenantId);
|
||
if ($planCode === 'free') {
|
||
return true;
|
||
}
|
||
|
||
if ($planCode === 'unknown') {
|
||
return false;
|
||
}
|
||
|
||
require_once __DIR__ . '/features.php';
|
||
|
||
return app_tenant_switch_enabled($pdo, $tenantId, 'watermark_enabled');
|
||
}
|
||
|
||
/**
|
||
* Wortmarke der Kaffeeliste als Inline-SVG. Als Inline-Grafik statt als
|
||
* Bilddatei, damit das Wasserzeichen ohne zusaetzlichen Request auskommt,
|
||
* auf jedem Bildschirm scharf bleibt und die Farbe der Umgebung uebernimmt.
|
||
*/
|
||
function plan_watermark_logo_svg(): string
|
||
{
|
||
return '<svg class="plan-watermark-logo" viewBox="0 0 24 24" width="18" height="18" '
|
||
. 'aria-hidden="true" focusable="false" fill="none" stroke="currentColor" '
|
||
. 'stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">'
|
||
. '<path d="M4 9h13v6a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V9Z"/>'
|
||
. '<path d="M17 10.5h1.5a2.5 2.5 0 0 1 0 5H17"/>'
|
||
. '<path d="M8 5.5c0-1 1-1.4 1-2.5M12 5.5c0-1 1-1.4 1-2.5"/>'
|
||
. '</svg>';
|
||
}
|
||
|
||
/**
|
||
* Beschriftung des Wasserzeichens: die Marketing-Domain ohne Schema
|
||
* ("kaffeeliste.de"). Laesst sie sich nicht ermitteln, bleibt der Name der
|
||
* App uebrig. Wird von der Web-Ansicht und vom PDF-Ausdruck gemeinsam
|
||
* genutzt, damit beide dieselbe Adresse nennen.
|
||
*/
|
||
function plan_watermark_label(): string
|
||
{
|
||
$url = app_marketing_url();
|
||
|
||
return $url !== '' ? (string)preg_replace('#^https?://#i', '', $url) : 'Kaffeeliste';
|
||
}
|
||
|
||
/**
|
||
* Markup des Wasserzeichens. Ohne erreichbare Marketing-Domain (CLI,
|
||
* ungewoehnliche Hosts) bleibt es bei Logo und Namen ohne Link - ein
|
||
* Verweis ins Leere waere schlechter als keiner.
|
||
*/
|
||
function plan_watermark_html(): string
|
||
{
|
||
$url = app_marketing_url();
|
||
$label = plan_watermark_label();
|
||
$inner = plan_watermark_logo_svg()
|
||
. '<span class="plan-watermark-text">' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</span>';
|
||
|
||
if ($url === '') {
|
||
return '<div class="plan-watermark" title="Kaffeeliste – die digitale Kaffeekasse">' . $inner . '</div>';
|
||
}
|
||
|
||
return '<a class="plan-watermark" href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '"'
|
||
. ' target="_blank" rel="noopener noreferrer"'
|
||
. ' title="Kaffeeliste – die digitale Kaffeekasse">' . $inner . '</a>';
|
||
}
|