*
* Stundenzettel - Business Object Klasse
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
/**
* Class Stundenzettel
*/
class Stundenzettel extends CommonObject
{
/**
* @var string ID to identify managed object
*/
public $element = 'stundenzettel';
/**
* @var string Name of table without prefix
*/
public $table_element = 'stundenzettel';
/**
* @var string Picto
*/
public $picto = 'clock';
// Status constants
const STATUS_DRAFT = 0;
const STATUS_VALIDATED = 1;
const STATUS_INVOICED = 2;
const STATUS_CANCELED = 9;
/**
* @var string Ref
*/
public $ref;
/**
* @var int Auftrag ID
*/
public $fk_commande;
/**
* @var int Rechnung ID (nach Übertrag)
*/
public $fk_facture;
/**
* @var int Kunde ID
*/
public $fk_soc;
/**
* @var int Ersteller
*/
public $fk_user_author;
/**
* @var int Freigebender User
*/
public $fk_user_valid;
/**
* @var int|string Datum des Stundenzettels
*/
public $date_stundenzettel;
/**
* @var int|string Erstelldatum
*/
public $datec;
/**
* @var int|string Freigabedatum
*/
public $date_valid;
/**
* @var int Status
*/
public $status;
/**
* @var string Private Notizen
*/
public $note_private;
/**
* @var string Öffentliche Notizen
*/
public $note_public;
/**
* @var float|null Stundenpreis (NULL = Standard verwenden)
*/
public $hourly_rate;
/**
* @var int 1 = Stundenpreis wurde manuell geändert
*/
public $hourly_rate_is_custom = 0;
/**
* @var array Leistungen
*/
public $leistungen = array();
/**
* @var array Produkte
*/
public $products = array();
/**
* @var array Notizen (abhakbare Merkzettel)
*/
public $notes = array();
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
$this->db = $db;
}
/**
* Create object into database
*
* @param User $user User that creates
* @param bool $notrigger false=launch triggers after, true=disable triggers
* @return int <0 if KO, Id of created object if OK
*/
public function create($user, $notrigger = false)
{
global $conf;
$error = 0;
// Generate ref
if (empty($this->ref)) {
$this->ref = $this->getNextNumRef();
}
$this->db->begin();
$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
$sql .= "ref, entity, fk_commande, fk_soc, fk_user_author,";
$sql .= "date_stundenzettel, datec, status, note_private, note_public,";
$sql .= "hourly_rate, hourly_rate_is_custom";
$sql .= ") VALUES (";
$sql .= "'".$this->db->escape($this->ref)."',";
$sql .= ((int)$conf->entity).",";
$sql .= ((int)$this->fk_commande).",";
$sql .= ((int)$this->fk_soc).",";
$sql .= ((int)$user->id).",";
$sql .= "'".$this->db->idate($this->date_stundenzettel)."',";
$sql .= "'".$this->db->idate(dol_now())."',";
$sql .= "0,"; // STATUS_DRAFT
$sql .= ($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL").",";
$sql .= ($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "NULL").",";
$sql .= (isset($this->hourly_rate) && $this->hourly_rate !== null ? ((float)$this->hourly_rate) : "NULL").",";
$sql .= ((int)$this->hourly_rate_is_custom);
$sql .= ")";
dol_syslog(get_class($this)."::create", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if (!$error) {
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
}
if (!$error) {
$this->db->commit();
return $this->id;
} else {
$this->db->rollback();
return -1;
}
}
/**
* Load object in memory from the database
*
* @param int $id Id object
* @param string $ref Ref
* @return int <0 if KO, 0 if not found, >0 if OK
*/
public function fetch($id, $ref = null)
{
$sql = "SELECT s.rowid, s.ref, s.entity, s.fk_commande, s.fk_facture, s.fk_soc,";
$sql .= " s.fk_user_author, s.fk_user_valid, s.date_stundenzettel, s.datec,";
$sql .= " s.date_valid, s.status, s.note_private, s.note_public, s.tms,";
$sql .= " s.hourly_rate, s.hourly_rate_is_custom";
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as s";
if ($ref) {
$sql .= " WHERE s.ref = '".$this->db->escape($ref)."'";
} else {
$sql .= " WHERE s.rowid = ".((int)$id);
}
dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql) {
if ($this->db->num_rows($resql)) {
$obj = $this->db->fetch_object($resql);
$this->id = $obj->rowid;
$this->ref = $obj->ref;
$this->entity = $obj->entity;
$this->fk_commande = $obj->fk_commande;
$this->fk_facture = $obj->fk_facture;
$this->fk_soc = $obj->fk_soc;
$this->fk_user_author = $obj->fk_user_author;
$this->fk_user_valid = $obj->fk_user_valid;
$this->date_stundenzettel = $this->db->jdate($obj->date_stundenzettel);
$this->datec = $this->db->jdate($obj->datec);
$this->date_valid = $this->db->jdate($obj->date_valid);
$this->status = $obj->status;
$this->note_private = $obj->note_private;
$this->note_public = $obj->note_public;
$this->hourly_rate = $obj->hourly_rate;
$this->hourly_rate_is_custom = $obj->hourly_rate_is_custom;
// Load lines
$this->fetchLeistungen();
$this->fetchProducts();
$this->fetchNotes();
return 1;
} else {
return 0;
}
} else {
$this->error = "Error ".$this->db->lasterror();
return -1;
}
}
/**
* Update object into database
*
* @param User $user User that modifies
* @param bool $notrigger false=launch triggers after, true=disable triggers
* @return int <0 if KO, >0 if OK
*/
public function update($user, $notrigger = false)
{
$error = 0;
$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
$sql .= " date_stundenzettel = '".$this->db->idate($this->date_stundenzettel)."',";
$sql .= " note_private = ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL").",";
$sql .= " note_public = ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "NULL").",";
$sql .= " hourly_rate = ".(isset($this->hourly_rate) && $this->hourly_rate !== null && $this->hourly_rate !== '' ? ((float)$this->hourly_rate) : "NULL").",";
$sql .= " hourly_rate_is_custom = ".((int)$this->hourly_rate_is_custom);
$sql .= " WHERE rowid = ".((int)$this->id);
dol_syslog(get_class($this)."::update", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if (!$error) {
return 1;
} else {
return -1;
}
}
/**
* Validate object
*
* @param User $user User that validates
* @return int <0 if KO, >0 if OK
*/
public function validate($user)
{
$error = 0;
$this->db->begin();
$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
$sql .= " status = ".self::STATUS_VALIDATED.",";
$sql .= " fk_user_valid = ".((int)$user->id).",";
$sql .= " date_valid = '".$this->db->idate(dol_now())."'";
$sql .= " WHERE rowid = ".((int)$this->id);
dol_syslog(get_class($this)."::validate", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if (!$error) {
$this->status = self::STATUS_VALIDATED;
$this->fk_user_valid = $user->id;
$this->date_valid = dol_now();
// Update tracking table
$this->updateTracking();
$this->db->commit();
return 1;
} else {
$this->db->rollback();
return -1;
}
}
/**
* Set to draft
*
* @param User $user User that reopens
* @return int <0 if KO, >0 if OK
*/
public function setDraft($user)
{
$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
$sql .= " status = ".self::STATUS_DRAFT.",";
$sql .= " fk_user_valid = NULL,";
$sql .= " date_valid = NULL";
$sql .= " WHERE rowid = ".((int)$this->id);
dol_syslog(get_class($this)."::setDraft", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql) {
$this->status = self::STATUS_DRAFT;
return 1;
} else {
$this->error = "Error ".$this->db->lasterror();
return -1;
}
}
/**
* Delete object in database
*
* @param User $user User that deletes
* @param bool $notrigger false=launch triggers after, true=disable triggers
* @return int <0 if KO, >0 if OK
*/
public function delete($user, $notrigger = false)
{
$error = 0;
$this->db->begin();
// Delete notes
$sql = "DELETE FROM ".MAIN_DB_PREFIX."stundenzettel_note WHERE fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
if (!$resql) $error++;
// Delete leistungen
$sql = "DELETE FROM ".MAIN_DB_PREFIX."stundenzettel_leistung WHERE fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
if (!$resql) $error++;
// Delete products
$sql = "DELETE FROM ".MAIN_DB_PREFIX."stundenzettel_product WHERE fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
if (!$resql) $error++;
// Delete main record
if (!$error) {
$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int)$this->id);
$resql = $this->db->query($sql);
if (!$resql) $error++;
}
if (!$error) {
$this->db->commit();
return 1;
} else {
$this->db->rollback();
return -1;
}
}
/**
* Load leistungen
*
* @return int <0 if KO, number of lines if OK
*/
public function fetchLeistungen()
{
$this->leistungen = array();
$sql = "SELECT l.rowid, l.fk_user, l.fk_product, l.date_leistung, l.time_start, l.time_end, l.duration, l.description, l.rang,";
$sql .= " p.ref as product_ref, p.label as product_label";
$sql .= " FROM ".MAIN_DB_PREFIX."stundenzettel_leistung as l";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product = p.rowid";
$sql .= " WHERE l.fk_stundenzettel = ".((int)$this->id);
$sql .= " ORDER BY l.rang, l.date_leistung, l.time_start";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$this->leistungen[] = $obj;
}
return count($this->leistungen);
}
return -1;
}
/**
* Load products
*
* @return int <0 if KO, number of lines if OK
*/
public function fetchProducts()
{
$this->products = array();
// Produkte laden, bei Freitext-Produkten Beschreibung aus commandedet holen falls leer
$sql = "SELECT sp.rowid, sp.fk_product, sp.fk_commandedet, sp.fk_manager_line,";
$sql .= " sp.product_ref, sp.product_label,";
$sql .= " CASE WHEN sp.description IS NULL OR sp.description = '' THEN cd.description ELSE sp.description END as description,";
$sql .= " sp.qty_original, sp.qty_done, sp.qty_cumulated, sp.origin, sp.rang";
$sql .= " FROM ".MAIN_DB_PREFIX."stundenzettel_product as sp";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commandedet as cd ON cd.rowid = sp.fk_commandedet";
$sql .= " WHERE sp.fk_stundenzettel = ".((int)$this->id);
$sql .= " ORDER BY sp.rang";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$this->products[] = $obj;
}
return count($this->products);
}
return -1;
}
/**
* Add a leistung
*
* @param User $user User
* @param string $date Date
* @param string $time_start Start time
* @param string $time_end End time
* @param string $description Description
* @return int <0 if KO, >0 if OK
*/
public function addLeistung($user, $date, $time_start = null, $time_end = null, $description = '', $fk_product = null)
{
global $langs;
// Calculate duration
$duration = 0;
if ($time_start && $time_end) {
$start = strtotime($time_start);
$end = strtotime($time_end);
$duration = ($end - $start) / 60; // in minutes
}
// Überlappungsprüfung: Prüfen ob für diese Zeit bereits eine Leistung existiert
if ($time_start && $time_end) {
$sqlCheck = "SELECT rowid, time_start, time_end FROM ".MAIN_DB_PREFIX."stundenzettel_leistung";
$sqlCheck .= " WHERE fk_stundenzettel = ".((int)$this->id);
$sqlCheck .= " AND time_start IS NOT NULL AND time_end IS NOT NULL";
$resqlCheck = $this->db->query($sqlCheck);
if ($resqlCheck) {
$newStart = strtotime($time_start);
$newEnd = strtotime($time_end);
while ($objCheck = $this->db->fetch_object($resqlCheck)) {
$existStart = strtotime($objCheck->time_start);
$existEnd = strtotime($objCheck->time_end);
// Überlappung: Start1 < End2 UND Start2 < End1
if ($newStart < $existEnd && $existStart < $newEnd) {
$this->error = $langs->trans("ErrorTimeOverlap", $objCheck->time_start, $objCheck->time_end);
return -2;
}
}
}
}
// Get next rang
$sql = "SELECT MAX(rang) as maxrang FROM ".MAIN_DB_PREFIX."stundenzettel_leistung WHERE fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
$rang = 0;
if ($resql) {
$obj = $this->db->fetch_object($resql);
$rang = $obj->maxrang + 1;
}
$sql = "INSERT INTO ".MAIN_DB_PREFIX."stundenzettel_leistung (";
$sql .= "fk_stundenzettel, fk_user, fk_product, date_leistung, time_start, time_end, duration, description, rang";
$sql .= ") VALUES (";
$sql .= ((int)$this->id).",";
$sql .= ((int)$user->id).",";
$sql .= ($fk_product > 0 ? ((int)$fk_product) : "NULL").",";
$sql .= "'".$this->db->idate($date)."',";
$sql .= ($time_start ? "'".$this->db->escape($time_start)."'" : "NULL").",";
$sql .= ($time_end ? "'".$this->db->escape($time_end)."'" : "NULL").",";
$sql .= ((int)$duration).",";
$sql .= "'".$this->db->escape($description)."',";
$sql .= ((int)$rang);
$sql .= ")";
$resql = $this->db->query($sql);
if ($resql) {
return $this->db->last_insert_id(MAIN_DB_PREFIX."stundenzettel_leistung");
}
return -1;
}
/**
* Update a leistung
*
* @param int $leistung_id Leistung ID
* @param string $date Date
* @param string $time_start Start time
* @param string $time_end End time
* @param string $description Description
* @param int $fk_product Product/Service ID
* @return int <0 if KO, >0 if OK
*/
public function updateLeistung($leistung_id, $date, $time_start = null, $time_end = null, $description = '', $fk_product = null)
{
global $langs;
// Calculate duration
$duration = 0;
if ($time_start && $time_end) {
$start = strtotime($time_start);
$end = strtotime($time_end);
$duration = ($end - $start) / 60; // in minutes
}
// Überlappungsprüfung: Prüfen ob für diese Zeit bereits eine andere Leistung existiert
if ($time_start && $time_end) {
$sqlCheck = "SELECT rowid, time_start, time_end FROM ".MAIN_DB_PREFIX."stundenzettel_leistung";
$sqlCheck .= " WHERE fk_stundenzettel = ".((int)$this->id);
$sqlCheck .= " AND rowid != ".((int)$leistung_id); // Aktuelle Leistung ausschließen
$sqlCheck .= " AND time_start IS NOT NULL AND time_end IS NOT NULL";
$resqlCheck = $this->db->query($sqlCheck);
if ($resqlCheck) {
$newStart = strtotime($time_start);
$newEnd = strtotime($time_end);
while ($objCheck = $this->db->fetch_object($resqlCheck)) {
$existStart = strtotime($objCheck->time_start);
$existEnd = strtotime($objCheck->time_end);
// Überlappung: Start1 < End2 UND Start2 < End1
if ($newStart < $existEnd && $existStart < $newEnd) {
$this->error = $langs->trans("ErrorTimeOverlap", $objCheck->time_start, $objCheck->time_end);
return -2;
}
}
}
}
$sql = "UPDATE ".MAIN_DB_PREFIX."stundenzettel_leistung SET";
$sql .= " fk_product = ".($fk_product > 0 ? ((int)$fk_product) : "NULL").",";
$sql .= " date_leistung = '".$this->db->idate($date)."',";
$sql .= " time_start = ".($time_start ? "'".$this->db->escape($time_start)."'" : "NULL").",";
$sql .= " time_end = ".($time_end ? "'".$this->db->escape($time_end)."'" : "NULL").",";
$sql .= " duration = ".((int)$duration).",";
$sql .= " description = '".$this->db->escape($description)."'";
$sql .= " WHERE rowid = ".((int)$leistung_id);
$sql .= " AND fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
if ($resql) {
return 1;
}
$this->error = $this->db->lasterror();
return -1;
}
/**
* Delete a leistung
*
* @param int $leistung_id Leistung ID
* @return int <0 if KO, >0 if OK
*/
public function deleteLeistung($leistung_id)
{
$sql = "DELETE FROM ".MAIN_DB_PREFIX."stundenzettel_leistung";
$sql .= " WHERE rowid = ".((int)$leistung_id);
$sql .= " AND fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
if ($resql) {
return 1;
}
$this->error = $this->db->lasterror();
return -1;
}
/**
* Add a product
*
* @param int $fk_product Product ID
* @param int $fk_commandedet Commandedet ID
* @param int $fk_manager_line Manager line ID
* @param float $qty_original Original qty
* @param float $qty_done Done qty
* @param string $origin Origin (order or added)
* @param string $description Description (for free-text products)
* @param string $product_label_override Label für Freitext-Produkte (ohne fk_product)
* @return int <0 if KO, >0 if OK
*/
public function addProduct($fk_product, $fk_commandedet = null, $fk_manager_line = null, $qty_original = 0, $qty_done = 0, $origin = 'order', $description = '', $product_label_override = '')
{
global $db;
// Get product info
$product_ref = '';
$product_label = '';
if ($fk_product > 0) {
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
$prod = new Product($this->db);
if ($prod->fetch($fk_product) > 0) {
$product_ref = $prod->ref;
$product_label = $prod->label;
}
}
// Override für Freitext-Produkte (kein fk_product, aber Label vorhanden)
if (!empty($product_label_override) && empty($product_label)) {
$product_label = $product_label_override;
}
// Get next rang
$sql = "SELECT MAX(rang) as maxrang FROM ".MAIN_DB_PREFIX."stundenzettel_product WHERE fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
$rang = 0;
if ($resql) {
$obj = $this->db->fetch_object($resql);
$rang = $obj->maxrang + 1;
}
$sql = "INSERT INTO ".MAIN_DB_PREFIX."stundenzettel_product (";
$sql .= "fk_stundenzettel, fk_product, fk_commandedet, fk_manager_line,";
$sql .= "product_ref, product_label, description, qty_original, qty_done, origin, rang";
$sql .= ") VALUES (";
$sql .= ((int)$this->id).",";
$sql .= ($fk_product > 0 ? (int)$fk_product : "NULL").",";
$sql .= ($fk_commandedet > 0 ? (int)$fk_commandedet : "NULL").",";
$sql .= ($fk_manager_line > 0 ? (int)$fk_manager_line : "NULL").",";
$sql .= "'".$this->db->escape($product_ref)."',";
$sql .= "'".$this->db->escape($product_label)."',";
$sql .= "'".$this->db->escape($description)."',";
$sql .= ((float)$qty_original).",";
$sql .= ((float)$qty_done).",";
$sql .= "'".$this->db->escape($origin)."',";
$sql .= ((int)$rang);
$sql .= ")";
$resql = $this->db->query($sql);
if ($resql) {
return $this->db->last_insert_id(MAIN_DB_PREFIX."stundenzettel_product");
}
return -1;
}
/**
* Update product qty_done
*
* @param int $line_id Line ID
* @param float $qty_done Done qty
* @return int <0 if KO, >0 if OK
*/
public function updateProductQty($line_id, $qty_done)
{
$sql = "UPDATE ".MAIN_DB_PREFIX."stundenzettel_product SET";
$sql .= " qty_done = ".((float)$qty_done);
$sql .= " WHERE rowid = ".((int)$line_id);
$sql .= " AND fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
return $resql ? 1 : -1;
}
/**
* Delete product from stundenzettel
*
* @param int $line_id Line ID
* @return int <0 if KO, >0 if OK
*/
public function deleteProduct($line_id)
{
$sql = "DELETE FROM ".MAIN_DB_PREFIX."stundenzettel_product";
$sql .= " WHERE rowid = ".((int)$line_id);
$sql .= " AND fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
return $resql ? 1 : -1;
}
/**
* Update tracking table
*
* @return int <0 if KO, >0 if OK
*/
public function updateTracking()
{
// Sum up all products for this order across all stundenzettels
foreach ($this->products as $prod) {
if (!$prod->fk_commandedet) continue;
// Get total done qty for this commandedet
$sql = "SELECT SUM(qty_done) as total_done FROM ".MAIN_DB_PREFIX."stundenzettel_product sp";
$sql .= " JOIN ".MAIN_DB_PREFIX."stundenzettel s ON s.rowid = sp.fk_stundenzettel";
$sql .= " WHERE sp.fk_commandedet = ".((int)$prod->fk_commandedet);
$sql .= " AND s.status >= ".self::STATUS_VALIDATED;
$resql = $this->db->query($sql);
$total_done = 0;
if ($resql && ($obj = $this->db->fetch_object($resql))) {
$total_done = $obj->total_done;
}
// Update or insert tracking
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."stundenzettel_tracking";
$sql .= " WHERE fk_commande = ".((int)$this->fk_commande);
$sql .= " AND fk_commandedet = ".((int)$prod->fk_commandedet);
$resql = $this->db->query($sql);
if ($resql && $this->db->num_rows($resql) > 0) {
// Update
$obj = $this->db->fetch_object($resql);
$remaining = $prod->qty_original - $total_done;
$status = 'open';
if ($total_done >= $prod->qty_original) {
$status = 'done';
} elseif ($total_done > 0) {
$status = 'partial';
}
$sql = "UPDATE ".MAIN_DB_PREFIX."stundenzettel_tracking SET";
$sql .= " qty_delivered = ".((float)$total_done).",";
$sql .= " qty_remaining = ".((float)$remaining).",";
$sql .= " status = '".$this->db->escape($status)."'";
$sql .= " WHERE rowid = ".((int)$obj->rowid);
$this->db->query($sql);
} else {
// Insert
$sql = "INSERT INTO ".MAIN_DB_PREFIX."stundenzettel_tracking (";
$sql .= "fk_commande, fk_product, fk_commandedet, fk_manager_line,";
$sql .= "product_ref, product_label, qty_ordered, qty_delivered, qty_remaining, status";
$sql .= ") VALUES (";
$sql .= ((int)$this->fk_commande).",";
$sql .= ($prod->fk_product > 0 ? (int)$prod->fk_product : "NULL").",";
$sql .= ((int)$prod->fk_commandedet).",";
$sql .= ($prod->fk_manager_line > 0 ? (int)$prod->fk_manager_line : "NULL").",";
$sql .= "'".$this->db->escape($prod->product_ref)."',";
$sql .= "'".$this->db->escape($prod->product_label)."',";
$sql .= ((float)$prod->qty_original).",";
$sql .= ((float)$total_done).",";
$sql .= ((float)($prod->qty_original - $total_done)).",";
$sql .= "'open'";
$sql .= ")";
$this->db->query($sql);
}
}
return 1;
}
/**
* Get next reference number
*
* @return string Next ref
*/
public function getNextNumRef()
{
global $conf;
$prefix = 'SZ';
$year = date('Y');
$sql = "SELECT MAX(CAST(SUBSTRING(ref, ".(strlen($prefix.$year.'-') + 1).") AS UNSIGNED)) as maxnum";
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
$sql .= " WHERE ref LIKE '".$this->db->escape($prefix.$year)."-%'";
$sql .= " AND entity = ".((int)$conf->entity);
$resql = $this->db->query($sql);
if ($resql) {
$obj = $this->db->fetch_object($resql);
$num = $obj->maxnum + 1;
} else {
$num = 1;
}
return $prefix.$year.'-'.sprintf('%05d', $num);
}
/**
* Get status label
*
* @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
* @return string Label
*/
public function getLibStatut($mode = 0)
{
return $this->LibStatut($this->status, $mode);
}
/**
* Return label of status
*
* @param int $status Status
* @param int $mode Mode
* @return string Label
*/
public function LibStatut($status, $mode = 0)
{
global $langs;
$langs->load("stundenzettel@stundenzettel");
if ($status == self::STATUS_DRAFT) {
$statusType = 'status0';
$label = $langs->trans("StatusDraft");
} elseif ($status == self::STATUS_VALIDATED) {
$statusType = 'status4';
$label = $langs->trans("StatusValidated");
} elseif ($status == self::STATUS_INVOICED) {
$statusType = 'status6';
$label = $langs->trans("StatusInvoiced");
} elseif ($status == self::STATUS_CANCELED) {
$statusType = 'status9';
$label = $langs->trans("StatusCanceled");
}
return dolGetStatus($label, '', '', $statusType, $mode);
}
/**
* Return URL link
*
* @param int $withpicto Picto
* @param string $option Option
* @return string Link
*/
public function getNomUrl($withpicto = 0, $option = '')
{
$result = '';
$url = dol_buildpath('/stundenzettel/card.php?id='.$this->id, 1);
$label = ''.$this->ref.'';
if ($withpicto) {
$result .= img_object('', $this->picto, 'class="pictofixedwidth"');
}
$result .= ''.$this->ref.'';
return $result;
}
/**
* Load notes (checkable memos)
*
* @return int <0 if KO, number of notes if OK
*/
public function fetchNotes()
{
$this->notes = array();
$sql = "SELECT rowid, fk_user, note, checked, rang, datec";
$sql .= " FROM ".MAIN_DB_PREFIX."stundenzettel_note";
$sql .= " WHERE fk_stundenzettel = ".((int)$this->id);
$sql .= " ORDER BY rang, datec";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$this->notes[] = $obj;
}
return count($this->notes);
}
return -1;
}
/**
* Add a note
*
* @param User $user User
* @param string $note Note text
* @return int <0 if KO, >0 if OK (rowid)
*/
public function addNote($user, $note)
{
if (empty($note)) {
return -1;
}
// Get next rang
$sql = "SELECT MAX(rang) as maxrang FROM ".MAIN_DB_PREFIX."stundenzettel_note WHERE fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
$rang = 0;
if ($resql) {
$obj = $this->db->fetch_object($resql);
$rang = $obj->maxrang + 1;
}
$sql = "INSERT INTO ".MAIN_DB_PREFIX."stundenzettel_note (";
$sql .= "fk_stundenzettel, fk_user, note, checked, rang, datec";
$sql .= ") VALUES (";
$sql .= ((int)$this->id).",";
$sql .= ((int)$user->id).",";
$sql .= "'".$this->db->escape($note)."',";
$sql .= "0,"; // not checked
$sql .= ((int)$rang).",";
$sql .= "'".$this->db->idate(dol_now())."'";
$sql .= ")";
$resql = $this->db->query($sql);
if ($resql) {
return $this->db->last_insert_id(MAIN_DB_PREFIX."stundenzettel_note");
}
return -1;
}
/**
* Update note checked status
*
* @param int $note_id Note ID
* @param int $checked 0=unchecked, 1=checked
* @return int <0 if KO, >0 if OK
*/
public function updateNoteStatus($note_id, $checked)
{
$sql = "UPDATE ".MAIN_DB_PREFIX."stundenzettel_note SET";
$sql .= " checked = ".((int)$checked);
$sql .= " WHERE rowid = ".((int)$note_id);
$sql .= " AND fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
return $resql ? 1 : -1;
}
/**
* Delete a note
*
* @param int $note_id Note ID
* @return int <0 if KO, >0 if OK
*/
public function deleteNote($note_id)
{
$sql = "DELETE FROM ".MAIN_DB_PREFIX."stundenzettel_note";
$sql .= " WHERE rowid = ".((int)$note_id);
$sql .= " AND fk_stundenzettel = ".((int)$this->id);
$resql = $this->db->query($sql);
return $resql ? 1 : -1;
}
/**
* Get unchecked notes (for display on order page)
*
* @return array Array of unchecked notes
*/
public function getUncheckedNotes()
{
$notes = array();
$sql = "SELECT rowid, fk_user, note, rang, datec";
$sql .= " FROM ".MAIN_DB_PREFIX."stundenzettel_note";
$sql .= " WHERE fk_stundenzettel = ".((int)$this->id);
$sql .= " AND checked = 0";
$sql .= " ORDER BY rang, datec";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$notes[] = $obj;
}
}
return $notes;
}
}