importzugferd/class/importnotification.class.php
2026-02-01 09:25:12 +01:00

389 lines
13 KiB
PHP

<?php
/* Copyright (C) 2026 ZUGFeRD Import Module
*
* 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.
*/
/**
* \file class/importnotification.class.php
* \ingroup importzugferd
* \brief Email notification class for ZUGFeRD imports
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
/**
* Class ImportNotification
* Handles email notifications for ZUGFeRD import events
*/
class ImportNotification
{
/**
* @var DoliDB Database handler
*/
public $db;
/**
* @var string Error message
*/
public $error = '';
/**
* @var array Error messages
*/
public $errors = array();
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
$this->db = $db;
}
/**
* Check if notifications are enabled
*
* @return bool True if enabled
*/
public function isEnabled()
{
return getDolGlobalString('IMPORTZUGFERD_NOTIFY_ENABLED') && getDolGlobalString('IMPORTZUGFERD_NOTIFY_EMAIL');
}
/**
* Get notification email address
*
* @return string Email address
*/
public function getNotifyEmail()
{
return getDolGlobalString('IMPORTZUGFERD_NOTIFY_EMAIL');
}
/**
* Send notification for manual intervention required
*
* @param ZugferdImport $import Import object
* @param array $lines Import lines
* @return int 1 if sent, 0 if not needed, -1 on error
*/
public function sendManualInterventionNotification($import, $lines = array())
{
global $conf, $langs;
if (!$this->isEnabled() || !getDolGlobalString('IMPORTZUGFERD_NOTIFY_MANUAL')) {
return 0;
}
$langs->load('importzugferd@importzugferd');
$subject = $langs->trans('NotifySubjectManualIntervention', $import->invoice_number);
$body = $langs->trans('NotifyBodyManualIntervention', $import->invoice_number, $import->seller_name);
$body .= "\n\n";
$body .= $langs->trans('InvoiceNumber').': '.$import->invoice_number."\n";
$body .= $langs->trans('Supplier').': '.$import->seller_name."\n";
$body .= $langs->trans('InvoiceDate').': '.dol_print_date($import->invoice_date, 'day')."\n";
$body .= $langs->trans('TotalTTC').': '.price($import->total_ttc).' '.$import->currency."\n";
$body .= "\n";
// List issues
$missingProducts = 0;
$missingSupplier = ($import->fk_soc <= 0);
if (!empty($lines)) {
foreach ($lines as $line) {
if ($line->fk_product <= 0) {
$missingProducts++;
}
}
}
if ($missingSupplier) {
$body .= "- ".$langs->trans('SupplierNotAssigned')."\n";
}
if ($missingProducts > 0) {
$body .= "- ".$missingProducts." ".$langs->trans('ProductsNotAssigned')."\n";
}
$body .= "\n";
$body .= $langs->trans('NotifyLinkToImport').': '.dol_buildpath('/importzugferd/import.php', 2).'?action=edit&id='.$import->id;
return $this->sendEmail($subject, $body);
}
/**
* Send notification for import error
*
* @param ZugferdImport $import Import object (may be partial)
* @param string $errorMessage Error message
* @param string $filename Original filename
* @return int 1 if sent, 0 if not needed, -1 on error
*/
public function sendErrorNotification($import, $errorMessage, $filename = '')
{
global $conf, $langs;
if (!$this->isEnabled() || !getDolGlobalString('IMPORTZUGFERD_NOTIFY_ERROR')) {
return 0;
}
$langs->load('importzugferd@importzugferd');
$invoiceNum = !empty($import->invoice_number) ? $import->invoice_number : $filename;
$subject = $langs->trans('NotifySubjectError', $invoiceNum);
$body = $langs->trans('NotifyBodyError', $invoiceNum);
$body .= "\n\n";
if (!empty($import->invoice_number)) {
$body .= $langs->trans('InvoiceNumber').': '.$import->invoice_number."\n";
}
if (!empty($import->seller_name)) {
$body .= $langs->trans('Supplier').': '.$import->seller_name."\n";
}
if (!empty($filename)) {
$body .= $langs->trans('File').': '.$filename."\n";
}
$body .= "\n";
$body .= $langs->trans('ErrorMessage').":\n";
$body .= $errorMessage."\n";
if ($import->id > 0) {
$body .= "\n";
$body .= $langs->trans('NotifyLinkToImport').': '.dol_buildpath('/importzugferd/import.php', 2).'?action=edit&id='.$import->id;
}
return $this->sendEmail($subject, $body);
}
/**
* Send notification for significant price differences
*
* @param ZugferdImport $import Import object
* @param array $priceDiffs Array of price differences: array of ['line' => ImportLine, 'product' => Product, 'old_price' => float, 'new_price' => float, 'diff_percent' => float]
* @return int 1 if sent, 0 if not needed, -1 on error
*/
public function sendPriceDifferenceNotification($import, $priceDiffs)
{
global $conf, $langs;
if (!$this->isEnabled() || !getDolGlobalString('IMPORTZUGFERD_NOTIFY_PRICE_DIFF')) {
return 0;
}
if (empty($priceDiffs)) {
return 0;
}
$langs->load('importzugferd@importzugferd');
$threshold = getDolGlobalInt('IMPORTZUGFERD_PRICE_DIFF_THRESHOLD', 10);
$subject = $langs->trans('NotifySubjectPriceDiff', $import->invoice_number, count($priceDiffs));
$body = $langs->trans('NotifyBodyPriceDiff', $import->invoice_number, $import->seller_name, $threshold);
$body .= "\n\n";
$body .= $langs->trans('InvoiceNumber').': '.$import->invoice_number."\n";
$body .= $langs->trans('Supplier').': '.$import->seller_name."\n";
$body .= $langs->trans('InvoiceDate').': '.dol_print_date($import->invoice_date, 'day')."\n";
$body .= "\n";
// Table header
$body .= str_pad($langs->trans('Product'), 40)." | ";
$body .= str_pad($langs->trans('OldPrice'), 12)." | ";
$body .= str_pad($langs->trans('NewPrice'), 12)." | ";
$body .= str_pad($langs->trans('Difference'), 10)."\n";
$body .= str_repeat('-', 80)."\n";
// List products with price differences
foreach ($priceDiffs as $diff) {
$productName = $diff['product']->ref.' - '.$diff['product']->label;
if (strlen($productName) > 38) {
$productName = substr($productName, 0, 35).'...';
}
$oldPrice = price($diff['old_price']).' '.$import->currency;
$newPrice = price($diff['new_price']).' '.$import->currency;
$diffPercent = ($diff['diff_percent'] > 0 ? '+' : '').number_format($diff['diff_percent'], 1).'%';
$body .= str_pad($productName, 40)." | ";
$body .= str_pad($oldPrice, 12)." | ";
$body .= str_pad($newPrice, 12)." | ";
$body .= str_pad($diffPercent, 10)."\n";
}
$body .= "\n";
$body .= $langs->trans('NotifyLinkToImport').': '.dol_buildpath('/importzugferd/import.php', 2).'?action=edit&id='.$import->id;
return $this->sendEmail($subject, $body);
}
/**
* Check for price differences and send notification if needed
*
* @param ZugferdImport $import Import object
* @param array $lines Import lines with fk_product set
* @return int 1 if notification sent, 0 if not needed, -1 on error
*/
public function checkAndNotifyPriceDifferences($import, $lines)
{
global $conf;
if (!$this->isEnabled() || !getDolGlobalString('IMPORTZUGFERD_NOTIFY_PRICE_DIFF')) {
return 0;
}
$threshold = getDolGlobalInt('IMPORTZUGFERD_PRICE_DIFF_THRESHOLD', 10);
$priceDiffs = array();
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
foreach ($lines as $line) {
if ($line->fk_product <= 0) {
continue;
}
// Get current supplier price
$productFourn = new ProductFournisseur($this->db);
$result = $productFourn->find_min_price_product_fournisseur($line->fk_product, 1, $import->fk_soc);
if ($result > 0 && $productFourn->fourn_price > 0) {
$oldPrice = $productFourn->fourn_price;
$newPrice = $line->unit_price;
// Calculate percentage difference
$diffPercent = (($newPrice - $oldPrice) / $oldPrice) * 100;
if (abs($diffPercent) >= $threshold) {
$product = new Product($this->db);
$product->fetch($line->fk_product);
$priceDiffs[] = array(
'line' => $line,
'product' => $product,
'old_price' => $oldPrice,
'new_price' => $newPrice,
'diff_percent' => $diffPercent
);
}
}
}
if (!empty($priceDiffs)) {
return $this->sendPriceDifferenceNotification($import, $priceDiffs);
}
return 0;
}
/**
* Send test notification email
*
* @return int 1 if sent, -1 on error
*/
public function sendTestNotification()
{
global $conf, $langs;
if (!$this->isEnabled()) {
$this->error = $langs->trans('NotificationsNotEnabled');
return -1;
}
$langs->load('importzugferd@importzugferd');
$subject = $langs->trans('NotifySubjectTest');
$body = $langs->trans('NotifyBodyTest');
$body .= "\n\n";
$body .= $langs->trans('NotifyTestInfo')."\n\n";
// Show current notification settings
$body .= $langs->trans('CurrentSettings').":\n";
$body .= "- ".$langs->trans('NotifyEmail').": ".$this->getNotifyEmail()."\n";
$body .= "- ".$langs->trans('IMPORTZUGFERD_NOTIFY_MANUAL').": ".(getDolGlobalString('IMPORTZUGFERD_NOTIFY_MANUAL') ? $langs->trans('Yes') : $langs->trans('No'))."\n";
$body .= "- ".$langs->trans('IMPORTZUGFERD_NOTIFY_ERROR').": ".(getDolGlobalString('IMPORTZUGFERD_NOTIFY_ERROR') ? $langs->trans('Yes') : $langs->trans('No'))."\n";
$body .= "- ".$langs->trans('IMPORTZUGFERD_NOTIFY_PRICE_DIFF').": ".(getDolGlobalString('IMPORTZUGFERD_NOTIFY_PRICE_DIFF') ? $langs->trans('Yes') : $langs->trans('No'))."\n";
if (getDolGlobalString('IMPORTZUGFERD_NOTIFY_PRICE_DIFF')) {
$body .= "- ".$langs->trans('IMPORTZUGFERD_PRICE_DIFF_THRESHOLD').": ".getDolGlobalInt('IMPORTZUGFERD_PRICE_DIFF_THRESHOLD', 10)."%\n";
}
$body .= "\n";
$body .= $langs->trans('NotifyTestSuccess');
return $this->sendEmail($subject, $body);
}
/**
* Send email using Dolibarr's mail system
*
* @param string $subject Email subject
* @param string $body Email body (plain text)
* @return int 1 if sent, -1 on error
*/
protected function sendEmail($subject, $body)
{
global $conf, $langs, $mysoc;
$to = $this->getNotifyEmail();
if (empty($to)) {
$this->error = 'No notification email configured';
return -1;
}
// Get sender
$from = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
if (empty($from)) {
$from = $mysoc->email;
}
if (empty($from)) {
$this->error = 'No sender email configured';
return -1;
}
// Add module prefix to subject
$subject = '[ZUGFeRD Import] '.$subject;
// Create mail object
$mailfile = new CMailFile(
$subject,
$to,
$from,
$body,
array(), // files
array(), // mimefiles
array(), // ccfiles
'', // cc
'', // bcc
0, // deliveryreceipt
0, // msgishtml
'', // errors_to
'', // css
'', // trackid
'', // moreinheader
'standard', // sendcontext
'' // replyto
);
$result = $mailfile->sendfile();
if ($result) {
dol_syslog("ImportNotification: Email sent to ".$to." - Subject: ".$subject, LOG_INFO);
return 1;
} else {
$this->error = $mailfile->error;
$this->errors = $mailfile->errors;
dol_syslog("ImportNotification: Failed to send email - ".$this->error, LOG_ERR);
return -1;
}
}
}