- Sortierung: kleinster Querschnitt zuerst (dann Aderanzahl, dann Ref) - Flexbox-Layout statt Tabelle (3 Spalten, links buendig) - Responsives Layout mit min-width Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
626 lines
18 KiB
PHP
Executable file
626 lines
18 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.
|
||
*/
|
||
|
||
/**
|
||
* \file metallzuschlag/class/metallzuschlagapi.class.php
|
||
* \ingroup metallzuschlag
|
||
* \brief API-Client fuer Metallnotierungen + Cronjob-Methode
|
||
*/
|
||
|
||
/**
|
||
* Klasse fuer Metallnotiz-API-Abfragen und Cronjob
|
||
*/
|
||
class MetallzuschlagApi
|
||
{
|
||
/** @var DoliDB */
|
||
public $db;
|
||
/** @var string */
|
||
public $error = '';
|
||
/** @var string[] */
|
||
public $errors = array();
|
||
/** @var string */
|
||
public $output = '';
|
||
|
||
/**
|
||
* Constructor
|
||
*
|
||
* @param DoliDB $db Database handler
|
||
*/
|
||
public function __construct($db)
|
||
{
|
||
$this->db = $db;
|
||
}
|
||
|
||
/**
|
||
* Cronjob-Methode: Metallnotierungen abrufen und speichern
|
||
*
|
||
* @return int 0 bei Erfolg, -1 bei Fehler
|
||
*/
|
||
public function fetchMetalNotes()
|
||
{
|
||
global $conf, $langs;
|
||
|
||
$langs->load('metallzuschlag@metallzuschlag');
|
||
|
||
dol_syslog("MetallzuschlagApi::fetchMetalNotes - Start", LOG_INFO);
|
||
|
||
$baseUrl = getDolGlobalString('METALLZUSCHLAG_API_URL', 'https://www.sonepar.de/api/content/metalnote');
|
||
$today = date('Ymd');
|
||
$firstOfMonth = date('Ym01');
|
||
|
||
$results = array();
|
||
$hasError = false;
|
||
|
||
// Tageswerte abrufen
|
||
$dayData = $this->callApi($baseUrl.'/day?date='.$today);
|
||
if ($dayData !== false && !empty($dayData['data'])) {
|
||
foreach ($dayData['data'] as $entry) {
|
||
$metal = $entry['nes'];
|
||
$value = (float)$entry['nku'];
|
||
$date = $entry['ndt'];
|
||
|
||
$res = $this->saveNotation($date, $metal, $value, null, 'sonepar');
|
||
if ($res < 0) {
|
||
$hasError = true;
|
||
} else {
|
||
$results[] = $metal.': '.$value.' EUR/100kg ('.$date.')';
|
||
}
|
||
}
|
||
} else {
|
||
$this->output .= "Tageswerte: Keine Daten erhalten\n";
|
||
$hasError = true;
|
||
}
|
||
|
||
// Monatsdurchschnitt Vormonat abrufen
|
||
$monthData = $this->callApi($baseUrl.'/previousmonth?date='.$firstOfMonth);
|
||
if ($monthData !== false && !empty($monthData['data'])) {
|
||
foreach ($monthData['data'] as $entry) {
|
||
$metal = $entry['nes'];
|
||
$avgValue = (float)$entry['nku'];
|
||
|
||
// Monatsdurchschnitt auf den heutigen Tageseintrag aktualisieren
|
||
$this->updateMonthAvg(date('Y-m-d'), $metal, $avgValue, 'sonepar');
|
||
$results[] = $metal.' Ø Vormonat: '.$avgValue.' EUR/100kg';
|
||
}
|
||
}
|
||
|
||
// Lieferanten-Extrafields aktualisieren
|
||
$updatedSuppliers = $this->updateSupplierExtrafields($dayData);
|
||
if ($updatedSuppliers > 0) {
|
||
$results[] = $updatedSuppliers.' Lieferant(en) aktualisiert';
|
||
}
|
||
|
||
if (!empty($results)) {
|
||
$this->output = implode("\n", $results);
|
||
}
|
||
|
||
dol_syslog("MetallzuschlagApi::fetchMetalNotes - Fertig: ".implode(', ', $results), LOG_INFO);
|
||
|
||
return $hasError ? -1 : 0;
|
||
}
|
||
|
||
/**
|
||
* API-Aufruf durchfuehren
|
||
*
|
||
* @param string $url URL zum Abrufen
|
||
* @return array|false Dekodierte JSON-Antwort oder false bei Fehler
|
||
*/
|
||
public function callApi($url)
|
||
{
|
||
dol_syslog("MetallzuschlagApi::callApi - URL: ".$url, LOG_DEBUG);
|
||
|
||
$ch = curl_init();
|
||
curl_setopt_array($ch, array(
|
||
CURLOPT_URL => $url,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_TIMEOUT => 30,
|
||
CURLOPT_FOLLOWLOCATION => true,
|
||
CURLOPT_HTTPHEADER => array(
|
||
'Accept: application/json',
|
||
'User-Agent: Dolibarr-Metallzuschlag/1.0',
|
||
),
|
||
));
|
||
|
||
$response = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($ch);
|
||
curl_close($ch);
|
||
|
||
if ($response === false || !empty($curlError)) {
|
||
$this->error = 'cURL-Fehler: '.$curlError;
|
||
dol_syslog("MetallzuschlagApi::callApi - ".$this->error, LOG_ERR);
|
||
return false;
|
||
}
|
||
|
||
if ($httpCode !== 200) {
|
||
$this->error = 'HTTP '.$httpCode.' von '.$url;
|
||
dol_syslog("MetallzuschlagApi::callApi - ".$this->error, LOG_ERR);
|
||
return false;
|
||
}
|
||
|
||
$data = json_decode($response, true);
|
||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||
$this->error = 'JSON-Parse-Fehler: '.json_last_error_msg();
|
||
dol_syslog("MetallzuschlagApi::callApi - ".$this->error, LOG_ERR);
|
||
return false;
|
||
}
|
||
|
||
if (empty($data['status']) || $data['status']['statuscode'] != 200) {
|
||
$this->error = 'API-Fehler: Status '.($data['status']['statuscode'] ?? 'unbekannt');
|
||
dol_syslog("MetallzuschlagApi::callApi - ".$this->error, LOG_ERR);
|
||
return false;
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
/**
|
||
* Notierung in DB speichern (INSERT oder UPDATE bei Duplikat)
|
||
*
|
||
* @param string $date Datum (Y-m-d)
|
||
* @param string $metal Metall-Kuerzel (CU/AL)
|
||
* @param float $value Wert in EUR/100kg
|
||
* @param float|null $avg Monatsdurchschnitt (optional)
|
||
* @param string $source Quelle
|
||
* @return int 1 bei Erfolg, -1 bei Fehler
|
||
*/
|
||
public function saveNotation($date, $metal, $value, $avg = null, $source = 'sonepar')
|
||
{
|
||
$sql = "INSERT INTO ".$this->db->prefix()."metallzuschlag_history";
|
||
$sql .= " (date_notiz, metal, value, value_month_avg, source)";
|
||
$sql .= " VALUES ('".$this->db->escape($date)."',";
|
||
$sql .= " '".$this->db->escape($metal)."',";
|
||
$sql .= " ".((float)$value).",";
|
||
$sql .= " ".($avg !== null ? ((float)$avg) : "NULL").",";
|
||
$sql .= " '".$this->db->escape($source)."')";
|
||
$sql .= " ON DUPLICATE KEY UPDATE value = ".((float)$value);
|
||
if ($avg !== null) {
|
||
$sql .= ", value_month_avg = ".((float)$avg);
|
||
}
|
||
|
||
$result = $this->db->query($sql);
|
||
if (!$result) {
|
||
$this->error = 'DB-Fehler: '.$this->db->lasterror();
|
||
dol_syslog("MetallzuschlagApi::saveNotation - ".$this->error, LOG_ERR);
|
||
return -1;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* Monatsdurchschnitt auf bestehenden Eintrag aktualisieren
|
||
*
|
||
* @param string $date Datum
|
||
* @param string $metal Metall
|
||
* @param float $avg Durchschnittswert
|
||
* @param string $source Quelle
|
||
* @return int
|
||
*/
|
||
public function updateMonthAvg($date, $metal, $avg, $source = 'sonepar')
|
||
{
|
||
$sql = "UPDATE ".$this->db->prefix()."metallzuschlag_history";
|
||
$sql .= " SET value_month_avg = ".((float)$avg);
|
||
$sql .= " WHERE date_notiz = '".$this->db->escape($date)."'";
|
||
$sql .= " AND metal = '".$this->db->escape($metal)."'";
|
||
$sql .= " AND source = '".$this->db->escape($source)."'";
|
||
|
||
return $this->db->query($sql) ? 1 : -1;
|
||
}
|
||
|
||
/**
|
||
* Lieferanten-Extrafields mit aktuellen Werten aktualisieren
|
||
*
|
||
* @param array|false $dayData Tageswerte von der API
|
||
* @return int Anzahl aktualisierter Lieferanten
|
||
*/
|
||
public function updateSupplierExtrafields($dayData)
|
||
{
|
||
if ($dayData === false || empty($dayData['data'])) {
|
||
return 0;
|
||
}
|
||
|
||
// Werte aus API-Antwort extrahieren
|
||
$values = array();
|
||
foreach ($dayData['data'] as $entry) {
|
||
$values[$entry['nes']] = (float)$entry['nku'];
|
||
}
|
||
|
||
$cuValue = isset($values['CU']) ? $values['CU'] : null;
|
||
$alValue = isset($values['AL']) ? $values['AL'] : null;
|
||
$today = date('Y-m-d');
|
||
|
||
// Alle Lieferanten mit metallzuschlag_source != '' finden
|
||
$sql = "SELECT fk_object, metallzuschlag_source";
|
||
$sql .= " FROM ".$this->db->prefix()."societe_extrafields";
|
||
$sql .= " WHERE metallzuschlag_source IS NOT NULL";
|
||
$sql .= " AND metallzuschlag_source != ''";
|
||
$sql .= " AND metallzuschlag_source != 'manuell'";
|
||
|
||
$resql = $this->db->query($sql);
|
||
if (!$resql) {
|
||
return 0;
|
||
}
|
||
|
||
$count = 0;
|
||
while ($obj = $this->db->fetch_object($resql)) {
|
||
$sets = array();
|
||
if ($cuValue !== null) {
|
||
$sets[] = "metallzuschlag_cu = ".$cuValue;
|
||
}
|
||
if ($alValue !== null) {
|
||
$sets[] = "metallzuschlag_al = ".$alValue;
|
||
}
|
||
$sets[] = "metallzuschlag_date = '".$this->db->escape($today)."'";
|
||
|
||
if (!empty($sets)) {
|
||
$sqlUpdate = "UPDATE ".$this->db->prefix()."societe_extrafields";
|
||
$sqlUpdate .= " SET ".implode(", ", $sets);
|
||
$sqlUpdate .= " WHERE fk_object = ".((int)$obj->fk_object);
|
||
|
||
if ($this->db->query($sqlUpdate)) {
|
||
$count++;
|
||
}
|
||
}
|
||
}
|
||
|
||
return $count;
|
||
}
|
||
|
||
/**
|
||
* Aktuelle Notierung aus DB holen
|
||
*
|
||
* @param string $metal Metall (CU/AL)
|
||
* @param string $source Quelle
|
||
* @return object|null Objekt mit value, value_month_avg, date_notiz oder null
|
||
*/
|
||
public function getLatest($metal = 'CU', $source = 'sonepar')
|
||
{
|
||
$sql = "SELECT date_notiz, metal, value, value_month_avg, source";
|
||
$sql .= " FROM ".$this->db->prefix()."metallzuschlag_history";
|
||
$sql .= " WHERE metal = '".$this->db->escape($metal)."'";
|
||
$sql .= " AND source = '".$this->db->escape($source)."'";
|
||
$sql .= " ORDER BY date_notiz DESC LIMIT 1";
|
||
|
||
$resql = $this->db->query($sql);
|
||
if ($resql && $this->db->num_rows($resql) > 0) {
|
||
return $this->db->fetch_object($resql);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Historie aus DB holen
|
||
*
|
||
* @param string $source Quelle
|
||
* @param int $limit Anzahl Eintraege
|
||
* @return array Array von Objekten
|
||
*/
|
||
public function getHistory($source = 'sonepar', $limit = 30)
|
||
{
|
||
$results = array();
|
||
|
||
$sql = "SELECT date_notiz, metal, value, value_month_avg, source";
|
||
$sql .= " FROM ".$this->db->prefix()."metallzuschlag_history";
|
||
$sql .= " WHERE source = '".$this->db->escape($source)."'";
|
||
$sql .= " ORDER BY date_notiz DESC, metal ASC";
|
||
$sql .= " LIMIT ".((int)$limit);
|
||
|
||
$resql = $this->db->query($sql);
|
||
if ($resql) {
|
||
while ($obj = $this->db->fetch_object($resql)) {
|
||
$results[] = $obj;
|
||
}
|
||
}
|
||
|
||
return $results;
|
||
}
|
||
|
||
/**
|
||
* Cronjob: Kupferzuschlag auf allen Einkaufspreisen neu berechnen
|
||
*
|
||
* Fuer alle Produkte mit Kupfergehalt > 0 werden die Einkaufspreise aktualisiert.
|
||
* CU-Notiz: Lieferant-eigener Wert (metallzuschlag_cu) oder aktuellster aus History.
|
||
*
|
||
* @return int 0 bei Erfolg, -1 bei Fehler
|
||
*/
|
||
public function recalcAllKupferzuschlag()
|
||
{
|
||
global $langs;
|
||
|
||
$langs->load('metallzuschlag@metallzuschlag');
|
||
|
||
dol_syslog("MetallzuschlagApi::recalcAllKupferzuschlag - Start", LOG_INFO);
|
||
|
||
// Aktuellste CU-Notiz als Fallback
|
||
$fallbackCU = 0;
|
||
$latestCU = $this->getLatest('CU');
|
||
if ($latestCU) {
|
||
$fallbackCU = (float) $latestCU->value;
|
||
}
|
||
|
||
if ($fallbackCU <= 0) {
|
||
$this->error = 'Keine CU-Notierung vorhanden';
|
||
dol_syslog("MetallzuschlagApi::recalcAllKupferzuschlag - ".$this->error, LOG_ERR);
|
||
return -1;
|
||
}
|
||
|
||
// Alle Produkte mit kupfergehalt > 0
|
||
$sql = "SELECT pe.fk_object, pe.kupfergehalt";
|
||
$sql .= " FROM ".$this->db->prefix()."product_extrafields pe";
|
||
$sql .= " WHERE pe.kupfergehalt IS NOT NULL AND pe.kupfergehalt > 0";
|
||
|
||
$resql = $this->db->query($sql);
|
||
if (!$resql) {
|
||
$this->error = 'DB-Fehler: '.$this->db->lasterror();
|
||
return -1;
|
||
}
|
||
|
||
$productCount = 0;
|
||
$priceCount = 0;
|
||
|
||
while ($product = $this->db->fetch_object($resql)) {
|
||
$kupfergehalt = (float) $product->kupfergehalt;
|
||
$productId = (int) $product->fk_object;
|
||
|
||
// Alle Einkaufspreise dieses Produkts
|
||
$sqlPrices = "SELECT pf.rowid, pf.fk_soc, pf.quantity";
|
||
$sqlPrices .= " FROM ".$this->db->prefix()."product_fournisseur_price pf";
|
||
$sqlPrices .= " WHERE pf.fk_product = ".$productId;
|
||
|
||
$resPrices = $this->db->query($sqlPrices);
|
||
if (!$resPrices) {
|
||
continue;
|
||
}
|
||
|
||
while ($price = $this->db->fetch_object($resPrices)) {
|
||
// CU-Notiz des Lieferanten oder Fallback
|
||
$cuNotiz = $this->getCUForSupplier((int) $price->fk_soc, $fallbackCU);
|
||
|
||
if ($cuNotiz <= 0) {
|
||
continue;
|
||
}
|
||
|
||
// Kupferzuschlag = Kupfergehalt (kg/km) × CU (EUR/100kg) / 100.000 × Mindestmenge
|
||
$quantity = (float) $price->quantity > 0 ? (float) $price->quantity : 1;
|
||
$kupferzuschlag = round($kupfergehalt * $cuNotiz / 100000 * $quantity, 2);
|
||
|
||
// UPDATE oder INSERT
|
||
$sqlUpd = "UPDATE ".$this->db->prefix()."product_fournisseur_price_extrafields";
|
||
$sqlUpd .= " SET kupferzuschlag = ".((float) $kupferzuschlag);
|
||
$sqlUpd .= " WHERE fk_object = ".((int) $price->rowid);
|
||
|
||
$resUpd = $this->db->query($sqlUpd);
|
||
if ($resUpd && $this->db->affected_rows($resUpd) > 0) {
|
||
$priceCount++;
|
||
} else {
|
||
$sqlIns = "INSERT INTO ".$this->db->prefix()."product_fournisseur_price_extrafields";
|
||
$sqlIns .= " (fk_object, kupferzuschlag) VALUES (".((int) $price->rowid).", ".((float) $kupferzuschlag).")";
|
||
if ($this->db->query($sqlIns)) {
|
||
$priceCount++;
|
||
}
|
||
}
|
||
}
|
||
|
||
$productCount++;
|
||
}
|
||
|
||
$this->output = $productCount.' Produkte, '.$priceCount.' Einkaufspreise aktualisiert (CU: '.$fallbackCU.' EUR/100kg)';
|
||
dol_syslog("MetallzuschlagApi::recalcAllKupferzuschlag - ".$this->output, LOG_INFO);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* 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
|
||
*/
|
||
public function getCUForSupplier($socId, $fallbackCU)
|
||
{
|
||
$sql = "SELECT metallzuschlag_cu";
|
||
$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;
|
||
}
|
||
}
|
||
|
||
return $fallbackCU;
|
||
}
|
||
|
||
/**
|
||
* Verlaufsdaten fuer Chart aufbereiten
|
||
*
|
||
* @param int $days Zeitraum in Tagen
|
||
* @param string $source Quelle
|
||
* @return array Array mit 'labels', 'cu', 'al' fuer Chart.js
|
||
*/
|
||
public function getChartData($days = 90, $source = 'sonepar')
|
||
{
|
||
$result = array(
|
||
'labels' => array(),
|
||
'cu' => array(),
|
||
'al' => array(),
|
||
);
|
||
|
||
$dateFrom = date('Y-m-d', strtotime('-'.$days.' days'));
|
||
|
||
// Alle Daten im Zeitraum holen, nach Datum sortiert
|
||
$sql = "SELECT date_notiz, metal, value";
|
||
$sql .= " FROM ".$this->db->prefix()."metallzuschlag_history";
|
||
$sql .= " WHERE source = '".$this->db->escape($source)."'";
|
||
$sql .= " AND date_notiz >= '".$this->db->escape($dateFrom)."'";
|
||
$sql .= " ORDER BY date_notiz ASC, metal ASC";
|
||
|
||
$resql = $this->db->query($sql);
|
||
if (!$resql) {
|
||
return $result;
|
||
}
|
||
|
||
// Daten nach Datum gruppieren
|
||
$byDate = array();
|
||
while ($obj = $this->db->fetch_object($resql)) {
|
||
$date = $obj->date_notiz;
|
||
if (!isset($byDate[$date])) {
|
||
$byDate[$date] = array('CU' => null, 'AL' => null);
|
||
}
|
||
$byDate[$date][$obj->metal] = (float) $obj->value;
|
||
}
|
||
|
||
foreach ($byDate as $date => $values) {
|
||
$result['labels'][] = $date;
|
||
$result['cu'][] = $values['CU'];
|
||
$result['al'][] = $values['AL'];
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* Alle Produkte mit Kupfergehalt > 0 holen
|
||
*
|
||
* @return array Array von Objekten mit id, ref, label, kupfergehalt
|
||
*/
|
||
public function getProductsWithKupfergehalt()
|
||
{
|
||
$results = array();
|
||
|
||
$sql = "SELECT p.rowid, p.ref, p.label, pe.kupfergehalt, pe.querschnitt, pe.aderanzahl";
|
||
$sql .= " FROM ".$this->db->prefix()."product p";
|
||
$sql .= " INNER JOIN ".$this->db->prefix()."product_extrafields pe ON pe.fk_object = p.rowid";
|
||
$sql .= " WHERE pe.kupfergehalt IS NOT NULL AND pe.kupfergehalt > 0";
|
||
$sql .= " ORDER BY pe.querschnitt ASC, pe.aderanzahl ASC, p.ref ASC";
|
||
|
||
$resql = $this->db->query($sql);
|
||
if ($resql) {
|
||
while ($obj = $this->db->fetch_object($resql)) {
|
||
$results[] = $obj;
|
||
}
|
||
}
|
||
|
||
return $results;
|
||
}
|
||
|
||
/**
|
||
* Kupferzuschlag-Verlauf fuer Kabel berechnen
|
||
*
|
||
* @param int $days Zeitraum in Tagen
|
||
* @param array $productIds Produkt-IDs (leer = alle mit Kupfergehalt)
|
||
* @param string $mode 'per_meter' oder 'total' (mit Mindestmenge)
|
||
* @param string $source Quelle fuer CU-Notierungen
|
||
* @return array ['labels' => [...], 'products' => [id => ['label' => name, 'data' => [...]]]]
|
||
*/
|
||
public function getCableChartData($days = 90, $productIds = array(), $mode = 'per_meter', $source = 'sonepar')
|
||
{
|
||
$result = array(
|
||
'labels' => array(),
|
||
'products' => array(),
|
||
);
|
||
|
||
// CU-Notierungen im Zeitraum holen
|
||
$dateFrom = date('Y-m-d', strtotime('-'.$days.' days'));
|
||
|
||
$sql = "SELECT date_notiz, value";
|
||
$sql .= " FROM ".$this->db->prefix()."metallzuschlag_history";
|
||
$sql .= " WHERE metal = 'CU'";
|
||
$sql .= " AND source = '".$this->db->escape($source)."'";
|
||
$sql .= " AND date_notiz >= '".$this->db->escape($dateFrom)."'";
|
||
$sql .= " ORDER BY date_notiz ASC";
|
||
|
||
$resql = $this->db->query($sql);
|
||
if (!$resql) {
|
||
return $result;
|
||
}
|
||
|
||
$cuByDate = array();
|
||
while ($obj = $this->db->fetch_object($resql)) {
|
||
$cuByDate[$obj->date_notiz] = (float) $obj->value;
|
||
$result['labels'][] = $obj->date_notiz;
|
||
}
|
||
|
||
if (empty($result['labels'])) {
|
||
return $result;
|
||
}
|
||
|
||
// Produkte mit Kupfergehalt holen
|
||
$sqlProd = "SELECT p.rowid, p.ref, p.label, pe.kupfergehalt";
|
||
$sqlProd .= " FROM ".$this->db->prefix()."product p";
|
||
$sqlProd .= " INNER JOIN ".$this->db->prefix()."product_extrafields pe ON pe.fk_object = p.rowid";
|
||
$sqlProd .= " WHERE pe.kupfergehalt IS NOT NULL AND pe.kupfergehalt > 0";
|
||
|
||
if (!empty($productIds)) {
|
||
$sqlProd .= " AND p.rowid IN (".implode(',', array_map('intval', $productIds)).")";
|
||
}
|
||
|
||
$sqlProd .= " ORDER BY p.ref ASC";
|
||
|
||
$resProd = $this->db->query($sqlProd);
|
||
if (!$resProd) {
|
||
return $result;
|
||
}
|
||
|
||
while ($product = $this->db->fetch_object($resProd)) {
|
||
$kupfergehalt = (float) $product->kupfergehalt;
|
||
$productId = (int) $product->rowid;
|
||
|
||
// Mindestmenge ermitteln (kleinste quantity aus Einkaufspreisen)
|
||
$quantity = 1;
|
||
if ($mode === 'total') {
|
||
$sqlQty = "SELECT MIN(quantity) as min_qty";
|
||
$sqlQty .= " FROM ".$this->db->prefix()."product_fournisseur_price";
|
||
$sqlQty .= " WHERE fk_product = ".$productId;
|
||
$sqlQty .= " AND quantity > 0";
|
||
|
||
$resQty = $this->db->query($sqlQty);
|
||
if ($resQty && $this->db->num_rows($resQty) > 0) {
|
||
$objQty = $this->db->fetch_object($resQty);
|
||
if ($objQty->min_qty > 0) {
|
||
$quantity = (float) $objQty->min_qty;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Kupferzuschlag fuer jeden Tag berechnen
|
||
$data = array();
|
||
foreach ($result['labels'] as $date) {
|
||
$cuNotiz = isset($cuByDate[$date]) ? $cuByDate[$date] : 0;
|
||
if ($cuNotiz > 0) {
|
||
// Kupferzuschlag = Kupfergehalt × CU / 100.000 × Menge
|
||
$data[] = round($kupfergehalt * $cuNotiz / 100000 * $quantity, 2);
|
||
} else {
|
||
$data[] = null;
|
||
}
|
||
}
|
||
|
||
$label = $product->ref;
|
||
if (!empty($product->label)) {
|
||
$label .= ' - '.$product->label;
|
||
}
|
||
if ($mode === 'total' && $quantity > 1) {
|
||
$label .= ' ('.$quantity.'m)';
|
||
}
|
||
|
||
$result['products'][$productId] = array(
|
||
'label' => $label,
|
||
'data' => $data,
|
||
'kupfergehalt' => $kupfergehalt,
|
||
);
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
}
|