802 lines
22 KiB
PHP
Executable file
802 lines
22 KiB
PHP
Executable file
<?php
|
|
/* Copyright (C) 2026 Alles Watt lauft
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* Class FavoriteProduct
|
|
* Manages favorite products for customers
|
|
*/
|
|
class FavoriteProduct extends CommonObject
|
|
{
|
|
public $element = 'favoriteproduct';
|
|
public $table_element = 'kundenkarte_favorite_products';
|
|
|
|
public $fk_soc;
|
|
public $fk_contact;
|
|
public $fk_product;
|
|
public $qty;
|
|
public $rang;
|
|
public $note;
|
|
public $active;
|
|
public $date_creation;
|
|
public $fk_user_creat;
|
|
public $fk_user_modif;
|
|
|
|
// Loaded objects
|
|
public $product;
|
|
public $societe;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param DoliDB $db Database handler
|
|
*/
|
|
public function __construct($db)
|
|
{
|
|
$this->db = $db;
|
|
}
|
|
|
|
/**
|
|
* Create object in database
|
|
*
|
|
* @param User $user User that creates
|
|
* @param bool $notrigger false=launch triggers, true=disable triggers
|
|
* @return int Return integer <0 if KO, Id of created object if OK
|
|
*/
|
|
public function create($user, $notrigger = false)
|
|
{
|
|
global $conf;
|
|
|
|
$error = 0;
|
|
$now = dol_now();
|
|
|
|
// Check parameters
|
|
if (empty($this->fk_soc) || empty($this->fk_product)) {
|
|
$this->error = 'ErrorMissingParameters';
|
|
return -1;
|
|
}
|
|
|
|
// Check if already exists
|
|
if ($this->alreadyExists($this->fk_soc, $this->fk_product, $this->fk_contact)) {
|
|
$this->error = 'ErrorRecordAlreadyExists';
|
|
return -2;
|
|
}
|
|
|
|
$this->db->begin();
|
|
|
|
// Get max rang for this customer/contact to add at end of list
|
|
$maxRang = 0;
|
|
$sqlRang = "SELECT MAX(rang) as maxrang FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sqlRang .= " WHERE fk_soc = ".((int) $this->fk_soc);
|
|
if ($this->fk_contact > 0) {
|
|
$sqlRang .= " AND fk_contact = ".((int) $this->fk_contact);
|
|
} else {
|
|
$sqlRang .= " AND (fk_contact IS NULL OR fk_contact = 0)";
|
|
}
|
|
$sqlRang .= " AND entity = ".((int) $conf->entity);
|
|
$resRang = $this->db->query($sqlRang);
|
|
if ($resRang) {
|
|
$objRang = $this->db->fetch_object($resRang);
|
|
$maxRang = ($objRang->maxrang !== null) ? ((int) $objRang->maxrang + 1) : 0;
|
|
}
|
|
|
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
|
|
$sql .= "entity, fk_soc, fk_contact, fk_product, qty, rang, note, active, date_creation, fk_user_creat";
|
|
$sql .= ") VALUES (";
|
|
$sql .= ((int) $conf->entity);
|
|
$sql .= ", ".((int) $this->fk_soc);
|
|
$sql .= ", ".($this->fk_contact > 0 ? ((int) $this->fk_contact) : "NULL");
|
|
$sql .= ", ".((int) $this->fk_product);
|
|
$sql .= ", ".((float) ($this->qty > 0 ? $this->qty : 1));
|
|
$sql .= ", ".((int) $maxRang);
|
|
$sql .= ", ".($this->note ? "'".$this->db->escape($this->note)."'" : "NULL");
|
|
$sql .= ", ".((int) ($this->active !== null ? $this->active : 1));
|
|
$sql .= ", '".$this->db->idate($now)."'";
|
|
$sql .= ", ".((int) $user->id);
|
|
$sql .= ")";
|
|
|
|
$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);
|
|
$this->date_creation = $now;
|
|
$this->fk_user_creat = $user->id;
|
|
}
|
|
|
|
if ($error) {
|
|
$this->db->rollback();
|
|
return -1 * $error;
|
|
} else {
|
|
$this->db->commit();
|
|
return $this->id;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load object from database
|
|
*
|
|
* @param int $id ID of record
|
|
* @return int Return integer <0 if KO, 0 if not found, >0 if OK
|
|
*/
|
|
public function fetch($id)
|
|
{
|
|
global $conf;
|
|
|
|
$sql = "SELECT rowid, entity, fk_soc, fk_contact, fk_product, qty, rang, note, active,";
|
|
$sql .= " date_creation, tms, fk_user_creat, fk_user_modif";
|
|
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sql .= " WHERE rowid = ".((int) $id);
|
|
$sql .= " AND entity = ".((int) $conf->entity);
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
if ($this->db->num_rows($resql)) {
|
|
$obj = $this->db->fetch_object($resql);
|
|
|
|
$this->id = $obj->rowid;
|
|
$this->entity = $obj->entity;
|
|
$this->fk_soc = $obj->fk_soc;
|
|
$this->fk_contact = $obj->fk_contact;
|
|
$this->fk_product = $obj->fk_product;
|
|
$this->qty = $obj->qty;
|
|
$this->rang = $obj->rang;
|
|
$this->note = $obj->note;
|
|
$this->active = $obj->active;
|
|
$this->date_creation = $this->db->jdate($obj->date_creation);
|
|
$this->tms = $this->db->jdate($obj->tms);
|
|
$this->fk_user_creat = $obj->fk_user_creat;
|
|
$this->fk_user_modif = $obj->fk_user_modif;
|
|
|
|
$this->db->free($resql);
|
|
return 1;
|
|
} else {
|
|
$this->db->free($resql);
|
|
return 0;
|
|
}
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update object in database
|
|
*
|
|
* @param User $user User that modifies
|
|
* @param bool $notrigger false=launch triggers, true=disable triggers
|
|
* @return int Return integer <0 if KO, >0 if OK
|
|
*/
|
|
public function update($user, $notrigger = false)
|
|
{
|
|
$error = 0;
|
|
|
|
$this->db->begin();
|
|
|
|
$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
|
|
$sql .= " qty = ".((float) $this->qty);
|
|
$sql .= ", rang = ".((int) $this->rang);
|
|
$sql .= ", note = ".($this->note ? "'".$this->db->escape($this->note)."'" : "NULL");
|
|
$sql .= ", active = ".((int) $this->active);
|
|
$sql .= ", fk_user_modif = ".((int) $user->id);
|
|
$sql .= " WHERE rowid = ".((int) $this->id);
|
|
|
|
$resql = $this->db->query($sql);
|
|
if (!$resql) {
|
|
$error++;
|
|
$this->errors[] = "Error ".$this->db->lasterror();
|
|
}
|
|
|
|
if ($error) {
|
|
$this->db->rollback();
|
|
return -1 * $error;
|
|
} else {
|
|
$this->db->commit();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete object in database
|
|
*
|
|
* @param User $user User that deletes
|
|
* @param bool $notrigger false=launch triggers, true=disable triggers
|
|
* @return int Return integer <0 if KO, >0 if OK
|
|
*/
|
|
public function delete($user, $notrigger = false)
|
|
{
|
|
$error = 0;
|
|
|
|
$this->db->begin();
|
|
|
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sql .= " WHERE rowid = ".((int) $this->id);
|
|
|
|
$resql = $this->db->query($sql);
|
|
if (!$resql) {
|
|
$error++;
|
|
$this->errors[] = "Error ".$this->db->lasterror();
|
|
}
|
|
|
|
if ($error) {
|
|
$this->db->rollback();
|
|
return -1 * $error;
|
|
} else {
|
|
$this->db->commit();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a product is already a favorite for a customer/contact
|
|
*
|
|
* @param int $socid Customer ID
|
|
* @param int $productid Product ID
|
|
* @param int $contactid Contact ID (optional)
|
|
* @return bool
|
|
*/
|
|
public function alreadyExists($socid, $productid, $contactid = 0)
|
|
{
|
|
global $conf;
|
|
|
|
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sql .= " WHERE fk_soc = ".((int) $socid);
|
|
$sql .= " AND fk_product = ".((int) $productid);
|
|
if ($contactid > 0) {
|
|
$sql .= " AND fk_contact = ".((int) $contactid);
|
|
} else {
|
|
$sql .= " AND (fk_contact IS NULL OR fk_contact = 0)";
|
|
}
|
|
$sql .= " AND entity = ".((int) $conf->entity);
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
return ($this->db->num_rows($resql) > 0);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get all favorite products for a customer
|
|
*
|
|
* @param int $socid Customer ID
|
|
* @param int $activeonly Only active favorites
|
|
* @return array|int Array of FavoriteProduct objects or -1 if error
|
|
*/
|
|
public function fetchAllBySociete($socid, $activeonly = 1)
|
|
{
|
|
global $conf;
|
|
|
|
$results = array();
|
|
|
|
$sql = "SELECT fp.rowid, fp.fk_soc, fp.fk_product, fp.qty, fp.rang, fp.note, fp.active,";
|
|
$sql .= " p.ref as product_ref, p.label as product_label, p.price, p.price_ttc, p.tva_tx";
|
|
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as fp";
|
|
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON fp.fk_product = p.rowid";
|
|
$sql .= " WHERE fp.fk_soc = ".((int) $socid);
|
|
// Only thirdparty-level favorites, not contact-specific
|
|
$sql .= " AND (fp.fk_contact IS NULL OR fp.fk_contact = 0)";
|
|
$sql .= " AND fp.entity = ".((int) $conf->entity);
|
|
if ($activeonly) {
|
|
$sql .= " AND fp.active = 1";
|
|
}
|
|
$sql .= " ORDER BY fp.rang ASC, p.label ASC";
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
while ($obj = $this->db->fetch_object($resql)) {
|
|
$fav = new FavoriteProduct($this->db);
|
|
$fav->id = $obj->rowid;
|
|
$fav->fk_soc = $obj->fk_soc;
|
|
$fav->fk_product = $obj->fk_product;
|
|
$fav->qty = $obj->qty;
|
|
$fav->rang = $obj->rang;
|
|
$fav->note = $obj->note;
|
|
$fav->active = $obj->active;
|
|
|
|
// Product info
|
|
$fav->product_ref = $obj->product_ref;
|
|
$fav->product_label = $obj->product_label;
|
|
$fav->product_price = $obj->price;
|
|
$fav->product_price_ttc = $obj->price_ttc;
|
|
$fav->product_tva_tx = $obj->tva_tx;
|
|
|
|
$results[] = $fav;
|
|
}
|
|
$this->db->free($resql);
|
|
return $results;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Move a favorite product up in the list
|
|
*
|
|
* @param int $id Favorite ID to move
|
|
* @param int $socid Customer ID
|
|
* @return int 1 if OK, <0 if KO
|
|
*/
|
|
public function moveUp($id, $socid)
|
|
{
|
|
return $this->movePosition($id, $socid, 'up');
|
|
}
|
|
|
|
/**
|
|
* Move a favorite product down in the list
|
|
*
|
|
* @param int $id Favorite ID to move
|
|
* @param int $socid Customer ID
|
|
* @return int 1 if OK, <0 if KO
|
|
*/
|
|
public function moveDown($id, $socid)
|
|
{
|
|
return $this->movePosition($id, $socid, 'down');
|
|
}
|
|
|
|
/**
|
|
* Move a favorite product position
|
|
*
|
|
* @param int $id Favorite ID to move
|
|
* @param int $socid Customer ID
|
|
* @param string $direction 'up' or 'down'
|
|
* @return int 1 if OK, <0 if KO
|
|
*/
|
|
private function movePosition($id, $socid, $direction)
|
|
{
|
|
global $conf;
|
|
|
|
// Get all favorites ordered by rang
|
|
$sql = "SELECT rowid, rang FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sql .= " WHERE fk_soc = ".((int) $socid);
|
|
$sql .= " AND entity = ".((int) $conf->entity);
|
|
$sql .= " ORDER BY rang ASC, rowid ASC";
|
|
|
|
$resql = $this->db->query($sql);
|
|
if (!$resql) {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
|
|
$items = array();
|
|
$currentIndex = -1;
|
|
$i = 0;
|
|
while ($obj = $this->db->fetch_object($resql)) {
|
|
$items[$i] = array('id' => $obj->rowid, 'rang' => $i);
|
|
if ($obj->rowid == $id) {
|
|
$currentIndex = $i;
|
|
}
|
|
$i++;
|
|
}
|
|
$this->db->free($resql);
|
|
|
|
if ($currentIndex < 0) {
|
|
return 0; // Item not found
|
|
}
|
|
|
|
// Calculate new positions
|
|
$swapIndex = -1;
|
|
if ($direction == 'up' && $currentIndex > 0) {
|
|
$swapIndex = $currentIndex - 1;
|
|
} elseif ($direction == 'down' && $currentIndex < count($items) - 1) {
|
|
$swapIndex = $currentIndex + 1;
|
|
}
|
|
|
|
if ($swapIndex < 0) {
|
|
return 0; // Cannot move
|
|
}
|
|
|
|
// Swap positions
|
|
$this->db->begin();
|
|
|
|
$sql1 = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET rang = ".((int) $swapIndex);
|
|
$sql1 .= " WHERE rowid = ".((int) $items[$currentIndex]['id']);
|
|
|
|
$sql2 = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET rang = ".((int) $currentIndex);
|
|
$sql2 .= " WHERE rowid = ".((int) $items[$swapIndex]['id']);
|
|
|
|
if ($this->db->query($sql1) && $this->db->query($sql2)) {
|
|
$this->db->commit();
|
|
return 1;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
$this->db->rollback();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate an order from selected favorite products
|
|
*
|
|
* @param User $user User creating the order
|
|
* @param int $socid Customer ID
|
|
* @param array $selectedIds Array of favorite product IDs to include
|
|
* @param array $quantities Optional array of quantities (id => qty)
|
|
* @return int Order ID if OK, <0 if KO
|
|
*/
|
|
public function generateOrder($user, $socid, $selectedIds, $quantities = array())
|
|
{
|
|
global $conf, $langs, $mysoc;
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
|
|
|
if (empty($selectedIds)) {
|
|
$this->error = 'NoProductsSelected';
|
|
return -1;
|
|
}
|
|
|
|
// Load thirdparty (required for VAT calculation)
|
|
$societe = new Societe($this->db);
|
|
if ($societe->fetch($socid) <= 0) {
|
|
$this->error = 'ErrorLoadingThirdparty';
|
|
return -1;
|
|
}
|
|
|
|
// Fetch selected favorites
|
|
$favorites = $this->fetchAllBySociete($socid);
|
|
if (!is_array($favorites)) {
|
|
return -1;
|
|
}
|
|
|
|
// Filter to selected only
|
|
$toAdd = array();
|
|
foreach ($favorites as $fav) {
|
|
if (in_array($fav->id, $selectedIds)) {
|
|
$qty = isset($quantities[$fav->id]) ? (float) $quantities[$fav->id] : $fav->qty;
|
|
if ($qty > 0) {
|
|
$toAdd[] = array(
|
|
'product_id' => $fav->fk_product,
|
|
'qty' => $qty
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($toAdd)) {
|
|
$this->error = 'NoValidProductsToAdd';
|
|
return -2;
|
|
}
|
|
|
|
// Create order
|
|
$order = new Commande($this->db);
|
|
$order->socid = $socid;
|
|
$order->thirdparty = $societe; // Required for VAT calculation
|
|
$order->date = dol_now();
|
|
$order->ref_client = $societe->name.' - '.$langs->trans('FavoriteProducts'); // Ihr Zeichen
|
|
$order->note_private = $langs->trans('OrderGeneratedFromFavorites');
|
|
|
|
$this->db->begin();
|
|
|
|
// First create the order header
|
|
$result = $order->create($user);
|
|
|
|
if ($result <= 0) {
|
|
$this->error = $order->error;
|
|
$this->errors = $order->errors;
|
|
$this->db->rollback();
|
|
return -3;
|
|
}
|
|
|
|
// Now add products to the created order
|
|
foreach ($toAdd as $item) {
|
|
$product = new Product($this->db);
|
|
$product->fetch($item['product_id']);
|
|
|
|
// Get VAT rate for this product and customer (mysoc = seller, societe = buyer)
|
|
$tva_tx = get_default_tva($mysoc, $societe, $product->id);
|
|
$localtax1_tx = get_default_localtax($mysoc, $societe, 1, $product->id);
|
|
$localtax2_tx = get_default_localtax($mysoc, $societe, 2, $product->id);
|
|
|
|
$lineResult = $order->addline(
|
|
$product->label, // Description
|
|
$product->price, // Unit price HT
|
|
$item['qty'], // Quantity
|
|
$tva_tx, // VAT rate
|
|
$localtax1_tx, // Local tax 1
|
|
$localtax2_tx, // Local tax 2
|
|
$product->id, // Product ID
|
|
0, // Discount
|
|
0, // Info bits
|
|
0, // fk_remise_except
|
|
'HT', // Price base type
|
|
0, // Unit price TTC
|
|
'', // Date start
|
|
'', // Date end
|
|
0, // Type (0=product)
|
|
-1, // Rang
|
|
0, // Special code
|
|
0, // fk_parent_line
|
|
0, // fk_fournprice
|
|
0, // pa_ht
|
|
$product->label, // Label
|
|
array(), // Array options
|
|
$product->fk_unit // Unit
|
|
);
|
|
|
|
if ($lineResult < 0) {
|
|
$this->error = $order->error;
|
|
$this->errors = $order->errors;
|
|
$this->db->rollback();
|
|
return -4;
|
|
}
|
|
}
|
|
|
|
$this->db->commit();
|
|
return $order->id;
|
|
}
|
|
|
|
/**
|
|
* Get all favorite products for a contact/address
|
|
*
|
|
* @param int $contactid Contact ID
|
|
* @param int $activeonly Only active favorites
|
|
* @return array|int Array of FavoriteProduct objects or -1 if error
|
|
*/
|
|
public function fetchAllByContact($contactid, $activeonly = 1)
|
|
{
|
|
global $conf;
|
|
|
|
$results = array();
|
|
|
|
$sql = "SELECT fp.rowid, fp.fk_soc, fp.fk_contact, fp.fk_product, fp.qty, fp.rang, fp.note, fp.active,";
|
|
$sql .= " p.ref as product_ref, p.label as product_label, p.price, p.price_ttc, p.tva_tx";
|
|
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as fp";
|
|
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON fp.fk_product = p.rowid";
|
|
$sql .= " WHERE fp.fk_contact = ".((int) $contactid);
|
|
$sql .= " AND fp.entity = ".((int) $conf->entity);
|
|
if ($activeonly) {
|
|
$sql .= " AND fp.active = 1";
|
|
}
|
|
$sql .= " ORDER BY fp.rang ASC, p.label ASC";
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
while ($obj = $this->db->fetch_object($resql)) {
|
|
$fav = new FavoriteProduct($this->db);
|
|
$fav->id = $obj->rowid;
|
|
$fav->fk_soc = $obj->fk_soc;
|
|
$fav->fk_contact = $obj->fk_contact;
|
|
$fav->fk_product = $obj->fk_product;
|
|
$fav->qty = $obj->qty;
|
|
$fav->rang = $obj->rang;
|
|
$fav->note = $obj->note;
|
|
$fav->active = $obj->active;
|
|
|
|
// Product info
|
|
$fav->product_ref = $obj->product_ref;
|
|
$fav->product_label = $obj->product_label;
|
|
$fav->product_price = $obj->price;
|
|
$fav->product_price_ttc = $obj->price_ttc;
|
|
$fav->product_tva_tx = $obj->tva_tx;
|
|
|
|
$results[] = $fav;
|
|
}
|
|
$this->db->free($resql);
|
|
return $results;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Move a favorite product up in the list (for contact)
|
|
*
|
|
* @param int $id Favorite ID to move
|
|
* @param int $contactid Contact ID
|
|
* @return int 1 if OK, <0 if KO
|
|
*/
|
|
public function moveUpByContact($id, $contactid)
|
|
{
|
|
return $this->movePositionByContact($id, $contactid, 'up');
|
|
}
|
|
|
|
/**
|
|
* Move a favorite product down in the list (for contact)
|
|
*
|
|
* @param int $id Favorite ID to move
|
|
* @param int $contactid Contact ID
|
|
* @return int 1 if OK, <0 if KO
|
|
*/
|
|
public function moveDownByContact($id, $contactid)
|
|
{
|
|
return $this->movePositionByContact($id, $contactid, 'down');
|
|
}
|
|
|
|
/**
|
|
* Move a favorite product position (for contact)
|
|
*
|
|
* @param int $id Favorite ID to move
|
|
* @param int $contactid Contact ID
|
|
* @param string $direction 'up' or 'down'
|
|
* @return int 1 if OK, <0 if KO
|
|
*/
|
|
private function movePositionByContact($id, $contactid, $direction)
|
|
{
|
|
global $conf;
|
|
|
|
$sql = "SELECT rowid, rang FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sql .= " WHERE fk_contact = ".((int) $contactid);
|
|
$sql .= " AND entity = ".((int) $conf->entity);
|
|
$sql .= " ORDER BY rang ASC, rowid ASC";
|
|
|
|
$resql = $this->db->query($sql);
|
|
if (!$resql) {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
|
|
$items = array();
|
|
$currentIndex = -1;
|
|
$i = 0;
|
|
while ($obj = $this->db->fetch_object($resql)) {
|
|
$items[$i] = array('id' => $obj->rowid, 'rang' => $i);
|
|
if ($obj->rowid == $id) {
|
|
$currentIndex = $i;
|
|
}
|
|
$i++;
|
|
}
|
|
$this->db->free($resql);
|
|
|
|
if ($currentIndex < 0) {
|
|
return 0;
|
|
}
|
|
|
|
$swapIndex = -1;
|
|
if ($direction == 'up' && $currentIndex > 0) {
|
|
$swapIndex = $currentIndex - 1;
|
|
} elseif ($direction == 'down' && $currentIndex < count($items) - 1) {
|
|
$swapIndex = $currentIndex + 1;
|
|
}
|
|
|
|
if ($swapIndex < 0) {
|
|
return 0;
|
|
}
|
|
|
|
$this->db->begin();
|
|
|
|
$sql1 = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET rang = ".((int) $swapIndex);
|
|
$sql1 .= " WHERE rowid = ".((int) $items[$currentIndex]['id']);
|
|
|
|
$sql2 = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET rang = ".((int) $currentIndex);
|
|
$sql2 .= " WHERE rowid = ".((int) $items[$swapIndex]['id']);
|
|
|
|
if ($this->db->query($sql1) && $this->db->query($sql2)) {
|
|
$this->db->commit();
|
|
return 1;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
$this->db->rollback();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate an order from selected favorite products (for contact)
|
|
*
|
|
* @param User $user User creating the order
|
|
* @param int $socid Customer ID
|
|
* @param int $contactid Contact ID
|
|
* @param array $selectedIds Array of favorite product IDs to include
|
|
* @param array $quantities Optional array of quantities (id => qty)
|
|
* @return int Order ID if OK, <0 if KO
|
|
*/
|
|
public function generateOrderByContact($user, $socid, $contactid, $selectedIds, $quantities = array())
|
|
{
|
|
global $conf, $langs, $mysoc;
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
|
|
|
if (empty($selectedIds)) {
|
|
$this->error = 'NoProductsSelected';
|
|
return -1;
|
|
}
|
|
|
|
// Load thirdparty
|
|
$societe = new Societe($this->db);
|
|
if ($societe->fetch($socid) <= 0) {
|
|
$this->error = 'ErrorLoadingThirdparty';
|
|
return -1;
|
|
}
|
|
|
|
// Load contact
|
|
$contact = new Contact($this->db);
|
|
if ($contact->fetch($contactid) <= 0) {
|
|
$this->error = 'ErrorLoadingContact';
|
|
return -1;
|
|
}
|
|
|
|
// Fetch selected favorites
|
|
$favorites = $this->fetchAllByContact($contactid);
|
|
if (!is_array($favorites)) {
|
|
return -1;
|
|
}
|
|
|
|
// Filter to selected only
|
|
$toAdd = array();
|
|
foreach ($favorites as $fav) {
|
|
if (in_array($fav->id, $selectedIds)) {
|
|
$qty = isset($quantities[$fav->id]) ? (float) $quantities[$fav->id] : $fav->qty;
|
|
if ($qty > 0) {
|
|
$toAdd[] = array(
|
|
'product_id' => $fav->fk_product,
|
|
'qty' => $qty
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($toAdd)) {
|
|
$this->error = 'NoValidProductsToAdd';
|
|
return -2;
|
|
}
|
|
|
|
// Create order
|
|
$order = new Commande($this->db);
|
|
$order->socid = $socid;
|
|
$order->thirdparty = $societe;
|
|
$order->date = dol_now();
|
|
// Ihr Zeichen: Kunde - Kontakt/Adresse - Favoriten
|
|
$order->ref_client = $societe->name.' - '.$contact->getFullName($langs).' - '.$langs->trans('FavoriteProducts');
|
|
$order->note_private = $langs->trans('OrderGeneratedFromFavorites');
|
|
|
|
$this->db->begin();
|
|
|
|
$result = $order->create($user);
|
|
|
|
if ($result <= 0) {
|
|
$this->error = $order->error;
|
|
$this->errors = $order->errors;
|
|
$this->db->rollback();
|
|
return -3;
|
|
}
|
|
|
|
// Add products
|
|
foreach ($toAdd as $item) {
|
|
$product = new Product($this->db);
|
|
$product->fetch($item['product_id']);
|
|
|
|
$tva_tx = get_default_tva($mysoc, $societe, $product->id);
|
|
$localtax1_tx = get_default_localtax($mysoc, $societe, 1, $product->id);
|
|
$localtax2_tx = get_default_localtax($mysoc, $societe, 2, $product->id);
|
|
|
|
$lineResult = $order->addline(
|
|
$product->label,
|
|
$product->price,
|
|
$item['qty'],
|
|
$tva_tx,
|
|
$localtax1_tx,
|
|
$localtax2_tx,
|
|
$product->id,
|
|
0, 0, 0, 'HT', 0, '', '', 0, -1, 0, 0, 0, 0,
|
|
$product->label,
|
|
array(),
|
|
$product->fk_unit
|
|
);
|
|
|
|
if ($lineResult < 0) {
|
|
$this->error = $order->error;
|
|
$this->errors = $order->errors;
|
|
$this->db->rollback();
|
|
return -4;
|
|
}
|
|
}
|
|
|
|
$this->db->commit();
|
|
return $order->id;
|
|
}
|
|
}
|