dolibarr.bankimport/js/bankimport_notify.js.php
data 94efa59df3 v1.7: Multi-invoice payments and payment unlinking
- Add multi-invoice payment support (link one bank transaction to multiple invoices)
- Add payment unlinking feature to correct wrong matches
- Show linked payments, invoices and bank entries in transaction detail view
- Allow linking already paid invoices to bank transactions
- Update README with new features
- Add CHANGELOG.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-20 09:00:05 +01:00

174 lines
4.8 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
/**
* JavaScript for browser push notifications about incoming payments
* Loaded on every Dolibarr page via module_parts['js']
*/
// Define MIME type
if (!defined('NOTOKENRENEWAL')) {
define('NOTOKENRENEWAL', '1');
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
if (!defined('NOREQUIREHTML')) {
define('NOREQUIREHTML', '1');
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
header('Content-Type: application/javascript; charset=UTF-8');
header('Cache-Control: max-age=3600');
if (!isModEnabled('bankimport') || empty($user->id) || !$user->hasRight('bankimport', 'read')) {
echo '/* bankimport: no access */';
exit;
}
$checkUrl = dol_buildpath('/bankimport/ajax/checkpending.php', 1);
$confirmUrl = dol_buildpath('/bankimport/confirm.php', 1).'?mainmenu=bank&leftmenu=bankimport';
$checkInterval = 5 * 60 * 1000; // 5 Minuten
?>
(function() {
'use strict';
var STORAGE_KEY = 'bankimport_last_pending';
var CHECK_URL = <?php echo json_encode($checkUrl); ?>;
var CONFIRM_URL = <?php echo json_encode($confirmUrl); ?>;
var CHECK_INTERVAL = <?php echo $checkInterval; ?>;
// Erst nach Seitenload starten
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
function init() {
// Berechtigung anfragen beim ersten Mal
if ('Notification' in window && Notification.permission === 'default') {
// Dezent um Berechtigung bitten - nicht sofort, sondern nach 10 Sekunden
setTimeout(function() {
Notification.requestPermission();
}, 10000);
}
// Sofort prüfen
checkPending();
// Regelmäßig prüfen
setInterval(checkPending, CHECK_INTERVAL);
}
function checkPending() {
var xhr = new XMLHttpRequest();
xhr.open('GET', CHECK_URL, true);
xhr.timeout = 15000;
xhr.onload = function() {
if (xhr.status !== 200) return;
try {
var data = JSON.parse(xhr.responseText);
} catch(e) {
return;
}
var lastKnown = parseInt(localStorage.getItem(STORAGE_KEY) || '0', 10);
var currentPending = data.pending || 0;
var incoming = data.incoming || 0;
var incomingTotal = data.incoming_total || 0;
// Neue Buchungen seit letztem Check?
if (currentPending > lastKnown && currentPending > 0) {
var newCount = currentPending - lastKnown;
if (incoming > 0) {
showNotification(
'Zahlungseingang',
incoming + ' Zahlungseingang' + (incoming > 1 ? 'e' : '') + ' (' + formatAmount(incomingTotal) + ' €)\nBestätigung erforderlich',
'incoming'
);
} else {
showNotification(
'Bankimport',
newCount + ' neue Buchung' + (newCount > 1 ? 'en' : '') + ' warten auf Zuordnung',
'pending'
);
}
}
// Aktuellen Stand merken
localStorage.setItem(STORAGE_KEY, currentPending.toString());
};
xhr.onerror = function() {};
xhr.send();
}
function showNotification(title, body, type) {
if (!('Notification' in window)) return;
if (Notification.permission !== 'granted') return;
var icon = type === 'incoming'
? '/theme/common/mime/money.png'
: '/theme/common/mime/doc.png';
var notification = new Notification(title, {
body: body,
icon: icon,
tag: 'bankimport-' + type,
requireInteraction: true
});
notification.onclick = function() {
window.focus();
window.location.href = CONFIRM_URL;
notification.close();
};
// Nach 30 Sekunden automatisch schließen
setTimeout(function() {
notification.close();
}, 30000);
}
function formatAmount(amount) {
return parseFloat(amount).toFixed(2).replace('.', ',').replace(/\B(?=(\d{3})+(?!\d))/g, '.');
}
})();