dolibarr.metallzuschlag/core/triggers/interface_99_modMetallzuschlag_MetallzuschlagTriggers.class.php
data 8729b5fdb7 Metallzuschlag v1.1 - Kupferzuschlag-Berechnung + Notierungsverlauf
- Sonepar Metal Note API: CU/AL Tageswerte + Monatsdurchschnitte
- Dashboard mit Chart.js Verlaufsdiagramm (30/90/365 Tage)
- Trigger: Kupfergehalt (kg/km) = Aderanzahl × Querschnitt × 8,89
- Trigger: Kupferzuschlag (€/m) auf Einkaufspreisen berechnen
- CU-Logik: Lieferant-eigener Wert oder aktuellster aus History
- Cronjobs: Wöchentlicher API-Abruf + Kupferzuschlag-Neuberechnung
- Extrafields: Lieferantenkarte (CU/AL/Datum/Quelle), Produkt (Aderanzahl/Querschnitt/Kupfergehalt)
- Admin-Seite mit API-URL, Auto-Fetch, Lieferantenübersicht
- Mehrsprachig (de_DE, en_US)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 17:41:31 +01:00

235 lines
7.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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.
*/
/**
* \file core/triggers/interface_99_modMetallzuschlag_MetallzuschlagTriggers.class.php
* \ingroup metallzuschlag
* \brief Trigger: Kupfergehalt + Kupferzuschlag berechnen
*/
require_once DOL_DOCUMENT_ROOT.'/core/triggers/dolibarrtriggers.class.php';
/**
* Trigger fuer automatische Kupfergehalt- und Kupferzuschlag-Berechnung
*/
class InterfaceMetallzuschlagTriggers extends DolibarrTriggers
{
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
$this->db = $db;
$this->name = preg_replace('/^Interface/i', '', get_class($this));
$this->family = 'products';
$this->description = "Berechnet Kupfergehalt und Kupferzuschlag auf Einkaufspreisen";
$this->version = '1.1';
$this->picto = 'fa-coins';
}
/**
* Trigger-Funktion
*
* @param string $action Trigger-Aktion
* @param Object $object Betroffenes Objekt
* @param User $user Ausloesender User
* @param Translate $langs Sprach-Objekt
* @param Conf $conf Konfiguration
* @return int 0 = OK, <0 = Fehler
*/
public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
{
if (!isModEnabled('metallzuschlag')) {
return 0;
}
// Produkt erstellt oder geaendert → Kupfergehalt + Kupferzuschlag berechnen
if ($action === 'PRODUCT_CREATE' || $action === 'PRODUCT_MODIFY') {
$kupfergehalt = $this->calculateKupfergehalt($object);
if ($kupfergehalt > 0) {
$this->updateKupferzuschlagForProduct($object->id, $kupfergehalt);
}
return 0;
}
return 0;
}
/**
* Berechnet Kupfergehalt aus Aderanzahl und Querschnitt
*
* Formel: kupfergehalt (kg/km) = aderanzahl × querschnitt (mm²) × 8,89
*
* @param Product $object Produkt-Objekt
* @return float Berechneter Kupfergehalt (0 wenn nicht berechenbar)
*/
private function calculateKupfergehalt($object)
{
if (empty($object->array_options)) {
$object->fetch_optionals();
}
$aderanzahl = !empty($object->array_options['options_aderanzahl']) ? (int) $object->array_options['options_aderanzahl'] : 0;
$querschnitt = !empty($object->array_options['options_querschnitt']) ? (float) $object->array_options['options_querschnitt'] : 0;
if ($aderanzahl <= 0 || $querschnitt <= 0) {
return 0;
}
// Kupfergewicht: Aderanzahl × Querschnitt (mm²) × 8,89 kg/(km·mm²)
$kupfergehalt = $aderanzahl * $querschnitt * 8.89;
// In Produkt-Extrafield speichern
$currentValue = !empty($object->array_options['options_kupfergehalt']) ? (float) $object->array_options['options_kupfergehalt'] : 0;
if (round($currentValue, 4) !== round($kupfergehalt, 4)) {
$sql = "UPDATE ".$this->db->prefix()."product_extrafields";
$sql .= " SET kupfergehalt = ".((float) $kupfergehalt);
$sql .= " WHERE fk_object = ".((int) $object->id);
$resql = $this->db->query($sql);
if ($resql && $this->db->affected_rows($resql) == 0) {
$sql2 = "INSERT INTO ".$this->db->prefix()."product_extrafields";
$sql2 .= " (fk_object, kupfergehalt) VALUES (".((int) $object->id).", ".((float) $kupfergehalt).")";
$this->db->query($sql2);
}
dol_syslog("Metallzuschlag: Kupfergehalt Produkt #".$object->id.": ".$aderanzahl." × ".$querschnitt." × 8,89 = ".round($kupfergehalt, 4)." kg/km", LOG_INFO);
}
return $kupfergehalt;
}
/**
* Kupferzuschlag auf allen Einkaufspreisen eines Produkts berechnen
*
* Logik fuer CU-Notiz:
* 1. Lieferant hat eigenen Metallzuschlag (metallzuschlag_cu) → diesen nehmen
* 2. Sonst: aktuellsten verfuegbaren Wert aus metallzuschlag_history
*
* Formel: kupferzuschlag (EUR/m) = kupfergehalt (kg/km) × CU-Notiz (EUR/100kg) / 100.000
*
* @param int $productId Produkt-ID
* @param float $kupfergehalt Kupfergehalt in kg/km
* @return int Anzahl aktualisierter Einkaufspreise
*/
private function updateKupferzuschlagForProduct($productId, $kupfergehalt)
{
// Alle Einkaufspreise des Produkts holen
$sql = "SELECT pf.rowid, pf.fk_soc";
$sql .= " FROM ".$this->db->prefix()."product_fournisseur_price pf";
$sql .= " WHERE pf.fk_product = ".((int) $productId);
$resql = $this->db->query($sql);
if (!$resql) {
return 0;
}
// Aktuellste CU-Notiz aus History als Fallback vorhalten
$fallbackCU = $this->getLatestCUFromHistory();
$count = 0;
while ($obj = $this->db->fetch_object($resql)) {
// CU-Notiz fuer diesen Lieferanten bestimmen
$cuNotiz = $this->getCUForSupplier((int) $obj->fk_soc, $fallbackCU);
if ($cuNotiz <= 0) {
continue;
}
// Kupferzuschlag EUR/m = Kupfergehalt (kg/km) × CU (EUR/100kg) / 100.000
$kupferzuschlag = $kupfergehalt * $cuNotiz / 100000;
// In Einkaufspreis-Extrafield schreiben
if ($this->saveKupferzuschlag((int) $obj->rowid, $kupferzuschlag)) {
$count++;
}
}
if ($count > 0) {
dol_syslog("Metallzuschlag: Kupferzuschlag fuer ".$count." Einkaufspreise von Produkt #".$productId." aktualisiert", LOG_INFO);
}
return $count;
}
/**
* CU-Notiz fuer einen Lieferanten ermitteln
*
* @param int $socId Lieferanten-ID
* @param float $fallbackCU Fallback-Wert aus History
* @return float CU-Notiz in EUR/100kg
*/
private function getCUForSupplier($socId, $fallbackCU)
{
// Lieferant hat eigenen Wert?
$sql = "SELECT metallzuschlag_cu, metallzuschlag_source";
$sql .= " FROM ".$this->db->prefix()."societe_extrafields";
$sql .= " WHERE fk_object = ".((int) $socId);
$resql = $this->db->query($sql);
if ($resql && $this->db->num_rows($resql) > 0) {
$obj = $this->db->fetch_object($resql);
if (!empty($obj->metallzuschlag_cu) && (float) $obj->metallzuschlag_cu > 0) {
return (float) $obj->metallzuschlag_cu;
}
}
// Kein eigener Wert → Fallback
return $fallbackCU;
}
/**
* Aktuellste CU-Notiz aus der History-Tabelle holen
*
* @return float CU-Notiz in EUR/100kg (0 wenn nichts vorhanden)
*/
private function getLatestCUFromHistory()
{
$sql = "SELECT value FROM ".$this->db->prefix()."metallzuschlag_history";
$sql .= " WHERE metal = 'CU'";
$sql .= " ORDER BY date_notiz DESC LIMIT 1";
$resql = $this->db->query($sql);
if ($resql && $this->db->num_rows($resql) > 0) {
$obj = $this->db->fetch_object($resql);
return (float) $obj->value;
}
return 0;
}
/**
* Kupferzuschlag in Einkaufspreis-Extrafield speichern
*
* @param int $priceId Einkaufspreis-ID (rowid)
* @param float $kupferzuschlag Wert in EUR/m
* @return bool true wenn gespeichert
*/
private function saveKupferzuschlag($priceId, $kupferzuschlag)
{
// UPDATE versuchen
$sql = "UPDATE ".$this->db->prefix()."product_fournisseur_price_extrafields";
$sql .= " SET kupferzuschlag = ".((float) $kupferzuschlag);
$sql .= " WHERE fk_object = ".((int) $priceId);
$resql = $this->db->query($sql);
if ($resql && $this->db->affected_rows($resql) > 0) {
return true;
}
// Zeile existiert nicht → INSERT
$sql2 = "INSERT INTO ".$this->db->prefix()."product_fournisseur_price_extrafields";
$sql2 .= " (fk_object, kupferzuschlag) VALUES (".((int) $priceId).", ".((float) $kupferzuschlag).")";
return (bool) $this->db->query($sql2);
}
}