1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/dolibarr_ynh.git synced 2024-09-03 18:35:53 +02:00
dolibarr_ynh/sources/dolibarr/htdocs/fourn/class/fournisseur.facture.class.php
Laurent Peuch e6008fc691 init
2015-09-28 22:09:38 +02:00

2178 lines
72 KiB
PHP

<?php
/* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
* Copyright (C) 2005 Marc Barilley <marc@ocebo.com>
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2013 Philippe Grand <philippe.grand@atoo-net.com>
* Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2015 Bahfir Abbes <bafbes@gmail.com>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/fourn/class/fournisseur.facture.class.php
* \ingroup fournisseur,facture
* \brief File of class to manage suppliers invoices
*/
include_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
/**
* Class to manage suppliers invoices
*/
class FactureFournisseur extends CommonInvoice
{
public $element='invoice_supplier';
public $table_element='facture_fourn';
public $table_element_line='facture_fourn_det';
public $fk_element='fk_facture_fourn';
protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
/**
* {@inheritdoc}
*/
protected $table_ref_field = 'ref';
var $rowid;
var $ref;
var $product_ref;
var $ref_supplier;
var $socid;
//Check constants for types
var $type = self::TYPE_STANDARD;
/**
* Supplier invoice status
* @var int
* @see FactureFournisseur::STATUS_DRAFT, FactureFournisseur::STATUS_VALIDATED, FactureFournisseur::STATUS_PAID, FactureFournisseur::STATUS_ABANDONED
*/
var $statut;
//! 1 si facture payee COMPLETEMENT, 0 sinon (ce champ ne devrait plus servir car insuffisant)
var $paye;
var $author;
var $libelle;
var $datec; // Creation date
var $tms; // Last update date
var $date; // Invoice date
var $date_echeance; // Max payment date
var $amount;
var $remise;
var $tva;
var $localtax1;
var $localtax2;
var $total_ht;
var $total_tva;
var $total_localtax1;
var $total_localtax2;
var $total_ttc;
/**
* @deprecated
* @see note_private, note_public
*/
var $note;
var $note_private;
var $note_public;
var $propalid;
var $cond_reglement_id;
var $cond_reglement_code;
var $fk_account;
var $mode_reglement_id;
var $mode_reglement_code;
/**
* Invoice lines
* @var SupplierInvoiceLine[]
*/
public $lines = array();
/**
* @deprecated
*/
var $fournisseur;
//Incorterms
var $fk_incoterms;
var $location_incoterms;
var $libelle_incoterms; //Used into tooltip
var $extraparams=array();
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
function __construct($db)
{
$this->db = $db;
$this->amount = 0;
$this->remise = 0;
$this->tva = 0;
$this->total_localtax1 = 0;
$this->total_localtax2 = 0;
$this->total_ht = 0;
$this->total_tva = 0;
$this->total_ttc = 0;
$this->propalid = 0;
$this->products = array();
}
/**
* Create supplier invoice into database
*
* @param User $user object utilisateur qui cree
* @return int id facture si ok, < 0 si erreur
*/
function create($user)
{
global $langs,$conf,$hookmanager;
$error=0;
$now=dol_now();
// Clean parameters
if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier);
if (empty($this->date)) $this->date=$now;
$socid = $this->socid;
$ref_supplier = $this->ref_supplier;
$amount = $this->amount;
$remise = $this->remise;
$this->db->begin();
if (! $remise) $remise = 0 ;
$totalht = ($amount - $remise);
$sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_fourn (";
$sql.= "ref";
$sql.= ", ref_supplier";
$sql.= ", entity";
$sql.= ", libelle";
$sql.= ", fk_soc";
$sql.= ", datec";
$sql.= ", datef";
$sql.= ", fk_projet";
$sql.= ", fk_cond_reglement";
$sql.= ", fk_mode_reglement";
$sql.= ", fk_account";
$sql.= ", note_private";
$sql.= ", note_public";
$sql.= ", fk_user_author";
$sql.= ", date_lim_reglement";
$sql.= ", fk_incoterms, location_incoterms";
$sql.= ")";
$sql.= " VALUES (";
$sql.= "'(PROV)'";
$sql.= ", '".$this->db->escape($this->ref_supplier)."'";
$sql.= ", ".$conf->entity;
$sql.= ", '".$this->db->escape($this->libelle)."'";
$sql.= ", ".$this->socid;
$sql.= ", '".$this->db->idate($now)."'";
$sql.= ", '".$this->db->idate($this->date)."'";
$sql.= ", ".(isset($this->fk_project)?$this->fk_project:"null");
$sql.= ", ".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null");
$sql.= ", ".(isset($this->mode_reglement_id)?$this->mode_reglement_id:"null");
$sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
$sql.= ", '".$this->db->escape($this->note_private)."'";
$sql.= ", '".$this->db->escape($this->note_public)."'";
$sql.= ", ".$user->id.",";
$sql.= $this->date_echeance!=''?"'".$this->db->idate($this->date_echeance)."'":"null";
$sql.= ", ".(int) $this->fk_incoterms;
$sql.= ", '".$this->db->escape($this->location_incoterms)."'";
$sql.= ")";
dol_syslog(get_class($this)."::create", LOG_DEBUG);
$resql=$this->db->query($sql);
if ($resql)
{
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn');
// Update ref with new one
$this->ref='(PROV'.$this->id.')';
$sql = 'UPDATE '.MAIN_DB_PREFIX."facture_fourn SET ref='".$this->ref."' WHERE rowid=".$this->id;
dol_syslog(get_class($this)."::create", LOG_DEBUG);
$resql=$this->db->query($sql);
if (! $resql) $error++;
// Add object linked
if (! $error && $this->id && ! empty($this->origin) && ! empty($this->origin_id))
{
$ret = $this->add_object_linked();
if (! $ret)
{
dol_print_error($this->db);
$error++;
}
}
foreach ($this->lines as $i => $val)
{
$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn)';
$sql .= ' VALUES ('.$this->id.');';
dol_syslog(get_class($this)."::create", LOG_DEBUG);
$resql_insert=$this->db->query($sql);
if ($resql_insert)
{
$idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
$this->updateline(
$idligne,
$this->lines[$i]->description,
$this->lines[$i]->pu_ht,
$this->lines[$i]->tva_tx,
$this->lines[$i]->localtax1_tx,
$this->lines[$i]->localtax2_tx,
$this->lines[$i]->qty,
$this->lines[$i]->fk_product,
'HT',
(! empty($this->lines[$i]->info_bits)?$this->lines[$i]->info_bits:''),
$this->lines[$i]->product_type
);
}
}
// Update total price
$result=$this->update_price();
if ($result > 0)
{
$action='create';
// Actions on extra fields (by external module or standard code)
// TODO le hook fait double emploi avec le trigger !!
$hookmanager->initHooks(array('supplierinvoicedao'));
$parameters=array('socid'=>$this->id);
$reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
if (empty($reshook))
{
if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
{
$result=$this->insertExtraFields(); // This also set $this->error or $this->errors if errors are found
if ($result < 0)
{
$error++;
}
}
}
else if ($reshook < 0) $error++;
if (! $error)
{
// Call trigger
$result=$this->call_trigger('BILL_SUPPLIER_CREATE',$user);
if ($result < 0) $error++;
// End call triggers
}
if (! $error)
{
$this->db->commit();
return $this->id;
}
else
{
$this->db->rollback();
return -4;
}
}
else
{
$this->error=$langs->trans('FailedToUpdatePrice');
$this->db->rollback();
return -3;
}
}
else
{
if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
{
$this->error=$langs->trans('ErrorRefAlreadyExists');
$this->db->rollback();
return -1;
}
else
{
$this->error=$this->db->lasterror();
$this->db->rollback();
return -2;
}
}
}
/**
* Load object in memory from database
*
* @param int $id Id supplier invoice
* @param string $ref Ref supplier invoice
* @return int <0 if KO, >0 if OK, 0 if not found
*/
function fetch($id='',$ref='')
{
global $langs;
$sql = "SELECT";
$sql.= " t.rowid,";
$sql.= " t.ref,";
$sql.= " t.ref_supplier,";
$sql.= " t.entity,";
$sql.= " t.type,";
$sql.= " t.fk_soc,";
$sql.= " t.datec,";
$sql.= " t.datef,";
$sql.= " t.tms,";
$sql.= " t.libelle,";
$sql.= " t.paye,";
$sql.= " t.amount,";
$sql.= " t.remise,";
$sql.= " t.close_code,";
$sql.= " t.close_note,";
$sql.= " t.tva,";
$sql.= " t.localtax1,";
$sql.= " t.localtax2,";
$sql.= " t.total,";
$sql.= " t.total_ht,";
$sql.= " t.total_tva,";
$sql.= " t.total_ttc,";
$sql.= " t.fk_statut,";
$sql.= " t.fk_user_author,";
$sql.= " t.fk_user_valid,";
$sql.= " t.fk_facture_source,";
$sql.= " t.fk_projet,";
$sql.= " t.fk_cond_reglement,";
$sql.= " t.fk_account,";
$sql.= " t.fk_mode_reglement,";
$sql.= " t.date_lim_reglement,";
$sql.= " t.note_private,";
$sql.= " t.note_public,";
$sql.= " t.model_pdf,";
$sql.= " t.import_key,";
$sql.= " t.extraparams,";
$sql.= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle,";
$sql.= " p.code as mode_reglement_code, p.libelle as mode_reglement_libelle,";
$sql.= ' s.nom as socnom, s.rowid as socid,';
$sql.= ' t.fk_incoterms, t.location_incoterms,';
$sql.= " i.libelle as libelle_incoterms";
$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as t';
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON (t.fk_soc = s.rowid)";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON (t.fk_cond_reglement = cr.rowid)";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON (t.fk_mode_reglement = p.id)";
$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON t.fk_incoterms = i.rowid';
if ($id) $sql.= " WHERE t.rowid=".$id;
if ($ref) $sql.= " WHERE t.ref='".$this->db->escape($ref)."'";
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?$obj->ref:$obj->rowid; // We take rowid if ref is empty for backward compatibility
$this->ref_supplier = $obj->ref_supplier;
$this->entity = $obj->entity;
$this->type = empty($obj->type)? self::TYPE_STANDARD:$obj->type;
$this->fk_soc = $obj->fk_soc;
$this->datec = $this->db->jdate($obj->datec);
$this->date = $this->db->jdate($obj->datef);
$this->datep = $this->db->jdate($obj->datef);
$this->tms = $this->db->jdate($obj->tms);
$this->libelle = $obj->libelle;
$this->label = $obj->libelle;
$this->paye = $obj->paye;
$this->amount = $obj->amount;
$this->remise = $obj->remise;
$this->close_code = $obj->close_code;
$this->close_note = $obj->close_note;
$this->tva = $obj->tva;
$this->total_localtax1 = $obj->localtax1;
$this->total_localtax2 = $obj->localtax2;
$this->total = $obj->total;
$this->total_ht = $obj->total_ht;
$this->total_tva = $obj->total_tva;
$this->total_ttc = $obj->total_ttc;
$this->fk_statut = $obj->fk_statut;
$this->statut = $obj->fk_statut;
$this->fk_user_author = $obj->fk_user_author;
$this->author = $obj->fk_user_author;
$this->fk_user_valid = $obj->fk_user_valid;
$this->fk_facture_source = $obj->fk_facture_source;
$this->fk_project = $obj->fk_projet;
$this->cond_reglement_id = $obj->fk_cond_reglement;
$this->cond_reglement_code = $obj->cond_reglement_code;
$this->cond_reglement = $obj->cond_reglement_libelle;
$this->cond_reglement_doc = $obj->cond_reglement_libelle;
$this->fk_account = $obj->fk_account;
$this->mode_reglement_id = $obj->fk_mode_reglement;
$this->mode_reglement_code = $obj->mode_reglement_code;
$this->mode_reglement = $obj->mode_reglement_libelle;
$this->date_echeance = $this->db->jdate($obj->date_lim_reglement);
$this->note = $obj->note_private; // deprecated
$this->note_private = $obj->note_private;
$this->note_public = $obj->note_public;
$this->model_pdf = $obj->model_pdf;
$this->modelpdf = $obj->model_pdf;
$this->import_key = $obj->import_key;
//Incoterms
$this->fk_incoterms = $obj->fk_incoterms;
$this->location_incoterms = $obj->location_incoterms;
$this->libelle_incoterms = $obj->libelle_incoterms;
$this->extraparams = (array) json_decode($obj->extraparams, true);
$this->socid = $obj->socid;
$this->socnom = $obj->socnom;
// Retreive all extrafield
// fetch optionals attributes and labels
require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
$extrafields=new ExtraFields($this->db);
$extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
$this->fetch_optionals($this->id,$extralabels);
if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1;
$result=$this->fetch_lines();
if ($result < 0)
{
$this->error=$this->db->lasterror();
return -3;
}
}
else
{
$this->error='Bill with id '.$id.' not found';
dol_syslog(get_class($this).'::fetch '.$this->error);
return 0;
}
$this->db->free($resql);
return 1;
}
else
{
$this->error="Error ".$this->db->lasterror();
return -1;
}
}
/**
* Load this->lines
*
* @return int 1 si ok, < 0 si erreur
*/
function fetch_lines()
{
$sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.tva_tx';
$sql.= ', f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2 ';
$sql.= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit';
$sql.= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
$sql.= ' WHERE fk_facture_fourn='.$this->id;
$sql.= ' ORDER BY f.rang, f.rowid';
dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
$resql_rows = $this->db->query($sql);
if ($resql_rows)
{
$num_rows = $this->db->num_rows($resql_rows);
if ($num_rows)
{
$i = 0;
while ($i < $num_rows)
{
$obj = $this->db->fetch_object($resql_rows);
$line = new SupplierInvoiceLine($this->db);
$line->id = $obj->rowid;
$line->rowid = $obj->rowid;
$line->description = $obj->description;
$line->product_ref = $obj->product_ref;
$line->ref = $obj->product_ref;
$line->ref_supplier = $obj->ref_supplier;
$line->libelle = $obj->label;
$line->label = $obj->label;
$line->product_desc = $obj->product_desc;
$line->subprice = $obj->pu_ht;
$line->pu_ht = $obj->pu_ht;
$line->pu_ttc = $obj->pu_ttc;
$line->tva_tx = $obj->tva_tx;
$line->localtax1_tx = $obj->localtax1_tx;
$line->localtax2_tx = $obj->localtax2_tx;
$line->qty = $obj->qty;
$line->remise_percent = $obj->remise_percent;
$line->tva = $obj->total_tva;
$line->total_ht = $obj->total_ht;
$line->total_tva = $obj->total_tva;
$line->total_localtax1 = $obj->total_localtax1;
$line->total_localtax2 = $obj->total_localtax2;
$line->total_ttc = $obj->total_ttc;
$line->fk_product = $obj->fk_product;
$line->product_type = $obj->product_type;
$line->product_label = $obj->label;
$line->info_bits = $obj->info_bits;
$line->fk_parent_line = $obj->fk_parent_line;
$line->special_code = $obj->special_code;
$line->rang = $obj->rang;
$line->fk_unit = $obj->fk_unit;
$this->lines[$i] = $line;
$i++;
}
}
$this->db->free($resql_rows);
return 1;
}
else
{
$this->error=$this->db->error();
return -3;
}
}
/**
* Update database
*
* @param User $user User that modify
* @param int $notrigger 0=launch triggers after, 1=disable triggers
* @return int <0 if KO, >0 if OK
*/
function update($user=null, $notrigger=0)
{
global $conf, $langs;
$error=0;
// Clean parameters
if (isset($this->ref)) $this->ref=trim($this->ref);
if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier);
if (isset($this->entity)) $this->entity=trim($this->entity);
if (isset($this->type)) $this->type=trim($this->type);
if (isset($this->fk_soc)) $this->fk_soc=trim($this->fk_soc);
if (isset($this->libelle)) $this->libelle=trim($this->libelle);
if (isset($this->paye)) $this->paye=trim($this->paye);
if (isset($this->amount)) $this->amount=trim($this->amount);
if (isset($this->remise)) $this->remise=trim($this->remise);
if (isset($this->close_code)) $this->close_code=trim($this->close_code);
if (isset($this->close_note)) $this->close_note=trim($this->close_note);
if (isset($this->tva)) $this->tva=trim($this->tva);
if (isset($this->localtax1)) $this->localtax1=trim($this->localtax1);
if (isset($this->localtax2)) $this->localtax2=trim($this->localtax2);
if (empty($this->total)) $this->total=0;
if (empty($this->total_ht)) $this->total_ht=0;
if (empty($this->total_tva)) $this->total_tva=0;
// if (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1);
// if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2);
if (isset($this->total_ttc)) $this->total_ttc=trim($this->total_ttc);
if (isset($this->statut)) $this->statut=(int) $this->statut;
if (isset($this->author)) $this->author=trim($this->author);
if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid);
if (isset($this->fk_facture_source)) $this->fk_facture_source=trim($this->fk_facture_source);
if (isset($this->fk_project)) $this->fk_project=trim($this->fk_project);
if (isset($this->cond_reglement_id)) $this->cond_reglement_id=trim($this->cond_reglement_id);
if (isset($this->note_private)) $this->note=trim($this->note_private);
if (isset($this->note_public)) $this->note_public=trim($this->note_public);
if (isset($this->model_pdf)) $this->model_pdf=trim($this->model_pdf);
if (isset($this->import_key)) $this->import_key=trim($this->import_key);
// Check parameters
// Put here code to add control on parameters values
// Update request
$sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn SET";
$sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").",";
$sql.= " ref_supplier=".(isset($this->ref_supplier)?"'".$this->db->escape($this->ref_supplier)."'":"null").",";
$sql.= " entity=".(isset($this->entity)?$this->entity:"null").",";
$sql.= " type=".(isset($this->type)?$this->type:"null").",";
$sql.= " fk_soc=".(isset($this->fk_soc)?$this->fk_soc:"null").",";
$sql.= " datec=".(dol_strlen($this->datec)!=0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
$sql.= " datef=".(dol_strlen($this->date)!=0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
if (dol_strlen($this->tms) != 0) $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
$sql.= " libelle=".(isset($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
$sql.= " paye=".(isset($this->paye)?$this->paye:"null").",";
$sql.= " amount=".(isset($this->amount)?$this->amount:"null").",";
$sql.= " remise=".(isset($this->remise)?$this->remise:"null").",";
$sql.= " close_code=".(isset($this->close_code)?"'".$this->db->escape($this->close_code)."'":"null").",";
$sql.= " close_note=".(isset($this->close_note)?"'".$this->db->escape($this->close_note)."'":"null").",";
$sql.= " tva=".(isset($this->tva)?$this->tva:"null").",";
$sql.= " localtax1=".(isset($this->localtax1)?$this->localtax1:"null").",";
$sql.= " localtax2=".(isset($this->localtax2)?$this->localtax2:"null").",";
$sql.= " total=".(isset($this->total)?$this->total:"null").",";
$sql.= " total_ht=".(isset($this->total_ht)?$this->total_ht:"null").",";
$sql.= " total_tva=".(isset($this->total_tva)?$this->total_tva:"null").",";
$sql.= " total_ttc=".(isset($this->total_ttc)?$this->total_ttc:"null").",";
$sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").",";
$sql.= " fk_user_author=".(isset($this->author)?$this->author:"null").",";
$sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").",";
$sql.= " fk_facture_source=".(isset($this->fk_facture_source)?$this->fk_facture_source:"null").",";
$sql.= " fk_projet=".(isset($this->fk_project)?$this->fk_project:"null").",";
$sql.= " fk_cond_reglement=".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null").",";
$sql.= " date_lim_reglement=".(dol_strlen($this->date_echeance)!=0 ? "'".$this->db->idate($this->date_echeance)."'" : 'null').",";
$sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").",";
$sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").",";
$sql.= " model_pdf=".(isset($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null").",";
$sql.= " import_key=".(isset($this->import_key)?"'".$this->db->escape($this->import_key)."'":"null")."";
$sql.= " WHERE rowid=".$this->id;
$this->db->begin();
dol_syslog(get_class($this)."::update", LOG_DEBUG);
$resql = $this->db->query($sql);
if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
if (! $error)
{
if (! $notrigger)
{
// Call trigger
$result=$this->call_trigger('BILL_SUPPLIER_UPDATE',$user);
if ($result < 0) $error++;
// End call triggers
}
}
// Commit or rollback
if ($error)
{
foreach($this->errors as $errmsg)
{
dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
$this->error.=($this->error?', '.$errmsg:$errmsg);
}
$this->db->rollback();
return -1*$error;
}
else
{
$this->db->commit();
return 1;
}
}
/**
* Delete invoice from database
*
* @param int $rowid Id of invoice to delete
* @return int <0 if KO, >0 if OK
*/
function delete($rowid)
{
global $user,$langs,$conf;
if (! $rowid) $rowid=$this->id;
dol_syslog("FactureFournisseur::delete rowid=".$rowid, LOG_DEBUG);
// TODO Test if there is at least on payment. If yes, refuse to delete.
$error=0;
$this->db->begin();
$sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det WHERE fk_facture_fourn = '.$rowid.';';
dol_syslog(get_class($this)."::delete", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
$sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn WHERE rowid = '.$rowid;
dol_syslog(get_class($this)."::delete", LOG_DEBUG);
$resql2 = $this->db->query($sql);
if (! $resql2) {
$error++;
}
}
else {
$error++;
}
if (! $error)
{
// Delete linked object
$res = $this->deleteObjectLinked();
if ($res < 0) $error++;
}
if (! $error)
{
// Call trigger
$result=$this->call_trigger('BILL_SUPPLIER_DELETE',$user);
if ($result < 0)
{
$this->db->rollback();
return -1;
}
// Fin appel triggers
}
if (! $error)
{
// Delete linked object
$res = $this->deleteObjectLinked();
if ($res < 0) $error++;
}
if (! $error)
{
// We remove directory
if ($conf->fournisseur->facture->dir_output)
{
include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
$ref = dol_sanitizeFileName($this->ref);
$dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id, 2, 0, 0, $this, 'invoive_supplier').$ref;
$file = $dir . "/" . $ref . ".pdf";
if (file_exists($file))
{
if (! dol_delete_file($file,0,0,0,$this)) // For triggers
{
$this->error='ErrorFailToDeleteFile';
$error++;
}
}
if (file_exists($dir))
{
$res=@dol_delete_dir_recursive($dir);
if (! $res)
{
$this->error='ErrorFailToDeleteDir';
$error++;
}
}
}
}
// Remove extrafields
if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
{
$result=$this->deleteExtraFields();
if ($result < 0)
{
$error++;
dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
}
}
if (! $error)
{
dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
$this->db->commit();
return 1;
}
else
{
$this->error=$this->db->lasterror();
$this->db->rollback();
return -$error;
}
}
/**
* Tag invoice as a payed invoice
*
* @param User $user Object user
* @return int <0 si ko, >0 si ok
*/
function set_paid($user)
{
global $conf,$langs;
$error=0;
$this->db->begin();
$sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
$sql.= ' SET paye = 1, fk_statut=2';
$sql.= ' WHERE rowid = '.$this->id;
dol_syslog("FactureFournisseur::set_paid", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
// Call trigger
$result=$this->call_trigger('BILL_SUPPLIER_PAYED',$user);
if ($result < 0) $error++;
// End call triggers
}
else
{
$error++;
$this->error=$this->db->error();
dol_print_error($this->db);
}
if (! $error)
{
$this->db->commit();
return 1;
}
else
{
$this->db->rollback();
return -1;
}
}
/**
* Tag la facture comme non payee completement + appel trigger BILL_UNPAYED
* Fonction utilisee quand un paiement prelevement est refuse,
* ou quand une facture annulee et reouverte.
*
* @param User $user Object user that change status
* @return int <0 si ok, >0 si ok
*/
function set_unpaid($user)
{
global $conf,$langs;
$error=0;
$this->db->begin();
$sql = 'UPDATE '.MAIN_DB_PREFIX.'facture_fourn';
$sql.= ' SET paye=0, fk_statut=1, close_code=null, close_note=null';
$sql.= ' WHERE rowid = '.$this->id;
dol_syslog("FactureFournisseur::set_unpaid", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
// Call trigger
$result=$this->call_trigger('BILL_SUPPLIER_UNPAYED',$user);
if ($result < 0) $error++;
// End call triggers
}
else
{
$error++;
$this->error=$this->db->lasterror();
dol_syslog("FactureFournisseur::set_unpaid ".$this->error);
}
if (! $error)
{
$this->db->commit();
return 1;
}
else
{
$this->db->rollback();
return -1;
}
}
/**
* Tag invoice as validated + call trigger BILL_VALIDATE
*
* @param User $user Object user that validate
* @param string $force_number Reference to force on invoice
* @param int $idwarehouse Id of warehouse for stock change
* @param int $notrigger 1=Does not execute triggers, 0= execuete triggers
* @return int <0 if KO, =0 if nothing to do, >0 if OK
*/
function validate($user, $force_number='', $idwarehouse=0, $notrigger=0)
{
global $conf,$langs;
$error=0;
// Protection
if ($this->statut > self::STATUS_DRAFT) // This is to avoid to validate twice (avoid errors on logs and stock management)
{
dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING);
return 0;
}
// Check parameters
if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->ref_supplier))
{
$this->error=$langs->trans("ErrorFieldFormat",$langs->transnoentities("RefSupplier"));
return -1;
}
$this->db->begin();
// Define new ref
if ($force_number)
{
$num = $force_number;
}
else if (preg_match('/^[\(]?PROV/i', $this->ref))
{
$num = $this->getNextNumRef($this->client);
}
else
{
$num = $this->ref;
}
$this->newref = $num;
$sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
$sql.= " SET ref='".$num."', fk_statut = 1, fk_user_valid = ".$user->id;
$sql.= " WHERE rowid = ".$this->id;
dol_syslog(get_class($this)."::validate", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
// Si on incrémente le produit principal et ses composants à la validation de facture fournisseur
if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL))
{
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
$langs->load("agenda");
$cpt=count($this->lines);
for ($i = 0; $i < $cpt; $i++)
{
if ($this->lines[$i]->fk_product > 0)
{
$mouvP = new MouvementStock($this->db);
$mouvP->origin = &$this;
// We increase stock for product
$up_ht_disc=$this->lines[$i]->pu_ht;
if (! empty($this->lines[$i]->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) $up_ht_disc=price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
$result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr",$num));
if ($result < 0) { $error++; }
}
}
}
// Triggers call
if (! $error && empty($notrigger))
{
// Call trigger
$result=$this->call_trigger('BILL_SUPPLIER_VALIDATE',$user);
if ($result < 0) $error++;
// End call triggers
}
if (! $error)
{
$this->oldref = $this->ref;
// Rename directory if dir was a temporary ref
if (preg_match('/^[\(]?PROV/i', $this->ref))
{
// On renomme repertoire facture ($this->ref = ancienne ref, $num = nouvelle ref)
// in order not to lose the attached files
$oldref = dol_sanitizeFileName($this->ref);
$newref = dol_sanitizeFileName($num);
$dirsource = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id,2,0,0, $this, 'invoive_supplier').$oldref;
$dirdest = $conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id,2,0,0, $this, 'invoive_supplier').$newref;
if (file_exists($dirsource))
{
dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
if (@rename($dirsource, $dirdest))
{
dol_syslog("Rename ok");
// Rename docs starting with $oldref with $newref
$listoffiles=dol_dir_list($conf->fournisseur->facture->dir_output.'/'.get_exdir($this->id,2,0,0, $this, 'invoive_supplier').$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
foreach($listoffiles as $fileentry)
{
$dirsource=$fileentry['name'];
$dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
$dirsource=$fileentry['path'].'/'.$dirsource;
$dirdest=$fileentry['path'].'/'.$dirdest;
@rename($dirsource, $dirdest);
}
}
}
}
}
// Set new ref and define current statut
if (! $error)
{
$this->ref = $num;
$this->statut=self::STATUS_VALIDATED;
//$this->date_validation=$now; this is stored into log table
}
if (! $error)
{
$this->db->commit();
return 1;
}
else
{
$this->db->rollback();
return -1;
}
}
else
{
$this->error=$this->db->error();
$this->db->rollback();
return -1;
}
}
/**
* Set draft status
*
* @param User $user Object user that modify
* @param int $idwarehouse Id warehouse to use for stock change.
* @return int <0 if KO, >0 if OK
*/
function set_draft($user, $idwarehouse=-1)
{
global $conf,$langs;
$error=0;
if ($this->statut == self::STATUS_DRAFT)
{
dol_syslog(get_class($this)."::set_draft already draft status", LOG_WARNING);
return 0;
}
$this->db->begin();
$sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn";
$sql.= " SET fk_statut = 0";
$sql.= " WHERE rowid = ".$this->id;
dol_syslog(get_class($this)."::set_draft", LOG_DEBUG);
$result=$this->db->query($sql);
if ($result)
{
// Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente
if ($result >= 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL))
{
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
$langs->load("agenda");
$cpt=count($this->lines);
for ($i = 0; $i < $cpt; $i++)
{
if ($this->lines[$i]->fk_product > 0)
{
$mouvP = new MouvementStock($this->db);
// We increase stock for product
$result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr",$this->ref));
}
}
}
// Triggers call
if (! $error && empty($notrigger))
{
// Call trigger
$result=$this->call_trigger('BILL_SUPPLIER_VALIDATE',$user);
if ($result < 0) $error++;
// End call triggers
}
if ($error == 0)
{
$this->db->commit();
return 1;
}
else
{
$this->db->rollback();
return -1;
}
}
else
{
$this->error=$this->db->error();
$this->db->rollback();
return -1;
}
}
/**
* Ajoute une ligne de facture (associe a aucun produit/service predefini)
* Les parametres sont deja cense etre juste et avec valeurs finales a l'appel
* de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini
* par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,idprod)
* et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue).
*
* @param string $desc Description de la ligne
* @param double $pu Prix unitaire (HT ou TTC selon price_base_type, > 0 even for credit note)
* @param double $txtva Taux de tva force, sinon -1
* @param double $txlocaltax1 LocalTax1 Rate
* @param double $txlocaltax2 LocalTax2 Rate
* @param double $qty Quantite
* @param int $fk_product Id du produit/service predefini
* @param double $remise_percent Pourcentage de remise de la ligne
* @param date $date_start Date de debut de validite du service
* @param date $date_end Date de fin de validite du service
* @param string $ventil Code de ventilation comptable
* @param int $info_bits Bits de type de lines
* @param string $price_base_type HT ou TTC
* @param int $type Type of line (0=product, 1=service)
* @param int $rang Position of line
* @param int $notrigger Disable triggers
* @param array $array_options extrafields array
* @param string $fk_unit Code of the unit to use. Null to use the default one
* @return int >0 if OK, <0 if KO
*
* FIXME Add field ref (that should be named ref_supplier) and label into update. For example can be filled when product line created from order.
*/
function addline($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits='', $price_base_type='HT', $type=0, $rang=-1, $notrigger=false, $array_options=0, $fk_unit=null)
{
dol_syslog(get_class($this)."::addline $desc,$pu,$qty,$txtva,$fk_product,$remise_percent,$date_start,$date_end,$ventil,$info_bits,$price_base_type,$type,$fk_unit", LOG_DEBUG);
include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
// Clean parameters
if (empty($remise_percent)) $remise_percent=0;
if (empty($qty)) $qty=0;
if (empty($info_bits)) $info_bits=0;
if (empty($rang)) $rang=0;
if (empty($ventil)) $ventil=0;
if (empty($txtva)) $txtva=0;
if (empty($txlocaltax1)) $txlocaltax1=0;
if (empty($txlocaltax2)) $txlocaltax2=0;
$remise_percent=price2num($remise_percent);
$qty=price2num($qty);
$pu=price2num($pu);
$txtva=price2num($txtva);
$txlocaltax1=price2num($txlocaltax1);
$txlocaltax2=price2num($txlocaltax2);
// Check parameters
if ($type < 0) return -1;
$this->db->begin();
$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn)';
$sql.= ' VALUES ('.$this->id.')';
dol_syslog(get_class($this)."::addline", LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
$idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det');
$result=$this->updateline($idligne, $desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product, $price_base_type, $info_bits, $type, $remise_percent, true, '', '', $array_options, $fk_unit);
if ($result > 0)
{
$this->rowid = $idligne;
if (! $notrigger)
{
global $conf, $langs, $user;
// Call trigger
$result=$this->call_trigger('LINEBILL_SUPPLIER_CREATE',$user);
if ($result < 0)
{
$this->db->rollback();
return -1;
}
// End call triggers
}
$this->db->commit();
return 1;
}
else
{
dol_syslog("Error after updateline error=".$this->error, LOG_ERR);
$this->db->rollback();
return -1;
}
}
else
{
$this->error=$this->db->lasterror();
$this->db->rollback();
return -2;
}
}
/**
* Update a line detail into database
*
* @param int $id Id of line invoice
* @param string $desc Description of line
* @param double $pu Prix unitaire (HT ou TTC selon price_base_type)
* @param double $vatrate VAT Rate
* @param double $txlocaltax1 LocalTax1 Rate
* @param double $txlocaltax2 LocalTax2 Rate
* @param double $qty Quantity
* @param int $idproduct Id produit
* @param double $price_base_type HT or TTC
* @param int $info_bits Miscellaneous informations of line
* @param int $type Type of line (0=product, 1=service)
* @param double $remise_percent Pourcentage de remise de la ligne
* @param int $notrigger Disable triggers
* @param timestamp $date_start Date start of service
* @param timestamp $date_end Date end of service
* @param array $array_options extrafields array
* @param string $fk_unit Code of the unit to use. Null to use the default one
* @return int <0 if KO, >0 if OK
*/
function updateline($id, $desc, $pu, $vatrate, $txlocaltax1=0, $txlocaltax2=0, $qty=1, $idproduct=0, $price_base_type='HT', $info_bits=0, $type=0, $remise_percent=0, $notrigger=false, $date_start='', $date_end='', $array_options=0, $fk_unit = null)
{
global $mysoc;
dol_syslog(get_class($this)."::updateline $id,$desc,$pu,$vatrate,$qty,$idproduct,$price_base_type,$info_bits,$type,$remise_percent,$fk_unit", LOG_DEBUG);
include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
$pu = price2num($pu);
$qty = price2num($qty);
$remise_percent=price2num($remise_percent);
// Check parameters
if (! is_numeric($pu) || ! is_numeric($qty)) return -1;
if ($type < 0) return -1;
// Clean parameters
if (empty($vatrate)) $vatrate=0;
if (empty($txlocaltax1)) $txlocaltax1=0;
if (empty($txlocaltax2)) $txlocaltax2=0;
$txlocaltax1=price2num($txlocaltax1);
$txlocaltax2=price2num($txlocaltax2);
// Calcul du total TTC et de la TVA pour la ligne a partir de
// qty, pu, remise_percent et txtva
// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
$localtaxes_type=getLocalTaxesFromRate($vatrate,0,$mysoc, $this->thirdparty);
$tabprice = calcul_price_total($qty, $pu, $remise_percent, $vatrate, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type);
$total_ht = $tabprice[0];
$total_tva = $tabprice[1];
$total_ttc = $tabprice[2];
$pu_ht = $tabprice[3];
$pu_tva = $tabprice[4];
$pu_ttc = $tabprice[5];
$total_localtax1 = $tabprice[9];
$total_localtax2 = $tabprice[10];
if (empty($info_bits)) $info_bits=0;
if ($idproduct)
{
$product=new Product($this->db);
$result=$product->fetch($idproduct);
$product_type = $product->type;
}
else
{
$product_type = $type;
}
$line = new SupplierInvoiceLine($this->db);
if ($line->fetch($id) < 1) {
return -1;
}
$line->description = $desc;
$line->subprice = $pu_ht;
$line->pu_ht = $pu_ht;
$line->pu_ttc = $pu_ttc;
$line->qty = $qty;
$line->remise_percent = $remise_percent;
$line->tva_tx = $vatrate;
$line->localtax1_tx = $txlocaltax1;
$line->localtax2_tx = $txlocaltax2;
$line->localtax1_type = $localtaxes_type[0];
$line->localtax2_type = $localtaxes_type[2];
$line->total_ht = $total_ht;
$line->total_tva = $total_tva;
$line->total_localtax1 = $total_localtax1;
$line->total_localtax2 = $total_localtax2;
$line->total_ttc = $total_ttc;
$line->fk_product = $idproduct;
$line->product_type = $product_type;
$line->info_bits = $info_bits;
$line->fk_unit = $fk_unit;
$line->array_options = $array_options;
$res = $line->update($notrigger);
if ($res < 1) {
$this->errors[] = $line->error;
} else {
// Update total price into invoice record
$res = $this->update_price('','auto');
}
return $res;
}
/**
* Delete a detail line from database
*
* @param int $rowid Id of line to delete
* @param int $notrigger 1=Does not execute triggers, 0= execute triggers
* @return int <0 if KO, >0 if OK
*/
function deleteline($rowid, $notrigger=0)
{
if (!$rowid) {
$rowid = $this->id;
}
$line = new SupplierInvoiceLine($this->db);
if ($line->fetch($rowid) < 1) {
return -1;
}
$res = $line->delete($notrigger);
if ($res < 1) {
$this->errors[] = $line->error;
} else {
$res = $this->update_price();
}
return $res;
}
/**
* Charge les informations d'ordre info dans l'objet facture
*
* @param int $id Id de la facture a charger
* @return void
*/
function info($id)
{
$sql = 'SELECT c.rowid, datec, tms as datem, ';
$sql.= ' fk_user_author, fk_user_valid';
$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c';
$sql.= ' WHERE c.rowid = '.$id;
$result=$this->db->query($sql);
if ($result)
{
if ($this->db->num_rows($result))
{
$obj = $this->db->fetch_object($result);
$this->id = $obj->rowid;
if ($obj->fk_user_author)
{
$cuser = new User($this->db);
$cuser->fetch($obj->fk_user_author);
$this->user_creation = $cuser;
}
if ($obj->fk_user_valid)
{
$vuser = new User($this->db);
$vuser->fetch($obj->fk_user_valid);
$this->user_validation = $vuser;
}
$this->date_creation = $obj->datec;
$this->date_modification = $obj->datem;
//$this->date_validation = $obj->datev; // This field is not available. Should be store into log table and using this function should be replaced with showing content of log (like for supplier orders)
}
$this->db->free($result);
}
else
{
dol_print_error($this->db);
}
}
/**
* Load indicators for dashboard (this->nbtodo and this->nbtodolate)
*
* @param User $user Object user
* @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK
*/
function load_board($user)
{
global $conf, $user, $langs;
$sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin';
$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as ff';
if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
$sql.= ' WHERE ff.paye=0';
$sql.= ' AND ff.fk_statut > 0';
$sql.= " AND ff.entity = ".$conf->entity;
if ($user->societe_id) $sql.=' AND ff.fk_soc = '.$user->societe_id;
if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND ff.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id;
$resql=$this->db->query($sql);
if ($resql)
{
$langs->load("bills");
$now=dol_now();
$response = new WorkboardResponse();
$response->warning_delay=$conf->facture->fournisseur->warning_delay/60/60/24;
$response->label=$langs->trans("SupplierBillsToPay");
$response->url=DOL_URL_ROOT.'/fourn/facture/list.php?filtre=fac.fk_statut:1,paye:0';
$response->img=img_object($langs->trans("Bills"),"bill");
while ($obj=$this->db->fetch_object($resql))
{
$response->nbtodo++;
if (! empty($obj->datefin) && $this->db->jdate($obj->datefin) < ($now - $conf->facture->fournisseur->warning_delay)) {
$response->nbtodolate++;
}
}
$this->db->free($resql);
return $response;
}
else
{
dol_print_error($this->db);
$this->error=$this->db->error();
return -1;
}
}
/**
* Return clicable name (with picto eventually)
*
* @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
* @param string $option Sur quoi pointe le lien
* @param int $max Max length of shown ref
* @return string Chaine avec URL
*/
function getNomUrl($withpicto=0,$option='',$max=0)
{
global $langs;
$result='';
$label = '<u>' . $langs->trans("ShowSupplierInvoice") . '</u>';
if (! empty($this->ref))
$label .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
if (! empty($this->ref_supplier))
$label.= '<br><b>' . $langs->trans('RefSupplier') . ':</b> ' . $this->ref_supplier;
if (! empty($this->total_ht))
$label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
if (! empty($this->total_tva))
$label.= '<br><b>' . $langs->trans('TVA') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
if (! empty($this->total_ttc))
$label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
if ($option == 'document')
{
$link = '<a href="'.DOL_URL_ROOT.'/fourn/facture/document.php?facid='.$this->id.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
$linkend='</a>';
}
else
{
$link = '<a href="'.DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$this->id.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
$linkend='</a>';
}
$ref=$this->ref;
if (empty($ref)) $ref=$this->id;
if ($withpicto) $result.=($link.img_object($label, 'bill', 'class="classfortooltip"').$linkend.' ');
$result.=$link.($max?dol_trunc($ref,$max):$ref).$linkend;
return $result;
}
/**
* Return next reference of supplier invoice not already used (or last reference)
* according to numbering module defined into constant INVOICE_SUPPLIER_ADDON_NUMBER
*
* @param Societe $soc Thirdparty object
* @param string $mode 'next' for next value or 'last' for last value
* @return string free ref or last ref
*/
function getNextNumRef($soc,$mode='next')
{
global $db, $langs, $conf;
$langs->load("orders");
// Clean parameters (if not defined or using deprecated value)
if (empty($conf->global->INVOICE_SUPPLIER_ADDON_NUMBER)) $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER='mod_facture_fournisseur_cactus';
$mybool=false;
$file = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER.".php";
$classname = $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER;
// Include file with class
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
foreach ($dirmodels as $reldir) {
$dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
// Load file with numbering class (if found)
$mybool|=@include_once $dir.$file;
}
if (! $mybool)
{
dol_print_error('',"Failed to include file ".$file);
return '';
}
$obj = new $classname();
$numref = "";
$numref = $obj->getNumRef($soc,$this,$mode);
if ($numref != "")
{
return $numref;
}
else
{
//dol_print_error($db,get_class($this)."::getNextNumRef ".$obj->error);
return false;
}
}
/**
* Initialise an instance with random values.
* Used to build previews or test instances.
* id must be 0 if object instance is a specimen.
*
* @return void
*/
function initAsSpecimen()
{
global $langs,$conf;
include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
$now = dol_now();
// Charge tableau des produits prodids
$prodids = array();
$sql = "SELECT rowid";
$sql.= " FROM ".MAIN_DB_PREFIX."product";
$sql.= " WHERE entity IN (".getEntity('product', 1).")";
$resql = $this->db->query($sql);
if ($resql)
{
$num_prods = $this->db->num_rows($resql);
$i = 0;
while ($i < $num_prods)
{
$i++;
$row = $this->db->fetch_row($resql);
$prodids[$i] = $row[0];
}
}
// Initialise parametres
$this->id=0;
$this->ref = 'SPECIMEN';
$this->ref_supplier = 'SUPPLIER_REF_SPECIMEN';
$this->specimen=1;
$this->socid = 1;
$this->date = $now;
$this->date_lim_reglement=$this->date+3600*24*30;
$this->cond_reglement_code = 'RECEP';
$this->mode_reglement_code = 'CHQ';
$this->note_public='This is a comment (public)';
$this->note_private='This is a comment (private)';
// Lines
$nbp = 5;
$xnbp = 0;
while ($xnbp < $nbp)
{
$line=new FactureLigne($this->db);
$line->desc=$langs->trans("Description")." ".$xnbp;
$line->qty=1;
$line->subprice=100;
$line->pu_ht=100; // the canelle template use pu_ht and not subprice
$line->price=100;
$line->tva_tx=19.6;
$line->localtax1_tx=0;
$line->localtax2_tx=0;
if ($xnbp == 2)
{
$line->total_ht=50;
$line->total_ttc=59.8;
$line->total_tva=9.8;
$line->remise_percent=50;
}
else
{
$line->total_ht=100;
$line->total_ttc=119.6;
$line->total_tva=19.6;
$line->remise_percent=0;
}
$prodid = rand(1, $num_prods);
$line->fk_product=$prodids[$prodid];
$line->product_type=0;
$this->lines[$xnbp]=$line;
$this->total_ht += $line->total_ht;
$this->total_tva += $line->total_tva;
$this->total_ttc += $line->total_ttc;
$xnbp++;
}
$this->amount_ht = $xnbp*100;
$this->total_ht = $xnbp*100;
$this->total_tva = $xnbp*19.6;
$this->total_ttc = $xnbp*119.6;
}
/**
* Load indicators for dashboard (this->nbtodo and this->nbtodolate)
*
* @return int <0 if KO, >0 if OK
*/
function load_state_board()
{
global $conf, $user;
$this->nb=array();
$clause = "WHERE";
$sql = "SELECT count(f.rowid) as nb";
$sql.= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
if (!$user->rights->societe->client->voir && !$user->societe_id)
{
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
$sql.= " WHERE sc.fk_user = " .$user->id;
$clause = "AND";
}
$sql.= " ".$clause." f.entity = ".$conf->entity;
$resql=$this->db->query($sql);
if ($resql)
{
while ($obj=$this->db->fetch_object($resql))
{
$this->nb["supplier_invoices"]=$obj->nb;
}
$this->db->free($resql);
return 1;
}
else
{
dol_print_error($this->db);
$this->error=$this->db->error();
return -1;
}
}
/**
* Load an object from its id and create a new one in database
*
* @param int $fromid Id of object to clone
* @param int $invertdetail Reverse sign of amounts for lines
* @return int New id of clone
*/
function createFromClone($fromid,$invertdetail=0)
{
global $user,$langs;
$error=0;
$object=new FactureFournisseur($this->db);
$object->context['createfromclone'] = 'createfromclone';
$this->db->begin();
// Load source object
$object->fetch($fromid);
$object->id=0;
$object->statut=self::STATUS_DRAFT;
// Clear fields
$object->ref_supplier=$langs->trans("CopyOf").' '.$object->ref_supplier;
$object->author = $user->id;
$object->user_valid = '';
$object->fk_facture_source = 0;
$object->date_creation = '';
$object->date_validation = '';
$object->date = '';
$object->date_echeance = '';
$object->ref_client = '';
$object->close_code = '';
$object->close_note = '';
// Loop on each line of new invoice
foreach($object->lines as $i => $line)
{
if (isset($object->lines[$i]->info_bits) && ($object->lines[$i]->info_bits & 0x02) == 0x02) // We do not clone line of discounts
{
unset($object->lines[$i]);
}
}
// Create clone
$result=$object->create($user);
// Other options
if ($result < 0)
{
$this->error=$object->error;
$error++;
}
if (! $error)
{
}
unset($object->context['createfromclone']);
// End
if (! $error)
{
$this->db->commit();
return $object->id;
}
else
{
$this->db->rollback();
return -1;
}
}
/**
* Create a document onto disk according to template model.
*
* @param string $modele Force template to use ('' to not force)
* @param Translate $outputlangs Object lang a utiliser pour traduction
* @param int $hidedetails Hide details of lines
* @param int $hidedesc Hide description
* @param int $hideref Hide ref
* @return int 0 if KO, 1 if OK
*/
public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
{
global $conf, $user, $langs;
$langs->load("suppliers");
// Set the model on the model name to use
if (! dol_strlen($modele))
{
if (! empty($conf->global->INVOICE_SUPPLIER_ADDON_PDF))
{
$modele = $conf->global->INVOICE_SUPPLIER_ADDON_PDF;
}
else
{
$modele = 'canelle';
}
}
$modelpath = "core/modules/supplier_invoice/pdf/";
return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
/**
* Returns the rights used for this class
* @return stdClass
*/
public function getRights()
{
global $user;
return $user->rights->fournisseur->facture;
}
/**
* Function used to replace a thirdparty id with another one.
*
* @param DoliDB $db Database handler
* @param int $origin_id Old thirdparty id
* @param int $dest_id New thirdparty id
* @return bool
*/
public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
{
$tables = array(
'facture_fourn'
);
return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
}
}
/**
* Class to manage line invoices
*/
class SupplierInvoiceLine extends CommonObjectLine
{
public $element='facture_fourn_det';
public $table_element='facture_fourn_det';
var $oldline;
/**
* @deprecated
* @see product_ref
*/
public $ref;
/**
* Internal ref
* @var string
*/
public $product_ref;
/**
* Reference product supplier
* TODO Rename field ref to ref_supplier into table llx_facture_fourn_det and llx_commande_fournisseurdet and update fields it into updateline
* @var string
*/
public $ref_supplier;
/**
* @deprecated
* @see label
*/
public $libelle;
/**
* Product description
* @var string
*/
public $product_desc;
/**
* Unit price before taxes
* @var float
* @deprecated Use $subprice
* @see subprice
*/
public $pu_ht;
public $subprice;
/**
* Unit price included taxes
* @var float
*/
public $pu_ttc;
/**
* Total VAT amount
* @var float
* @deprecated Use $total_tva instead
* @see total_tva
*/
public $tva;
public $total_tva;
/**
* Id of the corresponding supplier invoice
* @var int
*/
var $fk_facture_fourn;
/**
* Product label
* This field may contains label of product (when invoice create from order)
* @var string
*/
var $label;
/**
* Description of the line
* @var string
*/
var $description;
var $skip_update_total; // Skip update price total for special lines
/**
* @var int Situation advance percentage
*/
public $situation_percent;
/**
* @var int Previous situation line id reference
*/
public $fk_prev_id;
public $tva_tx;
public $localtax1_tx;
public $localtax2_tx;
public $qty;
public $remise_percent;
public $total_ht;
public $total_ttc;
public $total_localtax1;
public $total_localtax2;
public $fk_product;
public $product_type;
public $product_label;
public $info_bits;
public $fk_parent_line;
public $special_code;
public $rang;
public $localtax1_type;
public $localtax2_type;
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
function __construct($db)
{
$this->db= $db;
}
/**
* Retrieves a supplier invoice line
*
* @param int $rowid Line id
* @return int <0 KO; 0 NOT FOUND; 1 OK
*/
public function fetch($rowid)
{
$sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.tva_tx';
$sql.= ', f.localtax1_type, f.localtax2_type, f.localtax1_tx, f.localtax2_tx, f.total_localtax1, f.total_localtax2 ';
$sql.= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit';
$sql.= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.description as product_desc';
$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det as f';
$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON f.fk_product = p.rowid';
$sql.= ' WHERE f.rowid = '.$rowid;
$sql.= ' ORDER BY f.rang, f.rowid';
$query = $this->db->query($sql);
if (!$query) {
$this->errors[] = $this->db->error();
return -1;
}
if (!$this->db->num_rows($query)) {
return 0;
}
$obj = $this->db->fetch_object($query);
$this->id = $obj->rowid;
$this->rowid = $obj->rowid;
$this->description = $obj->description;
$this->product_ref = $obj->product_ref;
$this->ref = $obj->product_ref;
$this->ref_supplier = $obj->ref_supplier;
$this->libelle = $obj->label;
$this->label = $obj->label;
$this->product_desc = $obj->product_desc;
$this->subprice = $obj->pu_ht;
$this->pu_ht = $obj->pu_ht;
$this->pu_ttc = $obj->pu_ttc;
$this->tva_tx = $obj->tva_tx;
$this->localtax1_tx = $obj->localtax1_tx;
$this->localtax2_tx = $obj->localtax2_tx;
$this->localtax1_type = $obj->localtax1_type;
$this->localtax2_type = $obj->localtax2_type;
$this->qty = $obj->qty;
$this->remise_percent = $obj->remise_percent;
$this->tva = $obj->total_tva;
$this->total_ht = $obj->total_ht;
$this->total_tva = $obj->total_tva;
$this->total_localtax1 = $obj->total_localtax1;
$this->total_localtax2 = $obj->total_localtax2;
$this->total_ttc = $obj->total_ttc;
$this->fk_product = $obj->fk_product;
$this->product_type = $obj->product_type;
$this->product_label = $obj->label;
$this->info_bits = $obj->info_bits;
$this->fk_parent_line = $obj->fk_parent_line;
$this->special_code = $obj->special_code;
$this->rang = $obj->rang;
$this->fk_unit = $obj->fk_unit;
return 1;
}
/**
* Deletes a line
*
* @param bool|int $notrigger 1=Does not execute triggers, 0= execute triggers
* @return int 0 if KO, 1 if OK
*/
public function delete($notrigger = 0)
{
global $user;
dol_syslog(get_class($this)."::deleteline rowid=".$this->id, LOG_DEBUG);
$error = 0;
$this->db->begin();
if (!$notrigger) {
if ($this->call_trigger('LINEBILL_SUPPLIER_DELETE',$user) < 0) {
$error++;
}
}
if (!$error) {
// Supprime ligne
$sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det ';
$sql .= ' WHERE rowid = '.$this->id;
dol_syslog(get_class($this)."::delete", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->error = $this->db->lasterror();
}
}
if (! $error)
{
$this->db->commit();
return 1;
}
else
{
$this->db->rollback();
return -1;
}
}
/**
* Update a supplier invoice line
*
* @param int $notrigger Disable triggers
* @return int <0 if KO, >0 if OK
*/
public function update($notrigger = 0)
{
global $conf;
$pu = price2num($this->pu_ht);
$qty = price2num($this->qty);
// Check parameters
if (! is_numeric($pu) || ! is_numeric($qty)) {
return -1;
}
if ($this->product_type < 0) {
return -1;
}
// Clean parameters
if (empty($this->tva_tx)) {
$this->tva_tx = 0;
}
if (empty($this->localtax1_tx)) {
$this->localtax1_tx = 0;
}
if (empty($this->localtax2_tx)) {
$this->localtax2_tx = 0;
}
$this->db->begin();
if (empty($this->fk_product))
{
$fk_product = "null";
} else {
$fk_product = $this->fk_product;
}
if (empty($this->fk_unit)) {
$fk_unit = "null";
} else {
$fk_unit = "'".$this->db->escape($this->fk_unit)."'";
}
$sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET";
$sql.= " description ='".$this->db->escape($this->description)."'";
$sql.= ", pu_ht = ".price2num($this->pu_ht);
$sql.= ", pu_ttc = ".price2num($this->pu_ttc);
$sql.= ", qty = ".price2num($this->qty);
$sql.= ", remise_percent = ".price2num($this->remise_percent);
$sql.= ", tva_tx = ".price2num($this->tva_tx);
$sql.= ", localtax1_tx = ".price2num($this->localtax1_tx);
$sql.= ", localtax2_tx = ".price2num($this->localtax2_tx);
$sql.= ", localtax1_type = '".$this->localtax1_type."'";
$sql.= ", localtax2_type = '".$this->localtax2_type."'";
$sql.= ", total_ht = ".price2num($this->total_ht);
$sql.= ", tva= ".price2num($this->total_tva);
$sql.= ", total_localtax1= ".price2num($this->total_localtax1);
$sql.= ", total_localtax2= ".price2num($this->total_localtax2);
$sql.= ", total_ttc = ".price2num($this->total_ttc);
$sql.= ", fk_product = ".$fk_product;
$sql.= ", product_type = ".$this->product_type;
$sql.= ", info_bits = ".$this->info_bits;
$sql.= ", fk_unit = ".$fk_unit;
$sql.= " WHERE rowid = ".$this->id;
dol_syslog(get_class($this)."::update", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$this->db->rollback();
$this->error = $this->db->lasterror();
return -1;
}
$this->rowid = $this->id;
$error = 0;
if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
{
if ($this->insertExtraFields() < 0) {
$error++;
}
}
if (! $error && ! $notrigger)
{
global $langs, $user;
// Call trigger
if ($this->call_trigger('LINEBILL_SUPPLIER_UPDATE',$user) < 0) {
$this->db->rollback();
return -1;
}
// End call triggers
}
if ($error) {
$this->db->rollback();
return -1;
}
$this->db->commit();
return 1;
}
}