diff --git a/htdocs/comm/askpricesupplier/apercu.php b/htdocs/comm/askpricesupplier/apercu.php new file mode 100644 index 00000000000..87281e7ea63 --- /dev/null +++ b/htdocs/comm/askpricesupplier/apercu.php @@ -0,0 +1,221 @@ + + * Copyright (C) 2004 Eric Seigne + * Copyright (C) 2004-2007 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2011 Juanjo Menent + * Copyright (C) 2014 Frederic France + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/apercu.php + * \ingroup propal + * \brief Preview tab of propal + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + +$langs->load('propal'); +$langs->load("bills"); +$langs->load('compta'); + +// Security check +$socid=0; +$id = GETPOST('id','int'); +$ref = GETPOST("ref"); +if ($user->societe_id) $socid=$user->societe_id; +$result = restrictedArea($user, 'propal', $id); + + +/* + * View Mode + */ + +llxHeader(); + + +if ($id > 0 || ! empty($ref)) +{ + $object = new Propal($db); + + if ($object->fetch($id,$ref) > 0) + { + $soc = new Societe($db); + $soc->fetch($object->socid); + + $head = propal_prepare_head($object); + dol_fiche_head($head, 'preview', $langs->trans('Proposal'), 0, 'propal'); + + + /* + * Propal + */ + print ''; + + // Ref + print ''; + print ''; + print ''; + + // Ref client + print ''; + print ''; + print ''; + + + // Thirdparty + print ''; + print ''; + print ''; + + // Status + print ''; + print ''; + print ''; + + // Discount + print ''; + print ''; + + // Date + print ''; + print ''; + + // Right part with $rowspan lines + $rowspan=4; + print ''; + print ''; + + // Total HT - left part + print ''; + print ''; + print ''; + + // Total VAT - left part + print ''; + print ''; + print ''; + + // Total TTC - left part + print ''; + print ''; + print ''; + + print '
'.$langs->trans('Ref').''.$object->ref.'
'.$langs->trans('RefCustomer').''.$object->ref_client.'
'.$langs->trans('Company').''.$soc->getNomUrl(1).'
'.$langs->trans("Status").''.$object->getLibStatut(4).'
'.$langs->trans('Discounts').''; + if ($soc->remise_percent) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_percent); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + $absolute_discount=$soc->getAvailableDiscounts(); + print '. '; + if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",$absolute_discount,$langs->trans("Currency".$conf->currency)); + else print $langs->trans("CompanyHasNoAbsoluteDiscount"); + print '.
'.$langs->trans('Date').''.dol_print_date($object->date,'daytext').''; + + /* + * Documents + */ + $objectref = dol_sanitizeFileName($object->ref); + $dir_output = $conf->propal->dir_output . "/"; + $filepath = $dir_output . $objectref . "/"; + $file = $filepath . $objectref . ".pdf"; + $filedetail = $filepath . $objectref . "-detail.pdf"; + $relativepath = $objectref.'/'.$objectref.'.pdf'; + $relativepathdetail = $objectref.'/'.$objectref.'-detail.pdf'; + + // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png") + $fileimage = $file.'_preview.png'; // If PDF has 1 page + $fileimagebis = $file.'_preview-0.pdf.png'; // If PDF has more than one page + $relativepathimage = $relativepath.'_preview.png'; + + $var=true; + + // Si fichier PDF existe + if (file_exists($file)) + { + $encfile = urlencode($file); + print ''; + print ''; + + print ''; + + print ''; + + print ''; + print ''; + print ''; + + print "
'.$langs->trans("Documents").'
'.$langs->trans("Proposal").' PDF'.$object->ref.'.pdf'.dol_print_size(dol_filesize($file)).''.dol_print_date(dol_filemtime($file),'dayhour').'
\n"; + + // Conversion du PDF en image png si fichier png non existant + if (! file_exists($fileimage) && ! file_exists($fileimagebis)) + { + if (class_exists("Imagick")) + { + $ret = dol_convert_file($file,'png',$fileimage); + if ($ret < 0) $error++; + } + else + { + $langs->load("errors"); + print ''.$langs->trans("ErrorNoImagickReadimage").''; + } + } + } + + print '
'.$langs->trans('AmountHT').'' . price($object->total_ht, '', $langs, 0, - 1, - 1, $conf->currency) . '
'.$langs->trans('AmountVAT').'' . price($object->total_tva, '', $langs, 0, - 1, - 1, $conf->currency) . '
'.$langs->trans('AmountTTC').'' . price($object->total_ttc, '', $langs, 0, - 1, - 1, $conf->currency) . '
'; + + dol_fiche_end(); + } + else + { + // Propal non trouvee + print $langs->trans("ErrorPropalNotFound",$_GET["id"]); + } +} + +print ''; +print ''; +print '
'; +print '
'; +// Si fichier png PDF d'1 page trouve +if (file_exists($fileimage)) +{ + print ''; +} +// Si fichier png PDF de plus d'1 page trouve +elseif (file_exists($fileimagebis)) +{ + $multiple = preg_replace('/\.png/','',$relativepath) . "-"; + + for ($i = 0; $i < 20; $i++) + { + $preview = $multiple.$i.'.png'; + + if (file_exists($dir_output.$preview)) + { + print '

'; + } + } +} +print '

'; +print '
'; + + +llxFooter(); + +$db->close(); diff --git a/htdocs/comm/askpricesupplier/class/askpricesupplier.class.php b/htdocs/comm/askpricesupplier/class/askpricesupplier.class.php new file mode 100644 index 00000000000..f68a1f4f708 --- /dev/null +++ b/htdocs/comm/askpricesupplier/class/askpricesupplier.class.php @@ -0,0 +1,3211 @@ + + * Copyright (C) 2004 Eric Seigne + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2005 Marc Barilley + * Copyright (C) 2005-2013 Regis Houssin + * Copyright (C) 2006 Andre Cianfarani + * Copyright (C) 2008 Raphael Bertrand + * Copyright (C) 2010-2014 Juanjo Menent + * Copyright (C) 2010-2011 Philippe Grand + * Copyright (C) 2012-2014 Christophe Battarel + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2014 Marcos García + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/class/propal.class.php + * \brief File of class to manage proposals + */ + +require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT .'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT .'/margin/lib/margins.lib.php'; + +/** + * Class to manage proposals + */ +class Propal extends CommonObject +{ + public $element='propal'; + public $table_element='propal'; + public $table_element_line='propaldet'; + public $fk_element='fk_propal'; + 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 $id; + + var $socid; // Id client + var $client; // Objet societe client (a charger par fetch_client) + + var $contactid; + var $fk_project; + var $author; + var $ref; + var $ref_client; + var $statut; // 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (billed) + var $datec; // Date of creation + var $datev; // Date of validation + var $date; // Date of proposal + var $datep; // Same than date + var $date_livraison; + var $fin_validite; + + var $user_author_id; + var $user_valid_id; + var $user_close_id; + + var $total_ht; // Total net of tax + var $total_tva; // Total VAT + var $total_localtax1; // Total Local Taxes 1 + var $total_localtax2; // Total Local Taxes 2 + var $total_ttc; // Total with tax + var $price; // deprecated (for compatibility) + var $tva; // deprecated (for compatibility) + var $total; // deprecated (for compatibility) + + var $cond_reglement_id; + var $cond_reglement_code; + var $fk_account; // Id of bank account + var $mode_reglement_id; + var $mode_reglement_code; + var $remise; + var $remise_percent; + var $remise_absolue; + var $note; // deprecated (for compatibility) + var $note_private; + var $note_public; + var $fk_delivery_address; // deprecated (for compatibility) + var $fk_address; + var $address_type; + var $address; + var $shipping_method_id; + var $availability_id; + var $availability_code; + var $demand_reason_id; + var $demand_reason_code; + + var $products=array(); + var $extraparams=array(); + + var $lines = array(); + var $line; + + var $origin; + var $origin_id; + + var $labelstatut=array(); + var $labelstatut_short=array(); + + // Pour board + var $nbtodo; + var $nbtodolate; + + var $specimen; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + * @param int $socid Id third party + * @param int $propalid Id proposal + */ + function __construct($db, $socid="", $propalid=0) + { + global $conf,$langs; + + $this->db = $db; + $this->socid = $socid; + $this->id = $propalid; + $this->products = array(); + $this->remise = 0; + $this->remise_percent = 0; + $this->remise_absolue = 0; + + $this->duree_validite=$conf->global->PROPALE_VALIDITY_DURATION; + + $langs->load("propal"); + $this->labelstatut[0]=(! empty($conf->global->PROPAL_STATUS_DRAFT_LABEL) ? $conf->global->PROPAL_STATUS_DRAFT_LABEL : $langs->trans("PropalStatusDraft")); + $this->labelstatut[1]=(! empty($conf->global->PROPAL_STATUS_VALIDATED_LABEL) ? $conf->global->PROPAL_STATUS_VALIDATED_LABEL : $langs->trans("PropalStatusValidated")); + $this->labelstatut[2]=(! empty($conf->global->PROPAL_STATUS_SIGNED_LABEL) ? $conf->global->PROPAL_STATUS_SIGNED_LABEL : $langs->trans("PropalStatusSigned")); + $this->labelstatut[3]=(! empty($conf->global->PROPAL_STATUS_NOTSIGNED_LABEL) ? $conf->global->PROPAL_STATUS_NOTSIGNED_LABEL : $langs->trans("PropalStatusNotSigned")); + $this->labelstatut[4]=(! empty($conf->global->PROPAL_STATUS_BILLED_LABEL) ? $conf->global->PROPAL_STATUS_BILLED_LABEL : $langs->trans("PropalStatusBilled")); + $this->labelstatut_short[0]=(! empty($conf->global->PROPAL_STATUS_DRAFTSHORT_LABEL) ? $conf->global->PROPAL_STATUS_DRAFTSHORT_LABEL : $langs->trans("PropalStatusDraftShort")); + $this->labelstatut_short[1]=(! empty($conf->global->PROPAL_STATUS_VALIDATEDSHORT_LABEL) ? $conf->global->PROPAL_STATUS_VALIDATEDSHORT_LABEL : $langs->trans("Opened")); + $this->labelstatut_short[2]=(! empty($conf->global->PROPAL_STATUS_SIGNEDSHORT_LABEL) ? $conf->global->PROPAL_STATUS_SIGNEDSHORT_LABEL : $langs->trans("PropalStatusSignedShort")); + $this->labelstatut_short[3]=(! empty($conf->global->PROPAL_STATUS_NOTSIGNEDSHORT_LABEL) ? $conf->global->PROPAL_STATUS_NOTSIGNEDSHORT_LABEL : $langs->trans("PropalStatusNotSignedShort")); + $this->labelstatut_short[4]=(! empty($conf->global->PROPAL_STATUS_BILLEDSHORT_LABEL) ? $conf->global->PROPAL_STATUS_BILLEDSHORT_LABEL : $langs->trans("PropalStatusBilledShort")); + } + + + /** + * Add line into array products + * $this->client doit etre charge + * + * @param int $idproduct Product Id to add + * @param int $qty Quantity + * @param int $remise_percent Discount effected on Product + * @return int <0 if KO, >0 if OK + * + * TODO Remplacer les appels a cette fonction par generation objet Ligne + * insere dans tableau $this->products + */ + function add_product($idproduct, $qty, $remise_percent=0) + { + global $conf, $mysoc; + + if (! $qty) $qty = 1; + + dol_syslog(get_class($this)."::add_product $idproduct, $qty, $remise_percent"); + if ($idproduct > 0) + { + $prod=new Product($this->db); + $prod->fetch($idproduct); + + $productdesc = $prod->description; + + $tva_tx = get_default_tva($mysoc,$this->client,$prod->id); + // local taxes + $localtax1_tx = get_default_localtax($mysoc,$this->client,1,$prod->tva_tx); + $localtax2_tx = get_default_localtax($mysoc,$this->client,2,$prod->tva_tx); + + // multiprix + if($conf->global->PRODUIT_MULTIPRICES && $this->client->price_level) + { + $price = $prod->multiprices[$this->client->price_level]; + } + else + { + $price = $prod->price; + } + + $line = new PropaleLigne($this->db); + + $line->fk_product=$idproduct; + $line->desc=$productdesc; + $line->qty=$qty; + $line->subprice=$price; + $line->remise_percent=$remise_percent; + $line->tva_tx=$tva_tx; + + $this->lines[]=$line; + } + } + + /** + * Adding line of fixed discount in the proposal in DB + * + * @param int $idremise Id of fixed discount + * @return int >0 if OK, <0 if KO + */ + function insert_discount($idremise) + { + global $langs; + + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; + + $this->db->begin(); + + $remise=new DiscountAbsolute($this->db); + $result=$remise->fetch($idremise); + + if ($result > 0) + { + if ($remise->fk_facture) // Protection against multiple submission + { + $this->error=$langs->trans("ErrorDiscountAlreadyUsed"); + $this->db->rollback(); + return -5; + } + + $propalligne=new PropaleLigne($this->db); + $propalligne->fk_propal=$this->id; + $propalligne->fk_remise_except=$remise->id; + $propalligne->desc=$remise->description; // Description ligne + $propalligne->tva_tx=$remise->tva_tx; + $propalligne->subprice=-$remise->amount_ht; + $propalligne->fk_product=0; // Id produit predefini + $propalligne->qty=1; + $propalligne->remise=0; + $propalligne->remise_percent=0; + $propalligne->rang=-1; + $propalligne->info_bits=2; + + // TODO deprecated + $propalligne->price=-$remise->amount_ht; + + $propalligne->total_ht = -$remise->amount_ht; + $propalligne->total_tva = -$remise->amount_tva; + $propalligne->total_ttc = -$remise->amount_ttc; + + $result=$propalligne->insert(); + if ($result > 0) + { + $result=$this->update_price(1); + if ($result > 0) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$propalligne->error; + $this->db->rollback(); + return -2; + } + } + else + { + $this->db->rollback(); + return -2; + } + } + + /** + * Add a proposal line into database (linked to product/service or not) + * 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,'',produit) + * 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_ht Prix unitaire + * @param double $qty Quantite + * @param double $txtva Taux de tva + * @param double $txlocaltax1 Local tax 1 rate + * @param double $txlocaltax2 Local tax 2 rate + * @param int $fk_product Id du produit/service predefini + * @param double $remise_percent Pourcentage de remise de la ligne + * @param string $price_base_type HT or TTC + * @param double $pu_ttc Prix unitaire TTC + * @param int $info_bits Bits de type de lignes + * @param int $type Type of line (product, service) + * @param int $rang Position of line + * @param int $special_code Special code (also used by externals modules!) + * @param int $fk_parent_line Id of parent line + * @param int $fk_fournprice Id supplier price + * @param int $pa_ht Buying price without tax + * @param string $label ??? + * @param int $date_start Start date of the line + * @param int $date_end End date of the line + * @param array $array_option extrafields array + * @return int >0 if OK, <0 if KO + * + * @see add_product + */ + function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $pu_ttc=0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$date_start='', $date_end='',$array_option=0) + { + global $mysoc; + + dol_syslog(get_class($this)."::addline propalid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type"); + 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($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; + + $remise_percent=price2num($remise_percent); + $qty=price2num($qty); + $pu_ht=price2num($pu_ht); + $pu_ttc=price2num($pu_ttc); + $txtva=price2num($txtva); + $txlocaltax1=price2num($txlocaltax1); + $txlocaltax2=price2num($txlocaltax2); + $pa_ht=price2num($pa_ht); + if ($price_base_type=='HT') + { + $pu=$pu_ht; + } + else + { + $pu=$pu_ttc; + } + + // Check parameters + if ($type < 0) return -1; + + if ($this->statut == 0) + { + $this->db->begin(); + + // 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($txtva,0,$this->thirdparty,$mysoc); + + $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, '', $localtaxes_type); + $total_ht = $tabprice[0]; + $total_tva = $tabprice[1]; + $total_ttc = $tabprice[2]; + $total_localtax1 = $tabprice[9]; + $total_localtax2 = $tabprice[10]; + + // Rang to use + $rangtouse = $rang; + if ($rangtouse == -1) + { + $rangmax = $this->line_max($fk_parent_line); + $rangtouse = $rangmax + 1; + } + + // TODO A virer + // Anciens indicateurs: $price, $remise (a ne plus utiliser) + $price = $pu; + $remise = 0; + if ($remise_percent > 0) + { + $remise = round(($pu * $remise_percent / 100), 2); + $price = $pu - $remise; + } + + // Insert line + $this->line=new PropaleLigne($this->db); + + $this->line->fk_propal=$this->id; + $this->line->label=$label; + $this->line->desc=$desc; + $this->line->qty=$qty; + $this->line->tva_tx=$txtva; + $this->line->localtax1_tx=$txlocaltax1; + $this->line->localtax2_tx=$txlocaltax2; + $this->line->localtax1_type = $localtaxes_type[0]; + $this->line->localtax2_type = $localtaxes_type[2]; + $this->line->fk_product=$fk_product; + $this->line->remise_percent=$remise_percent; + $this->line->subprice=$pu_ht; + $this->line->rang=$rangtouse; + $this->line->info_bits=$info_bits; + $this->line->total_ht=$total_ht; + $this->line->total_tva=$total_tva; + $this->line->total_localtax1=$total_localtax1; + $this->line->total_localtax2=$total_localtax2; + $this->line->total_ttc=$total_ttc; + $this->line->product_type=$type; + $this->line->special_code=$special_code; + $this->line->fk_parent_line=$fk_parent_line; + + $this->line->date_start=$date_start; + $this->line->date_end=$date_end; + + + // infos marge + if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) { + // by external module, take lowest buying price + include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; + $productFournisseur = new ProductFournisseur($this->db); + $productFournisseur->find_min_price_product_fournisseur($fk_product); + $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id; + } else { + $this->line->fk_fournprice = $fk_fournprice; + } + $this->line->pa_ht = $pa_ht; + + // Mise en option de la ligne + if (empty($qty) && empty($special_code)) $this->line->special_code=3; + + // TODO deprecated + $this->line->price=$price; + $this->line->remise=$remise; + + if (is_array($array_option) && count($array_option)>0) { + $this->line->array_options=$array_option; + } + + $result=$this->line->insert(); + if ($result > 0) + { + // Reorder if child line + if (! empty($fk_parent_line)) $this->line_order(true,'DESC'); + + // Mise a jour informations denormalisees au niveau de la propale meme + $result=$this->update_price(1,'auto'); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + if ($result > 0) + { + $this->db->commit(); + return $this->line->rowid; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->line->error; + $this->db->rollback(); + return -2; + } + } + } + + + /** + * Update a proposal line + * + * @param int $rowid Id de la ligne + * @param double $pu Prix unitaire (HT ou TTC selon price_base_type) + * @param double $qty Quantity + * @param double $remise_percent Remise effectuee sur le produit + * @param double $txtva Taux de TVA + * @param double $txlocaltax1 Local tax 1 rate + * @param double $txlocaltax2 Local tax 2 rate + * @param string $desc Description + * @param double $price_base_type HT ou TTC + * @param int $info_bits Miscellaneous informations + * @param int $special_code Special code (also used by externals modules!) + * @param int $fk_parent_line Id of parent line (0 in most cases, used by modules adding sublevels into lines). + * @param int $skip_update_total Keep fields total_xxx to 0 (used for special lines by some modules) + * @param int $fk_fournprice Id of origin supplier price + * @param int $pa_ht Price (without tax) of product when it was bought + * @param string $label ??? + * @param int $type 0/1=Product/service + * @param int $date_start Start date of the line + * @param int $date_end End date of the line + * @param array $array_option extrafields array + * @return int 0 if OK, <0 if KO + */ + function updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $desc='', $price_base_type='HT', $info_bits=0, $special_code=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=0, $pa_ht=0, $label='', $type=0, $date_start='', $date_end='', $array_option=0) + { + global $conf,$user,$langs, $mysoc; + + dol_syslog(get_class($this)."::updateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits"); + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + // Clean parameters + $remise_percent=price2num($remise_percent); + $qty=price2num($qty); + $pu = price2num($pu); + $txtva = price2num($txtva); + $txlocaltax1=price2num($txlocaltax1); + $txlocaltax2=price2num($txlocaltax2); + $pa_ht=price2num($pa_ht); + if (empty($qty) && empty($special_code)) $special_code=3; // Set option tag + if (! empty($qty) && $special_code == 3) $special_code=0; // Remove option tag + + if ($this->statut == 0) + { + $this->db->begin(); + + // 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($txtva,0,$this->thirdparty,$mysoc); + + $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type,'', $localtaxes_type); + $total_ht = $tabprice[0]; + $total_tva = $tabprice[1]; + $total_ttc = $tabprice[2]; + $total_localtax1 = $tabprice[9]; + $total_localtax2 = $tabprice[10]; + + // Anciens indicateurs: $price, $remise (a ne plus utiliser) + $price = $pu; + if ($remise_percent > 0) + { + $remise = round(($pu * $remise_percent / 100), 2); + $price = $pu - $remise; + } + + // Update line + $this->line=new PropaleLigne($this->db); + + // Stock previous line records + $staticline=new PropaleLigne($this->db); + $staticline->fetch($rowid); + $this->line->oldline = $staticline; + + // Reorder if fk_parent_line change + if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line) + { + $rangmax = $this->line_max($fk_parent_line); + $this->line->rang = $rangmax + 1; + } + + $this->line->rowid = $rowid; + $this->line->label = $label; + $this->line->desc = $desc; + $this->line->qty = $qty; + $this->line->product_type = $type; + $this->line->tva_tx = $txtva; + $this->line->localtax1_tx = $txlocaltax1; + $this->line->localtax2_tx = $txlocaltax2; + $this->line->localtax1_type = $localtaxes_type[0]; + $this->line->localtax2_type = $localtaxes_type[2]; + $this->line->remise_percent = $remise_percent; + $this->line->subprice = $pu; + $this->line->info_bits = $info_bits; + $this->line->total_ht = $total_ht; + $this->line->total_tva = $total_tva; + $this->line->total_localtax1 = $total_localtax1; + $this->line->total_localtax2 = $total_localtax2; + $this->line->total_ttc = $total_ttc; + $this->line->special_code = $special_code; + $this->line->fk_parent_line = $fk_parent_line; + $this->line->skip_update_total = $skip_update_total; + + // infos marge + if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) { + // by external module, take lowest buying price + include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; + $productFournisseur = new ProductFournisseur($this->db); + $productFournisseur->find_min_price_product_fournisseur($fk_product); + $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id; + } else { + $this->line->fk_fournprice = $fk_fournprice; + } + $this->line->pa_ht = $pa_ht; + + $this->line->date_start=$date_start; + $this->line->date_end=$date_end; + + // TODO deprecated + $this->line->price=$price; + $this->line->remise=$remise; + + if (is_array($array_option) && count($array_option)>0) { + $this->line->array_options=$array_option; + } + + $result=$this->line->update(); + if ($result > 0) + { + // Reorder if child line + if (! empty($fk_parent_line)) $this->line_order(true,'DESC'); + + $this->update_price(1); + + $this->fk_propal = $this->id; + $this->rowid = $rowid; + + $this->db->commit(); + return $result; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + else + { + dol_syslog(get_class($this)."::updateline Erreur -2 Propal en mode incompatible pour cette action"); + return -2; + } + } + + + /** + * Delete detail line + * + * @param int $lineid Id of line to delete + * @return int >0 if OK, <0 if KO + */ + function deleteline($lineid) + { + if ($this->statut == 0) + { + $line=new PropaleLigne($this->db); + + // For triggers + $line->fetch($lineid); + + if ($line->delete() > 0) + { + $this->update_price(1); + + return 1; + } + else + { + return -1; + } + } + else + { + return -2; + } + } + + + /** + * Create commercial proposal into database + * this->ref can be set or empty. If empty, we will use "(PROVid)" + * + * @param User $user User that create + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >=0 if OK + */ + function create($user, $notrigger=0) + { + global $langs,$conf,$mysoc,$hookmanager; + $error=0; + + $now=dol_now(); + + // Clean parameters + if (empty($this->date)) $this->date=$this->datep; + $this->fin_validite = $this->date + ($this->duree_validite * 24 * 3600); + if (empty($this->availability_id)) $this->availability_id=0; + if (empty($this->demand_reason_id)) $this->demand_reason_id=0; + + dol_syslog(get_class($this)."::create"); + + // Check parameters + $result=$this->fetch_thirdparty(); + if ($result < 0) + { + $this->error="Failed to fetch company"; + dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR); + return -3; + } + + // Check parameters + if (! empty($this->ref)) // We check that ref is not already used + { + $result=self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used + if ($result > 0) + { + $this->error='ErrorRefAlreadyExists'; + dol_syslog(get_class($this)."::create ".$this->error,LOG_WARNING); + $this->db->rollback(); + return -1; + } + } + + if (empty($this->date)) + { + $this->error="Date of proposal is required"; + dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR); + return -4; + } + + + $this->db->begin(); + + // Insert into database + $sql = "INSERT INTO ".MAIN_DB_PREFIX."propal ("; + $sql.= "fk_soc"; + $sql.= ", price"; + $sql.= ", remise"; + $sql.= ", remise_percent"; + $sql.= ", remise_absolue"; + $sql.= ", tva"; + $sql.= ", total"; + $sql.= ", datep"; + $sql.= ", datec"; + $sql.= ", ref"; + $sql.= ", fk_user_author"; + $sql.= ", note_private"; + $sql.= ", note_public"; + $sql.= ", model_pdf"; + $sql.= ", fin_validite"; + $sql.= ", fk_cond_reglement"; + $sql.= ", fk_mode_reglement"; + $sql.= ", fk_account"; + $sql.= ", ref_client"; + $sql.= ", date_livraison"; + $sql.= ", fk_shipping_method"; + $sql.= ", fk_availability"; + $sql.= ", fk_input_reason"; + $sql.= ", fk_projet"; + $sql.= ", entity"; + $sql.= ") "; + $sql.= " VALUES ("; + $sql.= $this->socid; + $sql.= ", 0"; + $sql.= ", ".$this->remise; + $sql.= ", ".($this->remise_percent?$this->remise_percent:'null'); + $sql.= ", ".($this->remise_absolue?$this->remise_absolue:'null'); + $sql.= ", 0"; + $sql.= ", 0"; + $sql.= ", '".$this->db->idate($this->date)."'"; + $sql.= ", '".$this->db->idate($now)."'"; + $sql.= ", '(PROV)'"; + $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null"); + $sql.= ", '".$this->db->escape($this->note_private)."'"; + $sql.= ", '".$this->db->escape($this->note_public)."'"; + $sql.= ", '".$this->modelpdf."'"; + $sql.= ", ".($this->fin_validite!=''?"'".$this->db->idate($this->fin_validite)."'":"null"); + $sql.= ", ".$this->cond_reglement_id; + $sql.= ", ".$this->mode_reglement_id; + $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL'); + $sql.= ", '".$this->db->escape($this->ref_client)."'"; + $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":"null"); + $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL'); + $sql.= ", ".$this->availability_id; + $sql.= ", ".$this->demand_reason_id; + $sql.= ", ".($this->fk_project?$this->fk_project:"null"); + $sql.= ", ".$conf->entity; + $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."propal"); + + if ($this->id) + { + $this->ref='(PROV'.$this->id.')'; + $sql = 'UPDATE '.MAIN_DB_PREFIX."propal SET ref='".$this->ref."' WHERE rowid=".$this->id; + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) $error++; + + /* + * Insertion du detail des produits dans la base + */ + if (! $error) + { + $fk_parent_line=0; + $num=count($this->lines); + + for ($i=0;$i<$num;$i++) + { + // Reset fk_parent_line for no child products and special product + if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) { + $fk_parent_line = 0; + } + + $result = $this->addline( + $this->lines[$i]->desc, + $this->lines[$i]->subprice, + $this->lines[$i]->qty, + $this->lines[$i]->tva_tx, + $this->lines[$i]->localtax1_tx, + $this->lines[$i]->localtax2_tx, + $this->lines[$i]->fk_product, + $this->lines[$i]->remise_percent, + 'HT', + 0, + 0, + $this->lines[$i]->product_type, + $this->lines[$i]->rang, + $this->lines[$i]->special_code, + $fk_parent_line, + $this->lines[$i]->fk_fournprice, + $this->lines[$i]->pa_ht, + $this->lines[$i]->label, + $this->lines[$i]->date_start, + $this->lines[$i]->date_end, + $this->lines[$i]->array_options + ); + + if ($result < 0) + { + $error++; + $this->error=$this->db->error; + dol_print_error($this->db); + break; + } + // Defined the new fk_parent_line + if ($result > 0 && $this->lines[$i]->product_type == 9) { + $fk_parent_line = $result; + } + } + } + + // Add linked object + if (! $error && $this->origin && $this->origin_id) + { + $ret = $this->add_object_linked(); + if (! $ret) dol_print_error($this->db); + } + + // Set delivery address + if (! $error && $this->fk_delivery_address) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; + $sql.= " SET fk_delivery_address = ".$this->fk_delivery_address; + $sql.= " WHERE ref = '".$this->ref."'"; + $sql.= " AND entity = ".$conf->entity; + + $result=$this->db->query($sql); + } + + if (! $error) + { + // Mise a jour infos denormalisees + $resql=$this->update_price(1); + if ($resql) + { + $action='update'; + + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('propaldao')); + $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(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('PROPAL_CREATE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + + if (! $error) + { + $this->db->commit(); + dol_syslog(get_class($this)."::create done id=".$this->id); + return $this->id; + } + else + { + $this->db->rollback(); + return -2; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + } + + + /** + * Insert into DB a proposal object completely defined by its data members (ex, results from copy). + * + * @param User $user User that create + * @return int Id of the new object if ok, <0 if ko + * @see create + */ + function create_from($user) + { + $this->products=$this->lines; + + return $this->create($user); + } + + /** + * Load an object from its id and create a new one in database + * + * @param int $socid Id of thirdparty + * @return int New id of clone + */ + function createFromClone($socid=0) + { + global $user,$langs,$conf,$hookmanager; + + $error=0; + $now=dol_now(); + + $this->db->begin(); + + // get extrafields so they will be clone + foreach($this->lines as $line) + $line->fetch_optionals($line->rowid); + + // Load source object + $objFrom = dol_clone($this); + + $objsoc=new Societe($this->db); + + // Change socid if needed + if (! empty($socid) && $socid != $this->socid) + { + if ($objsoc->fetch($socid) > 0) + { + $this->socid = $objsoc->id; + $this->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); + $this->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); + $this->fk_project = ''; + $this->fk_delivery_address = ''; + } + + // reset ref_client + $this->ref_client = ''; + + // TODO Change product price if multi-prices + } + else + { + $objsoc->fetch($this->socid); + } + + $this->id=0; + $this->statut=0; + + if (empty($conf->global->PROPALE_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/propale/".$conf->global->PROPALE_ADDON.".php")) + { + $this->error='ErrorSetupNotComplete'; + return -1; + } + + // Clear fields + $this->user_author = $user->id; + $this->user_valid = ''; + $this->date = $now; + $this->datep = $now; // deprecated + $this->fin_validite = $this->date + ($this->duree_validite * 24 * 3600); + if (empty($conf->global->MAIN_KEEP_REF_CUSTOMER_ON_CLONING)) $this->ref_client = ''; + + // Set ref + require_once DOL_DOCUMENT_ROOT ."/core/modules/propale/".$conf->global->PROPALE_ADDON.'.php'; + $obj = $conf->global->PROPALE_ADDON; + $modPropale = new $obj; + $this->ref = $modPropale->getNextValue($objsoc,$this); + + // Create clone + $result=$this->create($user); + if ($result < 0) $error++; + else + { + // copy internal contacts + if ($this->copy_linked_contact($objFrom, 'internal') < 0) + $error++; + + // copy external contacts if same company + elseif ($objFrom->socid == $this->socid) + { + if ($this->copy_linked_contact($objFrom, 'external') < 0) + $error++; + } + } + + if (! $error) + { + // Hook of thirdparty module + if (is_object($hookmanager)) + { + $parameters=array('objFrom'=>$objFrom); + $action=''; + $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) $error++; + } + + // Call trigger + $result=$this->call_trigger('PROPAL_CLONE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + + // End + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Load a proposal from database and its ligne array + * + * @param int $rowid id of object to load + * @param string $ref Ref of proposal + * @return int >0 if OK, <0 if KO + */ + function fetch($rowid,$ref='') + { + global $conf; + + $sql = "SELECT p.rowid, p.ref, p.remise, p.remise_percent, p.remise_absolue, p.fk_soc"; + $sql.= ", p.total, p.tva, p.localtax1, p.localtax2, p.total_ht"; + $sql.= ", p.datec"; + $sql.= ", p.date_valid as datev"; + $sql.= ", p.datep as dp"; + $sql.= ", p.fin_validite as dfv"; + $sql.= ", p.date_livraison as date_livraison"; + $sql.= ", p.model_pdf, p.ref_client, p.extraparams"; + $sql.= ", p.note_private, p.note_public"; + $sql.= ", p.fk_projet, p.fk_statut"; + $sql.= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture"; + $sql.= ", p.fk_delivery_address"; + $sql.= ", p.fk_availability"; + $sql.= ", p.fk_input_reason"; + $sql.= ", p.fk_cond_reglement"; + $sql.= ", p.fk_mode_reglement"; + $sql.= ', p.fk_account'; + $sql.= ", p.fk_shipping_method"; + $sql.= ", c.label as statut_label"; + $sql.= ", ca.code as availability_code, ca.label as availability"; + $sql.= ", dr.code as demand_reason_code, dr.label as demand_reason"; + $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc"; + $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_propalst as c, ".MAIN_DB_PREFIX."propal as p"; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON p.fk_availability = ca.rowid'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON p.fk_input_reason = dr.rowid'; + $sql.= " WHERE p.fk_statut = c.id"; + $sql.= " AND p.entity = ".$conf->entity; + if ($ref) $sql.= " AND p.ref='".$ref."'"; + else $sql.= " AND p.rowid=".$rowid; + + 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->ref_client = $obj->ref_client; + $this->remise = $obj->remise; + $this->remise_percent = $obj->remise_percent; + $this->remise_absolue = $obj->remise_absolue; + $this->total = $obj->total; // TODO obsolete + $this->total_ht = $obj->total_ht; + $this->total_tva = $obj->tva; + $this->total_localtax1 = $obj->localtax1; + $this->total_localtax2 = $obj->localtax2; + $this->total_ttc = $obj->total; + $this->socid = $obj->fk_soc; + $this->fk_project = $obj->fk_projet; + $this->modelpdf = $obj->model_pdf; + $this->note = $obj->note_private; // TODO obsolete + $this->note_private = $obj->note_private; + $this->note_public = $obj->note_public; + $this->statut = $obj->fk_statut; + $this->statut_libelle = $obj->statut_label; + + $this->datec = $this->db->jdate($obj->datec); // TODO obsolete + $this->datev = $this->db->jdate($obj->datev); // TODO obsolete + $this->date_creation = $this->db->jdate($obj->datec); //Creation date + $this->date_validation = $this->db->jdate($obj->datev); //Validation date + $this->date = $this->db->jdate($obj->dp); // Proposal date + $this->datep = $this->db->jdate($obj->dp); // deprecated + $this->fin_validite = $this->db->jdate($obj->dfv); + $this->date_livraison = $this->db->jdate($obj->date_livraison); + $this->shipping_method_id = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null; + $this->availability_id = $obj->fk_availability; + $this->availability_code = $obj->availability_code; + $this->availability = $obj->availability; + $this->demand_reason_id = $obj->fk_input_reason; + $this->demand_reason_code = $obj->demand_reason_code; + $this->demand_reason = $obj->demand_reason; + $this->fk_address = $obj->fk_delivery_address; + + $this->mode_reglement_id = $obj->fk_mode_reglement; + $this->mode_reglement_code = $obj->mode_reglement_code; + $this->mode_reglement = $obj->mode_reglement; + $this->fk_account = ($obj->fk_account>0)?$obj->fk_account:null; + $this->cond_reglement_id = $obj->fk_cond_reglement; + $this->cond_reglement_code = $obj->cond_reglement_code; + $this->cond_reglement = $obj->cond_reglement; + $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc; + + $this->extraparams = (array) json_decode($obj->extraparams, true); + + $this->user_author_id = $obj->fk_user_author; + $this->user_valid_id = $obj->fk_user_valid; + $this->user_close_id = $obj->fk_user_cloture; + + if ($obj->fk_statut == 0) + { + $this->brouillon = 1; + } + + // Retreive all extrafield for invoice + // 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); + + $this->db->free($resql); + + $this->lines = array(); + + /* + * Lignes propales liees a un produit ou non + */ + $sql = "SELECT d.rowid, d.fk_propal, d.fk_parent_line, d.label as custom_label, d.description, d.price, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,"; + $sql.= " d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht, d.special_code, d.rang, d.product_type,"; + $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,'; + $sql.= ' d.date_start, d.date_end'; + $sql.= " FROM ".MAIN_DB_PREFIX."propaldet as d"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid"; + $sql.= " WHERE d.fk_propal = ".$this->id; + $sql.= " ORDER by d.rang"; + + $result = $this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); + $i = 0; + + while ($i < $num) + { + $objp = $this->db->fetch_object($result); + + $line = new PropaleLigne($this->db); + + $line->rowid = $objp->rowid; + $line->fk_propal = $objp->fk_propal; + $line->fk_parent_line = $objp->fk_parent_line; + $line->product_type = $objp->product_type; + $line->label = $objp->custom_label; + $line->desc = $objp->description; // Description ligne + $line->qty = $objp->qty; + $line->tva_tx = $objp->tva_tx; + $line->localtax1_tx = $objp->localtax1_tx; + $line->localtax2_tx = $objp->localtax2_tx; + $line->subprice = $objp->subprice; + $line->fk_remise_except = $objp->fk_remise_except; + $line->remise_percent = $objp->remise_percent; + $line->price = $objp->price; // TODO deprecated + + $line->info_bits = $objp->info_bits; + $line->total_ht = $objp->total_ht; + $line->total_tva = $objp->total_tva; + $line->total_localtax1 = $objp->total_localtax1; + $line->total_localtax2 = $objp->total_localtax2; + $line->total_ttc = $objp->total_ttc; + $line->fk_fournprice = $objp->fk_fournprice; + $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht); + $line->pa_ht = $marginInfos[0]; + $line->marge_tx = $marginInfos[1]; + $line->marque_tx = $marginInfos[2]; + $line->special_code = $objp->special_code; + $line->rang = $objp->rang; + + $line->fk_product = $objp->fk_product; + + $line->ref = $objp->product_ref; // TODO deprecated + $line->product_ref = $objp->product_ref; + $line->libelle = $objp->product_label; // TODO deprecated + $line->product_label = $objp->product_label; + $line->product_desc = $objp->product_desc; // Description produit + $line->fk_product_type = $objp->fk_product_type; + + $line->date_start = $objp->date_start; + $line->date_end = $objp->date_end; + + $this->lines[$i] = $line; + //dol_syslog("1 ".$line->fk_product); + //print "xx $i ".$this->lines[$i]->fk_product; + $i++; + } + $this->db->free($result); + } + else + { + $this->error=$this->db->error(); + return -1; + } + + // Retreive all extrafield for propal + // 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); + + return 1; + } + + $this->error="Record Not Found"; + return 0; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + /** + * Update value of extrafields on the proposal + * + * @param User $user Object user that modify + * @return int <0 if ko, >0 if ok + */ + function update_extrafields($user) + { + $action='update'; + + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('propaldao')); + $parameters=array('id'=>$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(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + + if (!$error) + { + return 1; + } + else + { + return -1; + } + + } + + /** + * Set status to validated + * + * @param User $user Object user that validate + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >=0 if OK + */ + function valid($user, $notrigger=0) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + global $conf,$langs; + + $error=0; + $now=dol_now(); + + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->propal->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->propal->propal_advance->validate))) + { + $this->db->begin(); + + // Numbering module definition + $soc = new Societe($this->db); + $soc->fetch($this->socid); + + // Define new ref + if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref))) + { + $num = $this->getNextNumRef($soc); + } + else + { + $num = $this->ref; + } + $this->newref = $num; + + $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; + $sql.= " SET ref = '".$num."',"; + $sql.= " fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + dol_syslog(get_class($this)."::valid", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) + { + dol_print_error($this->db); + $error++; + } + + // Trigger calls + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('PROPAL_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)) + { + // Rename of propal directory ($this->ref = old ref, $num = new ref) + // to not lose the linked files + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->propal->dir_output.'/'.$oldref; + $dirdest = $conf->propal->dir_output.'/'.$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->propal->dir_output.'/'.$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); + } + } + } + } + + $this->ref=$num; + $this->brouillon=0; + $this->statut = 1; + $this->user_valid_id=$user->id; + $this->datev=$now; + + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + } + + + /** + * Define proposal date + * + * @param User $user Object user that modify + * @param int $date Date + * @return int <0 if KO, >0 if OK + */ + function set_date($user, $date) + { + if (empty($date)) + { + $this->error='ErrorBadParameter'; + dol_syslog(get_class($this)."::set_date ".$this->error, LOG_ERR); + return -1; + } + + if (! empty($user->rights->propal->creer)) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET datep = '".$this->db->idate($date)."'"; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + dol_syslog(get_class($this)."::set_date", LOG_DEBUG); + if ($this->db->query($sql) ) + { + $this->date = $date; + $this->datep = $date; // deprecated + return 1; + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + } + } + + /** + * Define end validity date + * + * @param User $user Object user that modify + * @param int $date_fin_validite End of validity date + * @return int <0 if KO, >0 if OK + */ + function set_echeance($user, $date_fin_validite) + { + if (! empty($user->rights->propal->creer)) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fin_validite = ".($date_fin_validite!=''?"'".$this->db->idate($date_fin_validite)."'":'null'); + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + if ($this->db->query($sql) ) + { + $this->fin_validite = $date_fin_validite; + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + } + + /** + * Set delivery date + * + * @param User $user Object user that modify + * @param int $date_livraison Delivery date + * @return int <0 if ko, >0 if ok + */ + function set_date_livraison($user, $date_livraison) + { + if (! empty($user->rights->propal->creer)) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."propal "; + $sql.= " SET date_livraison = ".($date_livraison!=''?"'".$this->db->idate($date_livraison)."'":'null'); + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + $this->date_livraison = $date_livraison; + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::set_date_livraison Erreur SQL"); + return -1; + } + } + } + + /** + * Set delivery + * + * @param User $user Object user that modify + * @param int $id Availability id + * @return int <0 if KO, >0 if OK + */ + function set_availability($user, $id) + { + if (! empty($user->rights->propal->creer)) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."propal "; + $sql.= " SET fk_availability = '".$id."'"; + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + $this->fk_availability = $id; + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::set_availability Erreur SQL"); + return -1; + } + } + } + + /** + * Set source of demand + * + * @param User $user Object user that modify + * @param int $id Input reason id + * @return int <0 if KO, >0 if OK + */ + function set_demand_reason($user, $id) + { + if (! empty($user->rights->propal->creer)) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."propal "; + $sql.= " SET fk_input_reason = '".$id."'"; + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + $this->fk_input_reason = $id; + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::set_demand_reason Erreur SQL"); + return -1; + } + } + } + + /** + * Set customer reference number + * + * @param User $user Object user that modify + * @param string $ref_client Customer reference + * @return int <0 if ko, >0 if ok + */ + function set_ref_client($user, $ref_client) + { + if (! empty($user->rights->propal->creer)) + { + dol_syslog('Propale::set_ref_client this->id='.$this->id.', ref_client='.$ref_client); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET ref_client = '.(empty($ref_client) ? 'NULL' : '\''.$this->db->escape($ref_client).'\''); + $sql.= ' WHERE rowid = '.$this->id; + if ($this->db->query($sql) ) + { + $this->ref_client = $ref_client; + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog('Propale::set_ref_client Erreur '.$this->error.' - '.$sql); + return -2; + } + } + else + { + return -1; + } + } + + /** + * Set an overall discount on the proposal + * + * @param User $user Object user that modify + * @param double $remise Amount discount + * @return int <0 if ko, >0 if ok + */ + function set_remise_percent($user, $remise) + { + $remise=trim($remise)?trim($remise):0; + + if (! empty($user->rights->propal->creer)) + { + $remise = price2num($remise); + + $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET remise_percent = ".$remise; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + if ($this->db->query($sql) ) + { + $this->remise_percent = $remise; + $this->update_price(1); + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + } + + + /** + * Set an absolute overall discount on the proposal + * + * @param User $user Object user that modify + * @param double $remise Amount discount + * @return int <0 if ko, >0 if ok + */ + function set_remise_absolue($user, $remise) + { + $remise=trim($remise)?trim($remise):0; + + if (! empty($user->rights->propal->creer)) + { + $remise = price2num($remise); + + $sql = "UPDATE ".MAIN_DB_PREFIX."propal "; + $sql.= " SET remise_absolue = ".$remise; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + if ($this->db->query($sql) ) + { + $this->remise_absolue = $remise; + $this->update_price(1); + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + } + + + + /** + * Reopen the commercial proposal + * + * @param User $user Object user that close + * @param int $statut Statut + * @param string $note Comment + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >0 if OK + */ + function reopen($user, $statut, $note='', $notrigger=0) + { + global $langs,$conf; + + $this->statut = $statut; + $error=0; + + $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; + $sql.= " SET fk_statut = ".$this->statut.","; + if (! empty($note)) $sql.= " note_private = '".$this->db->escape($note)."',"; + $sql.= " date_cloture=NULL, fk_user_cloture=NULL"; + $sql.= " WHERE rowid = ".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::reopen", 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('PROPAL_REOPEN',$user); + if ($result < 0) { $error++; } + // End call triggers + } + } + + // Commit or rollback + if ($error) + { + if (!empty($this->errors)) + { + 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; + } + } + + + /** + * Close the commercial proposal + * + * @param User $user Object user that close + * @param int $statut Statut + * @param string $note Comment + * @return int <0 if KO, >0 if OK + */ + function cloture($user, $statut, $note) + { + global $langs,$conf; + + $this->statut = $statut; + $error=0; + $now=dol_now(); + + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; + $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($note)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id; + $sql.= " WHERE rowid = ".$this->id; + + $resql=$this->db->query($sql); + if ($resql) + { + $modelpdf=$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED?$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED:$this->modelpdf; + $trigger_name='PROPAL_CLOSE_REFUSED'; + + if ($statut == 2) + { + $trigger_name='PROPAL_CLOSE_SIGNED'; + $modelpdf=$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL?$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL:$this->modelpdf; + + // The connected company is classified as a client + $soc=new Societe($this->db); + $soc->id = $this->socid; + $result=$soc->set_as_client(); + + if ($result < 0) + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -2; + } + } + if ($statut == 4) + { + $trigger_name='PROPAL_CLASSIFY_BILLED'; + } + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $this->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + //$ret=$object->fetch($id); // Reload to get new records + $this->generateDocument($modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + // Call trigger + $result=$this->call_trigger($trigger_name,$user); + if ($result < 0) { $error++; } + // End call triggers + + if ( ! $error ) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + + /** + * Class invoiced the Propal + * + * @return int <0 si ko, >0 si ok + */ + function classifyBilled() + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET fk_statut = 4'; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0 ;'; + if ($this->db->query($sql) ) + { + $this->statut=4; + return 1; + } + else + { + dol_print_error($this->db); + } + } + + /** + * Class invoiced the Propal + * + * @return int <0 si ko, >0 si ok + * @deprecated + */ + function classer_facturee() + { + return $this->classifyBilled(); + } + + /** + * Set draft status + * + * @param User $user Object user that modify + * @return int <0 if KO, >0 if OK + */ + function set_draft($user) + { + global $conf,$langs; + + $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fk_statut = 0"; + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + $this->statut = 0; + $this->brouillon = 1; + return 1; + } + else + { + return -1; + } + } + + + /** + * Return list of proposal (eventually filtered on user) into an array + * + * @param int $shortlist 0=Return array[id]=ref, 1=Return array[](id=>id,ref=>ref,name=>name) + * @param int $draft 0=not draft, 1=draft + * @param int $notcurrentuser 0=all user, 1=not current user + * @param int $socid Id third pary + * @param int $limit For pagination + * @param int $offset For pagination + * @param string $sortfield Sort criteria + * @param string $sortorder Sort order + * @return int -1 if KO, array with result if OK + */ + function liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datep', $sortorder='DESC') + { + global $conf,$user; + + $ga = array(); + + $sql = "SELECT s.rowid, s.nom as name, s.client,"; + $sql.= " p.rowid as propalid, p.fk_statut, p.total_ht, p.ref, p.remise, "; + $sql.= " p.datep as dp, p.fin_validite as datelimite"; + if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user"; + $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as p, ".MAIN_DB_PREFIX."c_propalst as c"; + if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE p.entity = ".$conf->entity; + $sql.= " AND p.fk_soc = s.rowid"; + $sql.= " AND p.fk_statut = c.id"; + if (! $user->rights->societe->client->voir && ! $socid) //restriction + { + $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + } + if ($socid) $sql.= " AND s.rowid = ".$socid; + if ($draft) $sql.= " AND p.fk_statut = 0"; + if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id; + $sql.= $this->db->order($sortfield,$sortorder); + $sql.= $this->db->plimit($limit,$offset); + + $result=$this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); + if ($num) + { + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($result); + + if ($shortlist == 1) + { + $ga[$obj->propalid] = $obj->ref; + } + else if ($shortlist == 2) + { + $ga[$obj->propalid] = $obj->ref.' ('.$obj->name.')'; + } + else + { + $ga[$i]['id'] = $obj->propalid; + $ga[$i]['ref'] = $obj->ref; + $ga[$i]['name'] = $obj->name; + } + + $i++; + } + } + return $ga; + } + else + { + dol_print_error($this->db); + return -1; + } + } + + /** + * Returns an array with the numbers of related invoices + * + * @return array Array of invoices + */ + function getInvoiceArrayList() + { + return $this->InvoiceArrayList($this->id); + } + + /** + * Returns an array with id and ref of related invoices + * + * @param int $id Id propal + * @return array Array of invoices id + */ + function InvoiceArrayList($id) + { + $ga = array(); + $linkedInvoices = array(); + + $this->fetchObjectLinked($id,$this->element); + foreach($this->linkedObjectsIds as $objecttype => $objectid) + { + $numi=count($objectid); + for ($i=0;$i<$numi;$i++) + { + // Cas des factures liees directement + if ($objecttype == 'facture') + { + $linkedInvoices[] = $objectid[$i]; + } + // Cas des factures liees par un autre objet (ex: commande) + else + { + $this->fetchObjectLinked($objectid[$i],$objecttype); + foreach($this->linkedObjectsIds as $subobjecttype => $subobjectid) + { + $numj=count($subobjectid); + for ($j=0;$j<$numj;$j++) + { + if ($subobjecttype == 'facture') + { + $linkedInvoices[] = $subobjectid[$j]; + } + } + } + } + } + } + + if (count($linkedInvoices) > 0) + { + $sql= "SELECT rowid as facid, facnumber, total, datef as df, fk_user_author, fk_statut, paye"; + $sql.= " FROM ".MAIN_DB_PREFIX."facture"; + $sql.= " WHERE rowid IN (".implode(',',$linkedInvoices).")"; + + dol_syslog(get_class($this)."::InvoiceArrayList", LOG_DEBUG); + $resql=$this->db->query($sql); + + if ($resql) + { + $tab_sqlobj=array(); + $nump = $this->db->num_rows($resql); + for ($i = 0;$i < $nump;$i++) + { + $sqlobj = $this->db->fetch_object($resql); + $tab_sqlobj[] = $sqlobj; + } + $this->db->free($resql); + + $nump = count($tab_sqlobj); + + if ($nump) + { + $i = 0; + while ($i < $nump) + { + $obj = array_shift($tab_sqlobj); + + $ga[$i] = $obj; + + $i++; + } + } + return $ga; + } + else + { + return -1; + } + } + else return $ga; + } + + /** + * Delete proposal + * + * @param User $user Object user that delete + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int 1 if ok, otherwise if error + */ + function delete($user, $notrigger=0) + { + global $conf,$langs; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error=0; + + $this->db->begin(); + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('PROPAL_DELETE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."propaldet WHERE fk_propal = ".$this->id; + if ($this->db->query($sql)) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."propal WHERE rowid = ".$this->id; + if ($this->db->query($sql)) + { + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) $error++; + + // Delete linked contacts + $res = $this->delete_linked_contact(); + if ($res < 0) $error++; + + if (! $error) + { + // We remove directory + $ref = dol_sanitizeFileName($this->ref); + if ($conf->propal->dir_output && !empty($this->ref)) + { + $dir = $conf->propal->dir_output . "/" . $ref ; + $file = $dir . "/" . $ref . ".pdf"; + if (file_exists($file)) + { + dol_delete_preview($this); + + if (! dol_delete_file($file,0,0,0,$this)) // For triggers + { + $this->error='ErrorFailToDeleteFile'; + $this->errors=array('ErrorFailToDeleteFile'); + $this->db->rollback(); + return 0; + } + } + if (file_exists($dir)) + { + $res=@dol_delete_dir_recursive($dir); + if (! $res) + { + $this->error='ErrorFailToDeleteDir'; + $this->errors=array('ErrorFailToDeleteDir'); + $this->db->rollback(); + return 0; + } + } + } + } + + // Removed extrafields + if (! $error) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->deleteExtraFields(); + if ($result < 0) + { + $error++; + $errorflag=-4; + dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$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 0; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -3; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -2; + } + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Change the delivery time + * + * @param int $availability_id Id of new delivery time + * @return int >0 if OK, <0 if KO + */ + function availability($availability_id) + { + dol_syslog('Propale::availability('.$availability_id.')'); + if ($this->statut >= 0) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal'; + $sql .= ' SET fk_availability = '.$availability_id; + $sql .= ' WHERE rowid='.$this->id; + if ( $this->db->query($sql) ) + { + $this->availability_id = $availability_id; + return 1; + } + else + { + dol_syslog('Propale::availability Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog('Propale::availability, etat propale incompatible'); + $this->error='Etat propale incompatible '.$this->statut; + return -2; + } + } + + /** + * Change source demand + * + * @param int $demand_reason_id Id of new source demand + * @return int >0 si ok, <0 si ko + */ + function demand_reason($demand_reason_id) + { + dol_syslog('Propale::demand_reason('.$demand_reason_id.')'); + if ($this->statut >= 0) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal'; + $sql .= ' SET fk_input_reason = '.$demand_reason_id; + $sql .= ' WHERE rowid='.$this->id; + if ( $this->db->query($sql) ) + { + $this->demand_reason_id = $demand_reason_id; + return 1; + } + else + { + dol_syslog('Propale::demand_reason Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog('Propale::demand_reason, etat propale incompatible'); + $this->error='Etat propale incompatible '.$this->statut; + return -2; + } + } + + + /** + * Object Proposal Information + * + * @param int $id Proposal id + * @return void + */ + function info($id) + { + $sql = "SELECT c.rowid, "; + $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,"; + $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture"; + $sql.= " FROM ".MAIN_DB_PREFIX."propal 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; + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_validation = $this->db->jdate($obj->datev); + $this->date_cloture = $this->db->jdate($obj->dateo); + + $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; + } + + if ($obj->fk_user_cloture) + { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + + } + $this->db->free($result); + + } + else + { + dol_print_error($this->db); + } + } + + + /** + * Return label of status of proposal (draft, validated, ...) + * + * @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 + */ + function getLibStatut($mode=0) + { + return $this->LibStatut($this->statut,$mode); + } + + /** + * Return label of a status (draft, validated, ...) + * + * @param int $statut id statut + * @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 + */ + function LibStatut($statut,$mode=1) + { + global $langs; + $langs->load("propal"); + + if ($statut==0) $statuttrans='statut0'; + if ($statut==1) $statuttrans='statut1'; + if ($statut==2) $statuttrans='statut3'; + if ($statut==3) $statuttrans='statut5'; + if ($statut==4) $statuttrans='statut6'; + + if ($mode == 0) return $this->labelstatut[$statut]; + if ($mode == 1) return $this->labelstatut_short[$statut]; + if ($mode == 2) return img_picto($this->labelstatut_short[$statut], $statuttrans).' '.$this->labelstatut_short[$statut]; + if ($mode == 3) return img_picto($this->labelstatut[$statut], $statuttrans); + if ($mode == 4) return img_picto($this->labelstatut[$statut],$statuttrans).' '.$this->labelstatut[$statut]; + if ($mode == 5) return ''.$this->labelstatut_short[$statut].' '.img_picto($this->labelstatut_short[$statut],$statuttrans); + } + + + /** + * Load indicators for dashboard (this->nbtodo and this->nbtodolate) + * + * @param User $user Object user + * @param int $mode "opened" for proposal to close, "signed" for proposal to invoice + * @return int <0 if KO, >0 if OK + */ + function load_board($user,$mode) + { + global $conf, $user; + + $now=dol_now(); + + $this->nbtodo=$this->nbtodolate=0; + $clause = " WHERE"; + + $sql = "SELECT p.rowid, p.ref, p.datec as datec, p.fin_validite as datefin"; + $sql.= " FROM ".MAIN_DB_PREFIX."propal as p"; + if (!$user->rights->societe->client->voir && !$user->societe_id) + { + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc"; + $sql.= " WHERE sc.fk_user = " .$user->id; + $clause = " AND"; + } + $sql.= $clause." p.entity = ".$conf->entity; + if ($mode == 'opened') $sql.= " AND p.fk_statut = 1"; + if ($mode == 'signed') $sql.= " AND p.fk_statut = 2"; + if ($user->societe_id) $sql.= " AND p.fk_soc = ".$user->societe_id; + + $resql=$this->db->query($sql); + if ($resql) + { + if ($mode == 'opened') $delay_warning=$conf->propal->cloture->warning_delay; + if ($mode == 'signed') $delay_warning=$conf->propal->facturation->warning_delay; + + // This assignment in condition is not a bug. It allows walking the results. + while ($obj=$this->db->fetch_object($resql)) + { + $this->nbtodo++; + if ($mode == 'opened') + { + $datelimit = $this->db->jdate($obj->datefin); + if ($datelimit < ($now - $delay_warning)) + { + $this->nbtodolate++; + } + } + // TODO Definir regle des propales a facturer en retard + // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++; + } + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + + /** + * 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 $user,$langs,$conf; + + // 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_client='NEMICEPS'; + $this->specimen=1; + $this->socid = 1; + $this->date = time(); + $this->fin_validite = $this->date+3600*24*30; + $this->cond_reglement_id = 1; + $this->cond_reglement_code = 'RECEP'; + $this->mode_reglement_id = 7; + $this->mode_reglement_code = 'CHQ'; + $this->availability_id = 1; + $this->availability_code = 'AV_NOW'; + $this->demand_reason_id = 1; + $this->demand_reason_code = 'SRC_00'; + $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 PropaleLigne($this->db); + $line->desc=$langs->trans("Description")." ".$xnbp; + $line->qty=1; + $line->subprice=100; + $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=00; + } + + $prodid = rand(1, $num_prods); + $line->fk_product=$prodids[$prodid]; + + $this->lines[$xnbp]=$line; + + $this->total_ht += $line->total_ht; + $this->total_tva += $line->total_tva; + $this->total_ttc += $line->total_ttc; + + $xnbp++; + } + } + + /** + * Charge indicateurs this->nb de tableau de bord + * + * @return int <0 if ko, >0 if ok + */ + function load_state_board() + { + global $conf, $user; + + $this->nb=array(); + $clause = "WHERE"; + + $sql = "SELECT count(p.rowid) as nb"; + $sql.= " FROM ".MAIN_DB_PREFIX."propal as p"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.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." p.entity = ".$conf->entity; + + $resql=$this->db->query($sql); + if ($resql) + { + // This assignment in condition is not a bug. It allows walking the results. + while ($obj=$this->db->fetch_object($resql)) + { + $this->nb["proposals"]=$obj->nb; + } + $this->db->free($resql); + return 1; + } + else + { + dol_print_error($this->db); + $this->error=$this->db->error(); + return -1; + } + } + + + /** + * Returns the reference to the following non used Proposal used depending on the active numbering module + * defined into PROPALE_ADDON + * + * @param Societe $soc Object thirdparty + * @return string Reference libre pour la propale + */ + function getNextNumRef($soc) + { + global $conf, $db, $langs; + $langs->load("propal"); + + if (! empty($conf->global->PROPALE_ADDON)) + { + $mybool=false; + + $file = $conf->global->PROPALE_ADDON.".php"; + $classname = $conf->global->PROPALE_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + + $dir = dol_buildpath($reldir."core/modules/propale/"); + + // 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->getNextValue($soc,$this); + + if ($numref != "") + { + return $numref; + } + else + { + $this->error=$obj->error; + //dol_print_error($db,"Propale::getNextNumRef ".$obj->error); + return ""; + } + } + else + { + $langs->load("errors"); + print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete"); + return ""; + } + } + + /** + * Return clicable link of object (with eventually picto) + * + * @param int $withpicto Add picto into link + * @param string $option Where point the link ('compta', 'expedition', 'document', ...) + * @param string $get_params Parametres added to url + * @return string String with URL + */ + function getNomUrl($withpicto=0,$option='', $get_params='') + { + global $langs; + + $result=''; + $label=$langs->trans("ShowPropal").': '.$this->ref; + if (! empty($this->ref_client)) + $label.= '
'.$langs->trans('RefCustomer').': '.$this->ref_client; + $linkclose = '" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">'; + if ($option == '') { + $lien = ''; + + $picto='propal'; + + + if ($withpicto) + $result.=($lien.img_object($label, $picto, 'class="classfortooltip"').$lienfin); + if ($withpicto && $withpicto != 2) + $result.=' '; + $result.=$lien.$this->ref.$lienfin; + return $result; + } + + /** + * Retrieve an array of propal lines + * + * @return int <0 if ko, >0 if ok + */ + function getLinesArray() + { + $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,'; + $sql.= ' pt.qty, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,'; + $sql.= ' pt.total_ht, pt.total_tva, pt.total_ttc, pt.fk_product_fournisseur_price as fk_fournprice, pt.buy_price_ht as pa_ht, pt.special_code, pt.localtax1_tx, pt.localtax2_tx,'; + $sql.= ' pt.date_start, pt.date_end, pt.product_type, pt.rang, pt.fk_parent_line,'; + $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,'; + $sql.= ' p.description as product_desc'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'propaldet as pt'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pt.fk_product=p.rowid'; + $sql.= ' WHERE pt.fk_propal = '.$this->id; + $sql.= ' ORDER BY pt.rang ASC, pt.rowid'; + + dol_syslog(get_class($this).'::getLinesArray', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i = 0; + + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + $this->lines[$i] = new PropaleLigne($this->db); + $this->lines[$i]->id = $obj->rowid; // for backward compatibility + $this->lines[$i]->rowid = $obj->rowid; + $this->lines[$i]->label = $obj->custom_label; + $this->lines[$i]->description = $obj->description; + $this->lines[$i]->fk_product = $obj->fk_product; + $this->lines[$i]->ref = $obj->ref; + $this->lines[$i]->product_label = $obj->product_label; + $this->lines[$i]->product_desc = $obj->product_desc; + $this->lines[$i]->fk_product_type = $obj->fk_product_type; // deprecated + $this->lines[$i]->product_type = $obj->product_type; + $this->lines[$i]->qty = $obj->qty; + $this->lines[$i]->subprice = $obj->subprice; + $this->lines[$i]->fk_remise_except = $obj->fk_remise_except; + $this->lines[$i]->remise_percent = $obj->remise_percent; + $this->lines[$i]->tva_tx = $obj->tva_tx; + $this->lines[$i]->info_bits = $obj->info_bits; + $this->lines[$i]->total_ht = $obj->total_ht; + $this->lines[$i]->total_tva = $obj->total_tva; + $this->lines[$i]->total_ttc = $obj->total_ttc; + $this->lines[$i]->fk_fournprice = $obj->fk_fournprice; + $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht); + $this->lines[$i]->pa_ht = $marginInfos[0]; + $this->lines[$i]->marge_tx = $marginInfos[1]; + $this->lines[$i]->marque_tx = $marginInfos[2]; + $this->lines[$i]->fk_parent_line = $obj->fk_parent_line; + $this->lines[$i]->special_code = $obj->special_code; + $this->lines[$i]->rang = $obj->rang; + $this->lines[$i]->date_start = $this->db->jdate($obj->date_start); + $this->lines[$i]->date_end = $this->db->jdate($obj->date_end); + + $i++; + } + $this->db->free($resql); + + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force model to use ('' to not force) + * @param Translate $outputlangs Object langs to use for output + * @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("propale"); + + // Positionne le modele sur le nom du modele a utiliser + if (! dol_strlen($modele)) + { + if (! empty($conf->global->PROPALE_ADDON_PDF)) + { + $modele = $conf->global->PROPALE_ADDON_PDF; + } + else + { + $modele = 'azur'; + } + } + + $modelpath = "core/modules/propale/doc/"; + + return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + +} + + +/** + * \class PropaleLigne + * \brief Class to manage commercial proposal lines + */ +class PropaleLigne extends CommonObject +{ + var $db; + var $error; + + public $element='propaldet'; + public $table_element='propaldet'; + + var $oldline; + + // From llx_propaldet + var $rowid; + var $fk_propal; + var $fk_parent_line; + var $desc; // Description ligne + var $fk_product; // Id produit predefini + var $product_type = 0; // Type 0 = product, 1 = Service + + var $qty; + var $tva_tx; + var $subprice; + var $remise_percent; + var $fk_remise_except; + + var $rang = 0; + + var $fk_fournprice; + var $pa_ht; + var $marge_tx; + var $marque_tx; + + var $special_code; // Tag for special lines (exlusive tags) + // 1: frais de port + // 2: ecotaxe + // 3: option line (when qty = 0) + + var $info_bits = 0; // Liste d'options cumulables: + // Bit 0: 0 si TVA normal - 1 si TVA NPR + // Bit 1: 0 ligne normale - 1 si ligne de remise fixe + + var $total_ht; // Total HT de la ligne toute quantite et incluant la remise ligne + var $total_tva; // Total TVA de la ligne toute quantite et incluant la remise ligne + var $total_ttc; // Total TTC de la ligne toute quantite et incluant la remise ligne + + // Ne plus utiliser + var $remise; + var $price; + + // From llx_product + var $ref; // Reference produit + var $libelle; // Label produit + var $product_desc; // Description produit + + var $localtax1_tx; // Local tax 1 + var $localtax2_tx; // Local tax 2 + var $localtax1_type; // Local tax 1 type + var $localtax2_type; // Local tax 2 type + var $total_localtax1; // Line total local tax 1 + var $total_localtax2; // Line total local tax 2 + + var $date_start; + var $date_end; + + var $skip_update_total; // Skip update price total for special lines + + /** + * Class line Contructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + $this->db= $db; + } + + /** + * Retrieve the propal line object + * + * @param int $rowid Propal line id + * @return int <0 if KO, >0 if OK + */ + function fetch($rowid) + { + $sql = 'SELECT pd.rowid, pd.fk_propal, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.tva_tx,'; + $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,'; + $sql.= ' pd.info_bits, pd.total_ht, pd.total_tva, pd.total_ttc, pd.fk_product_fournisseur_price as fk_fournprice, pd.buy_price_ht as pa_ht, pd.special_code, pd.rang,'; + $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,'; + $sql.= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,'; + $sql.= ' pd.date_start, pd.date_end, pd.product_type'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'propaldet as pd'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid'; + $sql.= ' WHERE pd.rowid = '.$rowid; + + $result = $this->db->query($sql); + if ($result) + { + $objp = $this->db->fetch_object($result); + + $this->rowid = $objp->rowid; + $this->fk_propal = $objp->fk_propal; + $this->fk_parent_line = $objp->fk_parent_line; + $this->label = $objp->custom_label; + $this->desc = $objp->description; + $this->qty = $objp->qty; + $this->price = $objp->price; // deprecated + $this->subprice = $objp->subprice; + $this->tva_tx = $objp->tva_tx; + $this->remise = $objp->remise; + $this->remise_percent = $objp->remise_percent; + $this->fk_remise_except = $objp->fk_remise_except; + $this->fk_product = $objp->fk_product; + $this->info_bits = $objp->info_bits; + + $this->total_ht = $objp->total_ht; + $this->total_tva = $objp->total_tva; + $this->total_ttc = $objp->total_ttc; + + $this->fk_fournprice = $objp->fk_fournprice; + + $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht); + $this->pa_ht = $marginInfos[0]; + $this->marge_tx = $marginInfos[1]; + $this->marque_tx = $marginInfos[2]; + + $this->special_code = $objp->special_code; + $this->product_type = $objp->product_type; + $this->rang = $objp->rang; + + $this->ref = $objp->product_ref; // deprecated + $this->product_ref = $objp->product_ref; + $this->libelle = $objp->product_label; // deprecated + $this->product_label = $objp->product_label; + $this->product_desc = $objp->product_desc; + + $this->date_start = $this->db->jdate($objp->date_start); + $this->date_end = $this->db->jdate($objp->date_end); + + $this->db->free($result); + } + else + { + dol_print_error($this->db); + } + } + + /** + * Insert object line propal in database + * + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >0 if OK + */ + function insert($notrigger=0) + { + global $conf,$langs,$user; + + $error=0; + + dol_syslog(get_class($this)."::insert rang=".$this->rang); + + // 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; + if (empty($this->localtax1_type)) $this->localtax1_type=0; + if (empty($this->localtax2_type)) $this->localtax2_type=0; + if (empty($this->total_localtax1)) $this->total_localtax1=0; + if (empty($this->total_localtax2)) $this->total_localtax2=0; + if (empty($this->rang)) $this->rang=0; + if (empty($this->remise)) $this->remise=0; + if (empty($this->remise_percent)) $this->remise_percent=0; + if (empty($this->info_bits)) $this->info_bits=0; + if (empty($this->special_code)) $this->special_code=0; + if (empty($this->fk_parent_line)) $this->fk_parent_line=0; + if (empty($this->fk_fournprice)) $this->fk_fournprice=0; + + if (empty($this->pa_ht)) $this->pa_ht=0; + + // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente + if ($this->pa_ht == 0) { + if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) + $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); + } + + // Check parameters + if ($this->product_type < 0) return -1; + + $this->db->begin(); + + // Insert line into database + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'propaldet'; + $sql.= ' (fk_propal, fk_parent_line, label, description, fk_product, product_type,'; + $sql.= ' fk_remise_except, qty, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,'; + $sql.= ' subprice, remise_percent, '; + $sql.= ' info_bits, '; + $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_product_fournisseur_price, buy_price_ht, special_code, rang,'; + $sql.= ' date_start, date_end)'; + $sql.= " VALUES (".$this->fk_propal.","; + $sql.= " ".($this->fk_parent_line>0?"'".$this->fk_parent_line."'":"null").","; + $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").","; + $sql.= " '".$this->db->escape($this->desc)."',"; + $sql.= " ".($this->fk_product?"'".$this->fk_product."'":"null").","; + $sql.= " '".$this->product_type."',"; + $sql.= " ".($this->fk_remise_except?"'".$this->fk_remise_except."'":"null").","; + $sql.= " ".price2num($this->qty).","; + $sql.= " ".price2num($this->tva_tx).","; + $sql.= " ".price2num($this->localtax1_tx).","; + $sql.= " ".price2num($this->localtax2_tx).","; + $sql.= " '".$this->localtax1_type."',"; + $sql.= " '".$this->localtax2_type."',"; + $sql.= " ".($this->subprice?price2num($this->subprice):"null").","; + $sql.= " ".price2num($this->remise_percent).","; + $sql.= " ".(isset($this->info_bits)?"'".$this->info_bits."'":"null").","; + $sql.= " ".price2num($this->total_ht).","; + $sql.= " ".price2num($this->total_tva).","; + $sql.= " ".price2num($this->total_localtax1).","; + $sql.= " ".price2num($this->total_localtax2).","; + $sql.= " ".price2num($this->total_ttc).","; + $sql.= " ".(!empty($this->fk_fournprice)?"'".$this->fk_fournprice."'":"null").","; + $sql.= " ".(isset($this->pa_ht)?"'".price2num($this->pa_ht)."'":"null").","; + $sql.= ' '.$this->special_code.','; + $sql.= ' '.$this->rang.','; + $sql.= " ".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null").','; + $sql.= " ".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null"); + $sql.= ')'; + + dol_syslog(get_class($this).'::insert', LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'propaldet'); + + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $this->id=$this->rowid; + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINEPROPAL_INSERT',$user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + } + // End call triggers + } + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -1; + } + } + + /** + * Delete line in database + * + * @return int <0 if ko, >0 if ok + */ + function delete() + { + global $conf,$langs,$user; + + $error=0; + $this->db->begin(); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."propaldet WHERE rowid = ".$this->rowid; + dol_syslog("PropaleLigne::delete", LOG_DEBUG); + if ($this->db->query($sql) ) + { + + // Remove extrafields + if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used + { + $this->id=$this->rowid; + $result=$this->deleteExtraFields(); + if ($result < 0) + { + $error++; + dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR); + } + } + + // Call trigger + $result=$this->call_trigger('LINEPROPAL_DELETE',$user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + } + // End call triggers + + $this->db->commit(); + + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -1; + } + } + + /** + * Update propal line object into DB + * + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if ko, >0 if ok + */ + function update($notrigger=0) + { + global $conf,$langs,$user; + + $error=0; + + // 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; + if (empty($this->total_localtax1)) $this->total_localtax1=0; + if (empty($this->total_localtax2)) $this->total_localtax2=0; + if (empty($this->localtax1_type)) $this->localtax1_type=0; + if (empty($this->localtax2_type)) $this->localtax2_type=0; + if (empty($this->marque_tx)) $this->marque_tx=0; + if (empty($this->marge_tx)) $this->marge_tx=0; + if (empty($this->price)) $this->price=0; // TODO A virer + if (empty($this->remise)) $this->remise=0; // TODO A virer + if (empty($this->remise_percent)) $this->remise_percent=0; + if (empty($this->info_bits)) $this->info_bits=0; + if (empty($this->special_code)) $this->special_code=0; + if (empty($this->fk_parent_line)) $this->fk_parent_line=0; + if (empty($this->fk_fournprice)) $this->fk_fournprice=0; + + if (empty($this->pa_ht)) $this->pa_ht=0; + + // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente + if ($this->pa_ht == 0) { + if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) + $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); + } + + $this->db->begin(); + + // Mise a jour ligne en base + $sql = "UPDATE ".MAIN_DB_PREFIX."propaldet SET"; + $sql.= " description='".$this->db->escape($this->desc)."'"; + $sql.= " , label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null"); + $sql.= " , product_type=".$this->product_type; + $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.= " , qty='".price2num($this->qty)."'"; + $sql.= " , subprice=".price2num($this->subprice).""; + $sql.= " , remise_percent=".price2num($this->remise_percent).""; + $sql.= " , price=".price2num($this->price).""; // TODO A virer + $sql.= " , remise=".price2num($this->remise).""; // TODO A virer + $sql.= " , info_bits='".$this->info_bits."'"; + if (empty($this->skip_update_total)) + { + $sql.= " , total_ht=".price2num($this->total_ht).""; + $sql.= " , total_tva=".price2num($this->total_tva).""; + $sql.= " , total_ttc=".price2num($this->total_ttc).""; + $sql.= " , total_localtax1=".price2num($this->total_localtax1).""; + $sql.= " , total_localtax2=".price2num($this->total_localtax2).""; + } + $sql.= " , fk_product_fournisseur_price=".(! empty($this->fk_fournprice)?"'".$this->fk_fournprice."'":"null"); + $sql.= " , buy_price_ht=".price2num($this->pa_ht); + if (strlen($this->special_code)) $sql.= " , special_code=".$this->special_code; + $sql.= " , fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null"); + if (! empty($this->rang)) $sql.= ", rang=".$this->rang; + $sql.= " , date_start=".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null"); + $sql.= " , date_end=".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null"); + $sql.= " WHERE rowid = ".$this->rowid; + + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $this->id=$this->rowid; + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINEPROPAL_UPDATE',$user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + } + // End call triggers + } + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -2; + } + } + + /** + * Update DB line fields total_xxx + * Used by migration + * + * @return int <0 if ko, >0 if ok + */ + function update_total() + { + $this->db->begin(); + + // Mise a jour ligne en base + $sql = "UPDATE ".MAIN_DB_PREFIX."propaldet SET"; + $sql.= " total_ht=".price2num($this->total_ht,'MT').""; + $sql.= ",total_tva=".price2num($this->total_tva,'MT').""; + $sql.= ",total_ttc=".price2num($this->total_ttc,'MT').""; + $sql.= " WHERE rowid = ".$this->rowid; + + dol_syslog("PropaleLigne::update_total", LOG_DEBUG); + + $resql=$this->db->query($sql); + if ($resql) + { + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -2; + } + } + +} + diff --git a/htdocs/comm/askpricesupplier/class/index.html b/htdocs/comm/askpricesupplier/class/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/comm/askpricesupplier/contact.php b/htdocs/comm/askpricesupplier/contact.php new file mode 100644 index 00000000000..6a0a1076e62 --- /dev/null +++ b/htdocs/comm/askpricesupplier/contact.php @@ -0,0 +1,223 @@ + + * Copyright (C) 2005-2009 Destailleur Laurent + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2011-2012 Philippe Grand + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/contact.php + * \ingroup propal + * \brief Onglet de gestion des contacts de propal + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; + +$langs->load("facture"); +$langs->load("orders"); +$langs->load("sendings"); +$langs->load("companies"); + +$id=GETPOST('id','int'); +$ref= GETPOST('ref','alpha'); +$lineid=GETPOST('lineid','int'); +$action=GETPOST('action','alpha'); + +// Security check +if ($user->societe_id) $socid=$user->societe_id; +$result = restrictedArea($user, 'propal', $id); + +$object = new Propal($db); + +// Load object +if ($id > 0 || ! empty($ref)) +{ + $ret=$object->fetch($id, $ref); + if ($ret == 0) + { + $langs->load("errors"); + setEventMessage($langs->trans('ErrorRecordNotFound'), 'errors'); + $error++; + } + else if ($ret < 0) + { + setEventMessage($object->error, 'errors'); + $error++; + } +} +if (! $error) +{ + $object->fetch_thirdparty(); +} +else +{ + header('Location: '.DOL_URL_ROOT.'/comm/propal/list.php'); + exit; +} + + +/* + * Ajout d'un nouveau contact + */ + +if ($action == 'addcontact' && $user->rights->propale->creer) +{ + if ($object->id > 0) + { + $contactid = (GETPOST('userid','int') ? GETPOST('userid','int') : GETPOST('contactid','int')); + $result = $object->add_contact($contactid, $_POST["type"], $_POST["source"]); + } + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else + { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $langs->load("errors"); + setEventMessage($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), 'errors'); + } + else + { + setEventMessage($object->error, 'errors'); + } + } +} + +// Bascule du statut d'un contact +else if ($action == 'swapstatut' && $user->rights->propale->creer) +{ + if ($object->id > 0) + { + $result=$object->swapContactStatus(GETPOST('ligne')); + } +} + +// Efface un contact +else if ($action == 'deletecontact' && $user->rights->propale->creer) +{ + $result = $object->delete_contact($lineid); + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else + { + dol_print_error($db); + } +} + +else if ($action == 'setaddress' && $user->rights->propale->creer) +{ + $result=$object->setDeliveryAddress($_POST['fk_address']); + if ($result < 0) dol_print_error($db,$object->error); +} + + +/* + * View + */ + +llxHeader('',$langs->trans('Proposal'),'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos'); + +$form = new Form($db); +$formcompany= new FormCompany($db); +$formother = new FormOther($db); + +if ($object->id > 0) +{ + $head = propal_prepare_head($object); + dol_fiche_head($head, 'contact', $langs->trans("Proposal"), 0, 'propal'); + + /* + * Propal synthese pour rappel + */ + print ''; + + $linkback=''.$langs->trans("BackToList").''; + + // Ref + print ''; + + // Ref client + print ''; + print ''; + + // Customer + print ""; + print ''; + + // Delivery address + if (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT)) + { + print ''; + } + + print "
'.$langs->trans('Ref').''; + print $form->showrefnav($object,'ref',$linkback,1,'ref','ref',''); + print '
'; + print ''; + print '
'; + print $langs->trans('RefCustomer').''; + print '
'; + print '
'; + print $object->ref_client; + print '
".$langs->trans("Company")."'.$object->client->getNomUrl(1).'
'; + print ''; + + if ($action != 'editdelivery_address' && ! empty($object->brouillon)) + print ''; + print '
'; + print $langs->trans('DeliveryAddress'); + print 'socid.'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetDeliveryAddress'),1).'
'; + print '
'; + + if ($action == 'editdelivery_address') + { + $formother->form_address($_SERVER['PHP_SELF'].'?id='.$object->id,$object->fk_delivery_address,$object->socid,'fk_address','propal',$object->id); + } + else + { + $formother->form_address($_SERVER['PHP_SELF'].'?id='.$object->id,$object->fk_delivery_address,$object->socid,'none','propal',$object->id); + } + print '
"; + + print ''; + + print '
'; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); + foreach($dirtpls as $reldir) + { + $res=@include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) break; + } +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/comm/askpricesupplier/document.php b/htdocs/comm/askpricesupplier/document.php new file mode 100644 index 00000000000..d224c20bc97 --- /dev/null +++ b/htdocs/comm/askpricesupplier/document.php @@ -0,0 +1,144 @@ + + * Copyright (C) 2004-2009 Laurent Destailleur + * Copyright (C) 2005 Marc Barilley / Ocebo + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2013 Cédric Salvador + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/document.php + * \ingroup propal + * \brief Management page of documents attached to a business proposal + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + +$langs->load('compta'); +$langs->load('other'); + +$action = GETPOST('action','alpha'); +$confirm = GETPOST('confirm','alpha'); +$id = GETPOST('id','int'); +$ref = GETPOST('ref','alpha'); + +// Security check +$socid=''; +if (! empty($user->societe_id)) +{ + $action=''; + $socid = $user->societe_id; +} +$result = restrictedArea($user, 'propal', $id); + +// Get parameters +$sortfield = GETPOST("sortfield",'alpha'); +$sortorder = GETPOST("sortorder",'alpha'); +$page = GETPOST("page",'int'); +if ($page == -1) { $page = 0; } +$offset = $conf->liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (! $sortorder) $sortorder="ASC"; +if (! $sortfield) $sortfield="name"; + +$object = new Propal($db); +$object->fetch($id,$ref); +if ($object->id > 0) +{ + $object->fetch_thirdparty(); + $upload_dir = $conf->propal->dir_output.'/'.dol_sanitizeFileName($object->ref); + include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_pre_headers.tpl.php'; +} + +/* + * Actions + */ + + + +/* + * View + */ + +llxHeader('',$langs->trans('Proposal'),'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos'); + +$form = new Form($db); + +if ($object->id > 0) +{ + $upload_dir = $conf->propal->dir_output.'/'.dol_sanitizeFileName($object->ref); + + $head = propal_prepare_head($object); + dol_fiche_head($head, 'document', $langs->trans('Proposal'), 0, 'propal'); + + // Construit liste des fichiers + $filearray=dol_dir_list($upload_dir,"files",0,'','(\.meta|_preview\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1); + $totalsize=0; + foreach($filearray as $key => $file) + { + $totalsize+=$file['size']; + } + + + print ''; + + $linkback=''.$langs->trans("BackToList").''; + + // Ref + print ''; + + // Ref client + print ''; + print ''; + + // Customer + print ""; + print ''; + + print ''; + print ''; + + print '
'.$langs->trans('Ref').''; + print $form->showrefnav($object,'ref',$linkback,1,'ref','ref',''); + print '
'; + print ''; + print '
'; + print $langs->trans('RefCustomer').''; + print '
'; + print '
'; + print $object->ref_client; + print '
".$langs->trans("Company")."'.$object->thirdparty->getNomUrl(1).'
'.$langs->trans("NbOfAttachedFiles").''.count($filearray).'
'.$langs->trans("TotalSizeOfAttachedFiles").''.$totalsize.' '.$langs->trans("bytes").'
'; + + print ''; + + $modulepart = 'propal'; + $permission = $user->rights->propal->creer; + $param = '&id=' . $object->id; + include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_post_headers.tpl.php'; +} +else +{ + print $langs->trans("ErrorUnknown"); +} + +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/index.php b/htdocs/comm/askpricesupplier/index.php new file mode 100644 index 00000000000..a0e8a3409ab --- /dev/null +++ b/htdocs/comm/askpricesupplier/index.php @@ -0,0 +1,528 @@ + + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/index.php + * \ingroup propal + * \brief Home page of proposal area + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT .'/comm/propal/class/propal.class.php'; + +$langs->load("propal"); +$langs->load("companies"); + +// Security check +$socid=GETPOST('socid','int'); +if (isset($user->societe_id) && $user->societe_id > 0) +{ + $action = ''; + $socid = $user->societe_id; +} +$result = restrictedArea($user, 'propal'); + + +/* + * View + */ +$now=dol_now(); +$propalstatic=new Propal($db); +$companystatic=new Societe($db); +$form = new Form($db); +$formfile = new FormFile($db); +$help_url="EN:Module_Commercial_Proposals|FR:Module_Propositions_commerciales|ES:Módulo_Presupuestos"; + +llxHeader("",$langs->trans("ProspectionArea"),$help_url); + +print_fiche_titre($langs->trans("ProspectionArea")); + +//print ''; +//print '
'; +print '
'; + + +/* + * Search form + */ +$var=false; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "
'.$langs->trans("SearchPropal").'
'; +print $langs->trans("Ref").':
'.$langs->trans("Other").':

\n"; + + +/* + * Statistics + */ + +$sql = "SELECT count(p.rowid), p.fk_statut"; +$sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; +$sql.= ", ".MAIN_DB_PREFIX."propal as p"; +if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +$sql.= " WHERE p.fk_soc = s.rowid"; +$sql.= " AND p.entity = ".$conf->entity; +if ($user->societe_id) $sql.=' AND p.fk_soc = '.$user->societe_id; +if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; +$sql.= " AND p.fk_statut IN (0,1,2,3,4)"; +$sql.= " GROUP BY p.fk_statut"; +$resql = $db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + $i = 0; + + $total=0; + $totalinprocess=0; + $dataseries=array(); + $vals=array(); + // -1=Canceled, 0=Draft, 1=Validated, (2=Accepted/On process not managed for customer orders), 3=Closed (Sent/Received, billed or not) + while ($i < $num) + { + $row = $db->fetch_row($resql); + if ($row) + { + //if ($row[1]!=-1 && ($row[1]!=3 || $row[2]!=1)) + { + $vals[$row[1]]=$row[0]; + $totalinprocess+=$row[0]; + } + $total+=$row[0]; + } + $i++; + } + $db->free($resql); + + print ''; + print ''."\n"; + $var=true; + $listofstatus=array(0,1,2,3,4); + foreach ($listofstatus as $status) + { + $dataseries[]=array('label'=>$propalstatic->LibStatut($status,1),'data'=>(isset($vals[$status])?(int) $vals[$status]:0)); + if (! $conf->use_javascript_ajax) + { + $var=!$var; + print ""; + print ''; + print ''; + print "\n"; + } + } + if ($conf->use_javascript_ajax) + { + print ''; + } + //if ($totalinprocess != $total) + //print ''; + print ''; + print "
'.$langs->trans("Statistics").' - '.$langs->trans("Proposals").'
'.$propalstatic->LibStatut($status,0).''.(isset($vals[$status])?$vals[$status]:0).'
'; + $data=array('series'=>$dataseries); + dol_print_graph('stats',300,180,$data,1,'pie',1); + print '
'.$langs->trans("Total").' ('.$langs->trans("CustomersOrdersRunning").')'.$totalinprocess.'
'.$langs->trans("Total").''.$total.'

"; +} +else +{ + dol_print_error($db); +} + + +/* + * Draft proposals + */ +if (! empty($conf->propal->enabled)) +{ + $sql = "SELECT c.rowid, c.ref, s.nom as socname, s.rowid as socid, s.canvas, s.client"; + $sql.= " FROM ".MAIN_DB_PREFIX."propal as c"; + $sql.= ", ".MAIN_DB_PREFIX."societe as s"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.fk_soc = s.rowid"; + $sql.= " AND c.entity = ".$conf->entity; + $sql.= " AND c.fk_statut = 0"; + if ($socid) $sql.= " AND c.fk_soc = ".$socid; + if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + + $resql=$db->query($sql); + if ($resql) + { + print ''; + print ''; + print ''; + $langs->load("propal"); + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + $var = True; + while ($i < $num) + { + $var=!$var; + $obj = $db->fetch_object($resql); + print ""; + + $propalstatic->id=$obj->rowid; + $propalstatic->ref=$obj->ref; + print ''; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->socname; + $companystatic->client=$obj->client; + $companystatic->canvas=$obj->canvas; + print ''; + + print ''; + $i++; + } + } + print "
'.$langs->trans("DraftPropals").'
'.$propalstatic->getNomUrl(1).''.$companystatic->getNomUrl(1,'customer',24).'

"; + } +} + + +//print '
'; +print '
'; + + +$max=5; + +/* + * Last modified proposals + */ + +$sql = "SELECT c.rowid, c.ref, c.fk_statut, s.nom as socname, s.rowid as socid, s.canvas, s.client,"; +$sql.= " date_cloture as datec"; +$sql.= " FROM ".MAIN_DB_PREFIX."propal as c"; +$sql.= ", ".MAIN_DB_PREFIX."societe as s"; +if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +$sql.= " WHERE c.fk_soc = s.rowid"; +$sql.= " AND c.entity = ".$conf->entity; +//$sql.= " AND c.fk_statut > 2"; +if ($socid) $sql .= " AND c.fk_soc = ".$socid; +if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; +$sql.= " ORDER BY c.tms DESC"; +$sql.= $db->plimit($max, 0); + +$resql=$db->query($sql); +if ($resql) +{ + print ''; + print ''; + print ''; + + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + $var = True; + while ($i < $num) + { + $var=!$var; + $obj = $db->fetch_object($resql); + + print ""; + print ''; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->socname; + $companystatic->client=$obj->client; + $companystatic->canvas=$obj->canvas; + print ''; + + print ''; + print ''; + print ''; + $i++; + } + } + print "
'.$langs->trans("LastModifiedProposals",$max).'
'; + + $propalstatic->id=$obj->rowid; + $propalstatic->ref=$obj->ref; + + print ''; + print ''; + + print ''; + + print '
'; + print $propalstatic->getNomUrl(1); + print ''; + print ' '; + print ''; + $filename=dol_sanitizeFileName($obj->ref); + $filedir=$conf->propal->dir_output . '/' . dol_sanitizeFileName($obj->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->rowid; + print $formfile->getDocumentsLink($propalstatic->element, $filename, $filedir); + print '
'; + + print '
'.$companystatic->getNomUrl(1,'customer').''.dol_print_date($db->jdate($obj->datec),'day').''.$propalstatic->LibStatut($obj->fk_statut,5).'

"; +} +else dol_print_error($db); + + +/* + * Opened proposals + */ +if (! empty($conf->propal->enabled) && $user->rights->propale->lire) +{ + $langs->load("propal"); + + $now=dol_now(); + + $sql = "SELECT s.nom as socname, s.rowid as socid, s.canvas, s.client, p.rowid as propalid, p.total as total_ttc, p.total_ht, p.ref, p.fk_statut, p.datep as dp, p.fin_validite as dfv"; + $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; + $sql.= ", ".MAIN_DB_PREFIX."propal as p"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE p.fk_soc = s.rowid"; + $sql.= " AND p.entity = ".$conf->entity; + $sql.= " AND p.fk_statut = 1"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($socid) $sql.= " AND s.rowid = ".$socid; + $sql.= " ORDER BY p.rowid DESC"; + + $result=$db->query($sql); + if ($result) + { + $total = 0; + $num = $db->num_rows($result); + $i = 0; + if ($num > 0) + { + $var=true; + + print ''; + print ''; + + $nbofloop=min($num, (empty($conf->global->MAIN_MAXLIST_OVERLOAD)?500:$conf->global->MAIN_MAXLIST_OVERLOAD)); + while ($i < $nbofloop) + { + $obj = $db->fetch_object($result); + $var=!$var; + print ''; + + // Ref + print '"; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->socname; + $companystatic->client=$obj->client; + $companystatic->canvas=$obj->canvas; + print ''."\n"; + + print ''."\n"; + print ''; + print ''."\n"; + print ''."\n"; + $i++; + $total += $obj->total_ttc; + } + if ($num > $nbofloop) + { + print '"; + } + else if ($total>0) + { + print '"; + } + print "
'.$langs->trans("ProposalsOpened").' '.$num.'
'; + + $propalstatic->id=$obj->propalid; + $propalstatic->ref=$obj->ref; + + print ''; + print ''; + print ''; + print '
'; + print $propalstatic->getNomUrl(1); + print ''; + if ($db->jdate($obj->dfv) < ($now - $conf->propal->cloture->warning_delay)) print img_warning($langs->trans("Late")); + print ''; + $filename=dol_sanitizeFileName($obj->ref); + $filedir=$conf->propal->dir_output . '/' . dol_sanitizeFileName($obj->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->propalid; + print $formfile->getDocumentsLink($propalstatic->element, $filename, $filedir); + print '
'; + + print "
'.$companystatic->getNomUrl(1,'customer',44).''; + print dol_print_date($db->jdate($obj->dp),'day').''.price($obj->total_ttc).''.$propalstatic->LibStatut($obj->fk_statut,3).'
'.$langs->trans("XMoreLines", ($num - $nbofloop))."
'.$langs->trans("Total")."".price($total)." 

"; + } + } + else + { + dol_print_error($db); + } +} + +/* + * Proposals to process + */ +/* +if (! empty($conf->propal->enabled)) +{ + $sql = "SELECT c.rowid, c.ref, c.fk_statut, s.nom as name, s.rowid as socid"; + $sql.=" FROM ".MAIN_DB_PREFIX."propal as c"; + $sql.= ", ".MAIN_DB_PREFIX."societe as s"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.fk_soc = s.rowid"; + $sql.= " AND c.entity = ".$conf->entity; + $sql.= " AND c.fk_statut = 1"; + if ($socid) $sql.= " AND c.fk_soc = ".$socid; + if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + $sql.= " ORDER BY c.rowid DESC"; + + $resql=$db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + + print ''; + print ''; + print ''; + + if ($num) + { + $i = 0; + $var = True; + while ($i < $num) + { + $var=!$var; + $obj = $db->fetch_object($resql); + print ""; + print ''; + + print ''; + + print ''; + + print ''; + $i++; + } + } + + print "
'.$langs->trans("ProposalsToProcess").' '.$num.'
'; + + $propalstatic->id=$obj->rowid; + $propalstatic->ref=$obj->ref; + + print ''; + print ''; + + print ''; + + print '
'; + print $propalstatic->getNomUrl(1); + print ''; + print ' '; + print ''; + $filename=dol_sanitizeFileName($obj->ref); + $filedir=$conf->commande->dir_output . '/' . dol_sanitizeFileName($obj->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->rowid; + print $formfile->getDocumentsLink($propalstatic->element, $filename, $filedir); + print '
'; + + print '
'.img_object($langs->trans("ShowCompany"),"company").' '.dol_trunc($obj->name,24).''.$propalstatic->LibStatut($obj->fk_statut,$obj->facture,5).'

"; + } + else dol_print_error($db); +} +*/ + +/* + * Proposal that are in a shipping process + */ +/*if (! empty($conf->propal->enabled)) +{ + $sql = "SELECT c.rowid, c.ref, c.fk_statut, c.facture, s.nom as name, s.rowid as socid"; + $sql.= " FROM ".MAIN_DB_PREFIX."commande as c"; + $sql.= ", ".MAIN_DB_PREFIX."societe as s"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.fk_soc = s.rowid"; + $sql.= " AND c.entity = ".$conf->entity; + $sql.= " AND c.fk_statut = 2 "; + if ($socid) $sql.= " AND c.fk_soc = ".$socid; + if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + $sql.= " ORDER BY c.rowid DESC"; + + $resql=$db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + + print ''; + print ''; + print ''; + + if ($num) + { + $i = 0; + $var = True; + while ($i < $num) + { + $var=!$var; + $obj = $db->fetch_object($resql); + print ""; + print ''; + + print ''; + + print ''; + + print ''; + $i++; + } + } + print "
'.$langs->trans("OnProcessOrders").' '.$num.'
'; + + $propalstatic->id=$obj->rowid; + $propalstatic->ref=$obj->ref; + + print ''; + print ''; + + print ''; + + print '
'; + print $propalstatic->getNomUrl(1); + print ''; + print ' '; + print ''; + $filename=dol_sanitizeFileName($obj->ref); + $filedir=$conf->commande->dir_output . '/' . dol_sanitizeFileName($obj->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->rowid; + print $formfile->getDocumentsLink($propalstatic->element, $filename, $filedir); + print '
'; + + print '
'.img_object($langs->trans("ShowCompany"),"company").' '.$obj->name.''.$propalstatic->LibStatut($obj->fk_statut,$obj->facture,5).'

"; + } + else dol_print_error($db); +} +*/ + +//print '
'; +print ''; + + +llxFooter(); + +$db->close(); diff --git a/htdocs/comm/askpricesupplier/info.php b/htdocs/comm/askpricesupplier/info.php new file mode 100644 index 00000000000..d3a3899537b --- /dev/null +++ b/htdocs/comm/askpricesupplier/info.php @@ -0,0 +1,65 @@ + + * Copyright (C) 2004-2006 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/info.php + * \ingroup propal + * \brief Page d'affichage des infos d'une proposition commerciale + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; + +$langs->load('propal'); +$langs->load('compta'); + +$id=GETPOST('id','int'); +$socid=GETPOST('socid','int'); + +// Security check +if (! empty($user->societe_id)) $socid=$user->societe_id; +$result = restrictedArea($user, 'propal', $id); + + +/* + * View + */ + +llxHeader('',$langs->trans('Proposal'),'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos'); + +$object = new Propal($db); +$object->fetch($id); +$object->fetch_thirdparty(); + +$head = propal_prepare_head($object); +dol_fiche_head($head, 'info', $langs->trans('Proposal'), 0, 'propal'); + +$object->info($object->id); + +print '
'; +dol_print_object_info($object); +print '
'; + +print ''; + + +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/list.php b/htdocs/comm/askpricesupplier/list.php new file mode 100644 index 00000000000..c28128e81c5 --- /dev/null +++ b/htdocs/comm/askpricesupplier/list.php @@ -0,0 +1,464 @@ + + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2004 Eric Seigne + * Copyright (C) 2005 Marc Barilley / Ocebo + * Copyright (C) 2005-2013 Regis Houssin + * Copyright (C) 2006 Andre Cianfarani + * Copyright (C) 2010-2011 Juanjo Menent + * Copyright (C) 2010-2011 Philippe Grand + * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2013 Cédric Salvador +* + * 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 . + */ + +/** + * \file htdocs/comm/propal/list.php + * \ingroup propal + * \brief Page of commercial proposals card and list + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formpropal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +if (! empty($conf->projet->enabled)) + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + +$langs->load('companies'); +$langs->load('propal'); +$langs->load('compta'); +$langs->load('bills'); +$langs->load('orders'); +$langs->load('products'); + +$socid=GETPOST('socid','int'); + +$search_user=GETPOST('search_user','int'); +$search_sale=GETPOST('search_sale','int'); +$search_ref=GETPOST('sf_ref')?GETPOST('sf_ref','alpha'):GETPOST('search_ref','alpha'); +$search_refcustomer=GETPOST('search_refcustomer','alpha'); +$search_societe=GETPOST('search_societe','alpha'); +$search_montant_ht=GETPOST('search_montant_ht','alpha'); +$search_author=GETPOST('search_author','alpha'); +$search_town=GETPOST('search_town','alpha'); +$viewstatut=$db->escape(GETPOST('viewstatut')); +$object_statut=$db->escape(GETPOST('propal_statut')); + +$sall=GETPOST("sall"); +$mesg=(GETPOST("msg") ? GETPOST("msg") : GETPOST("mesg")); +$year=GETPOST("year"); +$month=GETPOST("month"); + +// Nombre de ligne pour choix de produit/service predefinis +$NBLINES=4; + +// Security check +$module='propal'; +$dbtable=''; +$objectid=''; +if (! empty($user->societe_id)) $socid=$user->societe_id; +if (! empty($socid)) +{ + $objectid=$socid; + $module='societe'; + $dbtable='&societe'; +} +$result = restrictedArea($user, $module, $objectid, $dbtable); + +if (GETPOST("button_removefilter") || GETPOST("button_removefilter_x")) // Both tests are required to be compatible with all browsers +{ + $search_categ=''; + $search_user=''; + $search_sale=''; + $search_ref=''; + $search_refcustomer=''; + $search_societe=''; + $search_montant_ht=''; + $search_author=''; + $search_town=''; + $year=''; + $month=''; + $viewstatut=''; + $object_statut=''; +} + +if($object_statut != '') +$viewstatut=$object_statut; + + +// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array +$hookmanager->initHooks(array('propallist')); + + + +/* + * Actions + */ + + +$parameters=array('socid'=>$socid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + + +/* + * View + */ + +llxHeader('',$langs->trans('Proposal'),'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos'); + +$form = new Form($db); +$formother = new FormOther($db); +$formfile = new FormFile($db); +$formpropal = new FormPropal($db); +$companystatic=new Societe($db); + +$now=dol_now(); + +$sortfield = GETPOST("sortfield",'alpha'); +$sortorder = GETPOST("sortorder",'alpha'); +$page = GETPOST("page",'int'); +if ($page == -1) { $page = 0; } +$offset = $conf->liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +if (! $sortfield) $sortfield='p.datep'; +if (! $sortorder) $sortorder='DESC'; +$limit = $conf->liste_limit; + + +$sql = 'SELECT s.rowid, s.nom as name, s.town, s.client, s.code_client,'; +$sql.= ' p.rowid as propalid, p.note_private, p.total_ht, p.ref, p.ref_client, p.fk_statut, p.fk_user_author, p.datep as dp, p.fin_validite as dfv,'; +if (! $user->rights->societe->client->voir && ! $socid) $sql .= " sc.fk_soc, sc.fk_user,"; +$sql.= ' u.login'; +$sql.= ' FROM '.MAIN_DB_PREFIX.'societe as s, '.MAIN_DB_PREFIX.'propal as p'; +if ($sall) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'propaldet as pd ON p.rowid=pd.fk_propal'; +$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'user as u ON p.fk_user_author = u.rowid'; +// We'll need this table joined to the select in order to filter by sale +if ($search_sale > 0 || (! $user->rights->societe->client->voir && ! $socid)) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +if ($search_user > 0) +{ + $sql.=", ".MAIN_DB_PREFIX."element_contact as c"; + $sql.=", ".MAIN_DB_PREFIX."c_type_contact as tc"; +} +$sql.= ' WHERE p.fk_soc = s.rowid'; +$sql.= ' AND p.entity = '.$conf->entity; +if (! $user->rights->societe->client->voir && ! $socid) //restriction +{ + $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; +} +if ($search_town) {//restriction + $sql .= natural_search('s.town', $search_town); +} +if ($search_ref) { + $sql .= natural_search('p.ref', $search_ref); +} +if ($search_refcustomer) { + $sql .= natural_search('p.ref_client', $search_refcustomer); +} +if ($search_societe) { + $sql .= natural_search('s.nom', $search_societe); +} +if ($search_author) +{ + $sql.= " AND u.login LIKE '%".$db->escape(trim($search_author))."%'"; +} +if ($search_montant_ht) +{ + $sql.= " AND p.total_ht='".$db->escape(price2num(trim($search_montant_ht)))."'"; +} +if ($sall) { + $sql .= natural_search(array('s.nom', 'p.note_private', 'p.note_public', 'pd.description'), $sall); +} +if ($socid) $sql.= ' AND s.rowid = '.$socid; +if ($viewstatut <> '') +{ + $sql.= ' AND p.fk_statut IN ('.$viewstatut.')'; +} +if ($month > 0) +{ + if ($year > 0 && empty($day)) + $sql.= " AND p.datep BETWEEN '".$db->idate(dol_get_first_day($year,$month,false))."' AND '".$db->idate(dol_get_last_day($year,$month,false))."'"; + else if ($year > 0 && ! empty($day)) + $sql.= " AND p.datep BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $month, $day, $year))."' AND '".$db->idate(dol_mktime(23, 59, 59, $month, $day, $year))."'"; + else + $sql.= " AND date_format(p.datep, '%m') = '".$month."'"; +} +else if ($year > 0) +{ + $sql.= " AND p.datep BETWEEN '".$db->idate(dol_get_first_day($year,1,false))."' AND '".$db->idate(dol_get_last_day($year,12,false))."'"; +} +if ($search_sale > 0) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$search_sale; +if ($search_user > 0) +{ + $sql.= " AND c.fk_c_type_contact = tc.rowid AND tc.element='propal' AND tc.source='internal' AND c.element_id = p.rowid AND c.fk_socpeople = ".$search_user; +} + + +$sql.= ' ORDER BY '.$sortfield.' '.$sortorder.', p.ref DESC'; + +$nbtotalofrecords = 0; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) +{ + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); +} + + +$sql.= $db->plimit($limit + 1,$offset); +$result=$db->query($sql); + +if ($result) +{ + $objectstatic=new Propal($db); + $userstatic=new User($db); + $num = $db->num_rows($result); + + if ($socid) + { + $soc = new Societe($db); + $soc->fetch($socid); + } + + $param='&socid='.$socid.'&viewstatut='.$viewstatut; + if ($month) $param.='&month='.$month; + if ($year) $param.='&year='.$year; + if ($search_ref) $param.='&search_ref=' .$search_ref; + if ($search_refcustomer) $param.='&search_refcustomer=' .$search_refcustomer; + if ($search_societe) $param.='&search_societe=' .$search_societe; + if ($search_user > 0) $param.='&search_user='.$search_user; + if ($search_sale > 0) $param.='&search_sale='.$search_sale; + if ($search_montant_ht) $param.='&search_montant_ht='.$search_montant_ht; + if ($search_author) $param.='&search_author='.$search_author; + if ($search_town) $param.='&search_town='.$search_town; + print_barre_liste($langs->trans('ListOfProposals').' '.($socid?'- '.$soc->name:''), $page, $_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,'',$num,$nbtotalofrecords); + + // Lignes des champs de filtre + print '
'; + + $i = 0; + print ''; + + $moreforfilter=''; + + // If the user can view prospects other than his' + if ($user->rights->societe->client->voir || $socid) + { + $langs->load("commercial"); + $moreforfilter.=$langs->trans('ThirdPartiesOfSaleRepresentative'). ': '; + $moreforfilter.=$formother->select_salesrepresentatives($search_sale,'search_sale',$user); + $moreforfilter.='       '; + } + // If the user can view prospects other than his' + if ($user->rights->societe->client->voir || $socid) + { + $moreforfilter.=$langs->trans('LinkedToSpecificUsers'). ': '; + $moreforfilter.=$form->select_dolusers($search_user,'search_user',1); + } + if (! empty($moreforfilter)) + { + print ''; + print ''; + } + + print ''; + print_liste_field_titre($langs->trans('Ref'),$_SERVER["PHP_SELF"],'p.ref','',$param,'',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('RefCustomer'),$_SERVER["PHP_SELF"],'p.ref_client','',$param,'',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Company'),$_SERVER["PHP_SELF"],'s.nom','',$param,'',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Town'),$_SERVER["PHP_SELF"],'s.town','',$param,'',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Date'),$_SERVER["PHP_SELF"],'p.datep','',$param, 'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('DateEndPropalShort'),$_SERVER["PHP_SELF"],'dfv','',$param, 'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('AmountHT'),$_SERVER["PHP_SELF"],'p.total_ht','',$param, 'align="right"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Author'),$_SERVER["PHP_SELF"],'u.login','',$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Status'),$_SERVER["PHP_SELF"],'p.fk_statut','',$param,'align="right"',$sortfield,$sortorder); + print_liste_field_titre(''); + print "\n"; + + print ''; + print ''; + print ''; + print ''; + print ''; + // Date + print ''; + print ''; + // Amount + print ''; + // Author + print ''; + print ''; + + print ''; + + print "\n"; + + $var=true; + $total=0; + $subtotal=0; + + while ($i < min($num,$limit)) + { + $objp = $db->fetch_object($result); + $now = dol_now(); + $var=!$var; + print ''; + print '\n"; + + // Customer ref + print ''; + + $url = DOL_URL_ROOT.'/comm/card.php?socid='.$objp->rowid; + + // Company + $companystatic->id=$objp->rowid; + $companystatic->name=$objp->name; + $companystatic->client=$objp->client; + $companystatic->code_client=$objp->code_client; + print ''; + + // Town + print ''; + + // Date proposal + print '\n"; + + // Date end validity + if ($objp->dfv) + { + print ''; + } + else + { + print ''; + } + + print '\n"; + + $userstatic->id=$objp->fk_user_author; + $userstatic->login=$objp->login; + print '\n"; + + print '\n"; + + print ''; + + print "\n"; + + $total += $objp->total_ht; + $subtotal += $objp->total_ht; + + $i++; + } + + if ($total>0) + { + if($num<$limit){ + $var=!$var; + print ''; + print ''; + print ''; + } + else + { + $var=!$var; + print ''; + print ''; + print ''; + } + + } + + print '
'; + print $moreforfilter; + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + //print $langs->trans('Month').': '; + print ''; + //print ' '.$langs->trans('Year').': '; + $syear = $year; + $formother->select_year($syear,'year',1, 20, 5); + print ' '; + print ''; + print ''; + print ''; + print ''; + $formpropal->selectProposalStatus($viewstatut,1); + print ''; + print ''; + print ''; + print '
'; + + $objectstatic->id=$objp->propalid; + $objectstatic->ref=$objp->ref; + + print ''; + print ''; + + print ''; + + // Ref + print '
'; + print $objectstatic->getNomUrl(1); + print ''; + if ($objp->fk_statut == 1 && $db->jdate($objp->dfv) < ($now - $conf->propal->cloture->warning_delay)) print img_warning($langs->trans("Late")); + if (! empty($objp->note_private)) + { + print ' '; + print ''.img_picto($langs->trans("ViewPrivateNote"),'object_generic').''; + print ''; + } + print ''; + $filename=dol_sanitizeFileName($objp->ref); + $filedir=$conf->propal->dir_output . '/' . dol_sanitizeFileName($objp->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$objp->propalid; + print $formfile->getDocumentsLink($objectstatic->element, $filename, $filedir); + print '
'; + + print "
'; + print $objp->ref_client; + print ''; + print $companystatic->getNomUrl(1,'customer'); + print ''; + print $objp->town; + print ''; + print dol_print_date($db->jdate($objp->dp), 'day'); + print "'.dol_print_date($db->jdate($objp->dfv),'day'); + print ' '.price($objp->total_ht)."'; + if ($userstatic->id) print $userstatic->getLoginUrl(1); + else print ' '; + print "'.$objectstatic->LibStatut($objp->fk_statut,5)." 
'.$langs->trans("TotalHT").''.price($total).'
'.$langs->trans("TotalHTforthispage").''.price($total).'
'; + + print '
'; + + $db->free($result); +} +else +{ + dol_print_error($db); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/note.php b/htdocs/comm/askpricesupplier/note.php new file mode 100644 index 00000000000..9292684d06f --- /dev/null +++ b/htdocs/comm/askpricesupplier/note.php @@ -0,0 +1,151 @@ + + * Copyright (C) 2004-2012 Laurent Destailleur + * Copyright (C) 2004 Eric Seigne + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2013 Florian Henry + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/note.php + * \ingroup propal + * \brief Fiche d'information sur une proposition commerciale + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; + +$langs->load('propal'); +$langs->load('compta'); +$langs->load('bills'); + +$id = GETPOST('id','int'); +$ref=GETPOST('ref','alpha'); +$action=GETPOST('action','alpha'); + +// Security check +if ($user->societe_id) $socid=$user->societe_id; +$result = restrictedArea($user, 'propale', $id, 'propal'); + +$object = new Propal($db); + + + +/******************************************************************************/ +/* Actions */ +/******************************************************************************/ + +$permissionnote=$user->rights->propale->creer; // Used by the include of actions_setnotes.inc.php + +include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once + + + +/******************************************************************************/ +/* Affichage fiche */ +/******************************************************************************/ + +llxHeader('',$langs->trans('Proposal'),'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos'); + +$form = new Form($db); + +if ($id > 0 || ! empty($ref)) +{ + if ($mesg) print $mesg; + + $now=dol_now(); + + if ($object->fetch($id, $ref)) + { + $societe = new Societe($db); + if ( $societe->fetch($object->socid) ) + { + $head = propal_prepare_head($object); + dol_fiche_head($head, 'note', $langs->trans('Proposal'), 0, 'propal'); + + print ''; + + $linkback = ''.$langs->trans('BackToList').''; + + // Ref + print ''; + + // Ref client + print ''; + print ''; + + // Customer + if ( is_null($object->client) ) + $object->fetch_thirdparty(); + print ""; + print ''; + + // Ligne info remises tiers + print ''; + + // Date + print ''; + print ''; + + // Date fin propal + print ''; + print ''; + print ''; + + print "
'.$langs->trans('Ref').''; + print $form->showrefnav($object,'ref',$linkback,1,'ref','ref',''); + print '
'; + print ''; + print '
'; + print $langs->trans('RefCustomer').''; + print '
'; + print '
'; + print $object->ref_client; + print '
".$langs->trans("Company")."'.$object->client->getNomUrl(1).'
'.$langs->trans('Discounts').''; + if ($societe->remise_percent) print $langs->trans("CompanyHasRelativeDiscount",$societe->remise_percent); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + $absolute_discount=$societe->getAvailableDiscounts(); + print '. '; + if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->trans("Currency".$conf->currency)); + else print $langs->trans("CompanyHasNoAbsoluteDiscount"); + print '.'; + print '
'.$langs->trans('Date').''; + print dol_print_date($object->date,'daytext'); + print '
'.$langs->trans('DateEndPropal').''; + if ($object->fin_validite) + { + print dol_print_date($object->fin_validite,'daytext'); + if ($object->statut == 1 && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) print img_warning($langs->trans("Late")); + } + else + { + print $langs->trans("Unknown"); + } + print '
"; + + print '
'; + + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + dol_fiche_end(); + } + } +} + + +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/tpl/index.html b/htdocs/comm/askpricesupplier/tpl/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/comm/askpricesupplier/tpl/linkedobjectblock.tpl.php b/htdocs/comm/askpricesupplier/tpl/linkedobjectblock.tpl.php new file mode 100644 index 00000000000..cb920afd5fc --- /dev/null +++ b/htdocs/comm/askpricesupplier/tpl/linkedobjectblock.tpl.php @@ -0,0 +1,79 @@ + + * Copyright (C) 2013 Juanjo Menent + * Copyright (C) 2014 Marcos García + * + * 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 . + */ + +/** + * \file htdocs/comm/propal/tpl/linkedobjectblock.tpl.php + * \ingroup propal + * \brief Template to show objects linked to proposals + */ +?> + + + +'; +print_titre($langs->trans('RelatedCommercialProposals')); +?> + + + + + + + + + + > + + + + + + + + + + + +
trans("Ref"); ?>trans('RefCustomer'); ?>trans("Date"); ?>trans("AmountHTShort"); ?>trans("Status"); ?>
+ trans("ShowPropal"),"propal").' '.$object->ref; ?>ref_client; ?>date,'day'); ?>rights->propale->lire) { + $total = $total + $object->total_ht; + echo price($object->total_ht); + } ?>getLibStatut(3); ?>
trans('TotalHT'); ?>rights->propale->lire) { + echo price($total); + } ?> 
+ + diff --git a/htdocs/core/modules/modAskPriceSupplier.class.php b/htdocs/core/modules/modAskPriceSupplier.class.php new file mode 100644 index 00000000000..9ae6d15ba71 --- /dev/null +++ b/htdocs/core/modules/modAskPriceSupplier.class.php @@ -0,0 +1,226 @@ + + * Copyright (C) 2004-2010 Laurent Destailleur + * Copyright (C) 2004 Sebastien Di Cintio + * Copyright (C) 2004 Benoit Mortier + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2012 Juanjo Menent + * + * 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 . + */ + +/** + * \defgroup propale Module commercial proposals + * \brief Module pour gerer la tenue de propositions commerciales + * \file htdocs/core/modules/modPropale.class.php + * \ingroup propale + * \brief Fichier de description et activation du module Propale + */ +include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; + + +/** + * Classe de description et activation du module Propale + */ +class modAskPriceSupplier extends DolibarrModules +{ + + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf; + + $this->db = $db; + $this->numero = 999999; + + $this->family = "products"; + // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) + $this->name = preg_replace('/^mod/i','',get_class($this)); + $this->description = "askpricesupplierDESC"; + + // Possible values for version are: 'development', 'experimental', 'dolibarr' or version + $this->version = '0.1'; + + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + $this->special = 0; + $this->picto='askpricesupplier'; + + // Data directories to create when module is enabled + $this->dirs = array(); + + // Dependancies + $this->depends = array('modFournisseur'); + $this->requiredby = array(); + $this->config_page_url = array("askpricesupplier.php"); + $this->langfiles = array("askpricesupplier"); + + // Constants + $this->const = array(); + $r=0; + + /*$this->const[$r][0] = "PROPALE_ADDON_PDF"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "azur"; + $this->const[$r][3] = 'Nom du gestionnaire de generation des propales en PDF'; + $this->const[$r][4] = 0; + $r++;*/ + + // Boxes + $this->boxes = array(); + + // Permissions + $this->rights = array(); + $this->rights_class = 'askpricesupplier'; + $r=0; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Créer/modifier les demandes fournisseurs'; // libelle de la permission + $this->rights[$r][3] = 1; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'create'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Lire les demandes fournisseurs'; // libelle de la permission + $this->rights[$r][3] = 1; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'read'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Valider les demandes fournisseurs'; // libelle de la permission + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'read'; + $this->rights[$r][5] = 'validate'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Envoyer les demandes fournisseurs'; // libelle de la permission + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'read'; + $this->rights[$r][5] = 'send'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Supprimer les demandes fournisseurs'; // libelle de la permission + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'delete'; + + // Exports + //-------- + $r=0; +/* + $r++; + $this->export_code[$r]=$this->rights_class.'_'.$r; + $this->export_label[$r]='ProposalsAndProposalsLines'; // Translation key (used only if key ExportDataset_xxx_z not found) + $this->export_permission[$r]=array(array("propale","export")); + $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','co.code'=>'CountryCode','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','c.rowid'=>"Id",'c.ref'=>"Ref",'c.ref_client'=>"RefCustomer",'c.fk_soc'=>"IdCompany",'c.datec'=>"DateCreation",'c.datep'=>"DatePropal",'c.fin_validite'=>"DateEndPropal",'c.remise_percent'=>"GlobalDiscount",'c.total_ht'=>"TotalHT",'c.total'=>"TotalTTC",'c.fk_statut'=>'Status','c.note_public'=>"Note",'c.date_livraison'=>'DeliveryDate','c.fk_user_author'=>'CreatedById','uc.login'=>'CreatedByLogin','c.fk_user_valid'=>'ValidatedById','uv.login'=>'ValidatedByLogin','cd.rowid'=>'LineId','cd.label'=>"Label",'cd.description'=>"LineDescription",'cd.product_type'=>'TypeOfLineServiceOrProduct','cd.tva_tx'=>"LineVATRate",'cd.qty'=>"LineQty",'cd.total_ht'=>"LineTotalHT",'cd.total_tva'=>"LineTotalVAT",'cd.total_ttc'=>"LineTotalTTC",'p.rowid'=>'ProductId','p.ref'=>'ProductRef','p.label'=>'ProductLabel'); + //$this->export_TypeFields_array[$r]=array('s.rowid'=>"List:societe:nom",'s.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text','co.code'=>'Text','s.phone'=>'Text','s.siren'=>'Text','s.siret'=>'Text','s.ape'=>'Text','s.idprof4'=>'Text','c.ref'=>"Text",'c.ref_client'=>"Text",'c.datec'=>"Date",'c.datep'=>"Date",'c.fin_validite'=>"Date",'c.remise_percent'=>"Numeric",'c.total_ht'=>"Numeric",'c.total'=>"Numeric",'c.fk_statut'=>'Status','c.note_public'=>"Text",'c.date_livraison'=>'Date','cd.description'=>"Text",'cd.product_type'=>'Boolean','cd.tva_tx'=>"Numeric",'cd.qty'=>"Numeric",'cd.total_ht'=>"Numeric",'cd.total_tva'=>"Numeric",'cd.total_ttc'=>"Numeric",'p.rowid'=>'List:Product:label','p.ref'=>'Text','p.label'=>'Text'); + $this->export_TypeFields_array[$r]=array('s.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text','co.code'=>'Text','s.phone'=>'Text','s.siren'=>'Text','s.siret'=>'Text','s.ape'=>'Text','s.idprof4'=>'Text','c.ref'=>"Text",'c.ref_client'=>"Text",'c.datec'=>"Date",'c.datep'=>"Date",'c.fin_validite'=>"Date",'c.remise_percent'=>"Numeric",'c.total_ht'=>"Numeric",'c.total'=>"Numeric",'c.fk_statut'=>'Status','c.note_public'=>"Text",'c.date_livraison'=>'Date','cd.description'=>"Text",'cd.product_type'=>'Boolean','cd.tva_tx'=>"Numeric",'cd.qty'=>"Numeric",'cd.total_ht'=>"Numeric",'cd.total_tva'=>"Numeric",'cd.total_ttc'=>"Numeric",'p.ref'=>'Text','p.label'=>'Text'); + $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','co.code'=>'company','s.phone'=>'company','s.siren'=>'company','s.ape'=>'company','s.idprof4'=>'company','s.siret'=>'company','c.rowid'=>"propal",'c.ref'=>"propal",'c.ref_client'=>"propal",'c.fk_soc'=>"propal",'c.datec'=>"propal",'c.datep'=>"propal",'c.fin_validite'=>"propal",'c.remise_percent'=>"propal",'c.total_ht'=>"propal",'c.total'=>"propal",'c.fk_statut'=>"propal",'c.note_public'=>"propal",'c.date_livraison'=>"propal",'cd.rowid'=>'propal_line','cd.label'=>"propal_line",'cd.description'=>"propal_line",'cd.product_type'=>'propal_line','cd.tva_tx'=>"propal_line",'cd.qty'=>"propal_line",'cd.total_ht'=>"propal_line",'cd.total_tva'=>"propal_line",'cd.total_ttc'=>"propal_line",'p.rowid'=>'product','p.ref'=>'product','p.label'=>'product'); + $this->export_dependencies_array[$r]=array('propal_line'=>'cd.rowid','product'=>'cd.rowid'); // To add unique key if we ask a field of a child to avoid the DISTINCT to discard them + + $this->export_sql_start[$r]='SELECT DISTINCT '; + $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'societe as s '; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'c_country as co ON s.fk_pays = co.rowid,'; + $this->export_sql_end[$r] .=' '.MAIN_DB_PREFIX.'propal as c'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'user as uc ON c.fk_user_author = uc.rowid'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'user as uv ON c.fk_user_valid = uc.rowid'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'propal_extrafields as extra ON c.rowid = extra.fk_object'; + $this->export_sql_end[$r] .=', '.MAIN_DB_PREFIX.'propaldet as cd'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (cd.fk_product = p.rowid)'; + $this->export_sql_end[$r] .=' WHERE c.fk_soc = s.rowid AND c.rowid = cd.fk_propal'; + $this->export_sql_end[$r] .=' AND c.entity = '.$conf->entity; + */ + + // Main menu entries + $this->menu = array(); // List of menus to add + $r=0; + $this->menu[$r]=array( + 'fk_menu'=>'fk_mainmenu=commercial', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'left', // This is a Left menu entry + 'titre'=>'askpricesupplierMENU_LEFT_TITLE', + 'leftmenu'=>'askpricesuppliersubmenu', + 'url'=>'/askpricesupplier/index.php', + 'langs'=>'askpricesupplier', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'enabled'=>'$conf->askpricesupplier->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + 'perms'=>'$user->rights->askpricesupplier->read', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'user'=>2 // 0=Menu for internal users, 1=external users, 2=both + ); + $r++; + + $this->menu[$r]=array( + 'fk_menu'=>'fk_mainmenu=commercial,fk_leftmenu=askpricesuppliersubmenu', + 'type'=>'left', + 'titre'=>'askpricesupplierMENU_LEFT_TITLE_NEW', + 'url'=>'/askpricesupplier/card.php?action=create', + 'langs'=>'askpricesupplier', + 'enabled'=>'$conf->askpricesupplier->enabled', + 'perms'=>'$user->rights->askpricesupplier->create', + 'user'=>2 + ); + $r++; + + $this->menu[$r]=array( + 'fk_menu'=>'fk_mainmenu=commercial,fk_leftmenu=askpricesuppliersubmenu', + 'type'=>'left', + 'titre'=>'askpricesupplierMENU_LEFT_TITLE_LIST', + 'url'=>'/askpricesupplier/list.php', + 'langs'=>'askpricesupplier', + 'enabled'=>'$conf->askpricesupplier->enabled', + 'perms'=>'$user->rights->askpricesupplier->read', + 'user'=>2 + ); + $r++; + } + + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function init($options='') + { + //global $conf,$langs; + + $sql = array(); + + $result=$this->_load_tables('/mymodule/sql/'); + + return $this->_init($sql, $options); + } + + /** + * Function called when module is disabled. + * Remove from database constants, boxes and permissions from Dolibarr database. + * Data directories are not deleted + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function remove($options='') + { + $sql = array(); + + return $this->_remove($sql,$options); + } + +} diff --git a/htdocs/langs/fr_FR/askpricesupplier.lang b/htdocs/langs/fr_FR/askpricesupplier.lang new file mode 100644 index 00000000000..784082f42c4 --- /dev/null +++ b/htdocs/langs/fr_FR/askpricesupplier.lang @@ -0,0 +1,6 @@ +# Dolibarr language file - Source file is en_US - askpricesupplier +AskPriceSupplier=Demande de prix fournisseur +askpricesupplierDESC=Gestion des demandes de prix aux fournisseurs +askpricesupplierMENU_LEFT_TITLE=Demandes de prix fourn. +askpricesupplierMENU_LEFT_TITLE_NEW=Nouvelle demande +askpricesupplierMENU_LEFT_TITLE_LIST=Liste \ No newline at end of file diff --git a/htdocs/theme/eldy/img/object_askpricesupplier.png b/htdocs/theme/eldy/img/object_askpricesupplier.png new file mode 100644 index 00000000000..9ab48924ccb Binary files /dev/null and b/htdocs/theme/eldy/img/object_askpricesupplier.png differ