From f335c4f306d347a9afc78ab2fae67fba8997e939 Mon Sep 17 00:00:00 2001 From: jfefe Date: Mon, 4 Mar 2013 18:22:25 +0100 Subject: [PATCH 01/24] New : add extrafield support on propal object --- htdocs/admin/propal.php | 7 +- htdocs/comm/admin/propal_extrafields.php | 159 ++++++++++++++++++ htdocs/comm/propal.php | 5 + htdocs/comm/propal/class/propal.class.php | 14 ++ htdocs/core/lib/propal.lib.php | 36 ++++ .../install/mysql/migration/3.3.0-3.4.0.sql | 10 ++ .../tables/llx_propal_extrafields.key.sql | 20 +++ .../mysql/tables/llx_propal_extrafields.sql | 26 +++ 8 files changed, 276 insertions(+), 1 deletion(-) create mode 100755 htdocs/comm/admin/propal_extrafields.php create mode 100755 htdocs/install/mysql/tables/llx_propal_extrafields.key.sql create mode 100755 htdocs/install/mysql/tables/llx_propal_extrafields.sql diff --git a/htdocs/admin/propal.php b/htdocs/admin/propal.php index 04f429f50bb..6c18da0e240 100644 --- a/htdocs/admin/propal.php +++ b/htdocs/admin/propal.php @@ -31,7 +31,7 @@ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.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("admin"); $langs->load("errors"); $langs->load('other'); @@ -214,6 +214,7 @@ else if ($action == 'setmod') $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); + llxHeader('',$langs->trans("PropalSetup")); $form=new Form($db); @@ -223,6 +224,10 @@ $form=new Form($db); $linkback=''.$langs->trans("BackToModuleList").''; print_fiche_titre($langs->trans("PropalSetup"),$linkback,'setup'); +$head = propal_admin_prepare_head(null); + +dol_fiche_head($head, 'general', $langs->trans("Propales"), 0, 'propal'); + /* * Module numerotation */ diff --git a/htdocs/comm/admin/propal_extrafields.php b/htdocs/comm/admin/propal_extrafields.php new file mode 100755 index 00000000000..9993019775e --- /dev/null +++ b/htdocs/comm/admin/propal_extrafields.php @@ -0,0 +1,159 @@ + + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 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/societe/admin/societe_extrafields.php + * \ingroup societe + * \brief Page to setup extra fields of third party + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + +$langs->load("companies"); +$langs->load("admin"); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=getStaticMember(get_class($extrafields),'type2label'); +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); +$elementtype='propal'; + +if (!$user->admin) accessforbidden(); + + +/* + * Actions + */ + +require DOL_DOCUMENT_ROOT.'/core/admin_extrafields.inc.php'; + + + +/* + * View + */ + +$textobject=$langs->transnoentitiesnoconv("Propales"); + + +llxHeader('',$langs->trans("PropalSetup")); + + +$linkback=''.$langs->trans("BackToModuleList").''; +print_fiche_titre($langs->trans("PropalSetup"),$linkback,'setup'); + + +$head = propal_admin_prepare_head(null); + +dol_fiche_head($head, 'attributes', $langs->trans("Propal"), 0, 'propal'); + + +print $langs->trans("DefineHereComplementaryAttributes",$textobject).'
'."\n"; +print '
'; + +dol_htmloutput_errors($mesg); + +// Load attribute_label +$extrafields->fetch_name_optionals_label($elementtype); + +print ""; + +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +$var=True; +foreach($extrafields->attribute_type as $key => $value) +{ + $var=!$var; + print ""; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + print '\n"; + print '\n"; + print '\n"; + print '\n"; + print ""; + // $i++; +} + +print "
'.$langs->trans("Position").''.$langs->trans("Label").''.$langs->trans("AttributeCode").''.$langs->trans("Type").''.$langs->trans("Size").''.$langs->trans("Unique").''.$langs->trans("Required").' 
".$extrafields->attribute_pos[$key]."".$extrafields->attribute_label[$key]."".$key."".$type2label[$extrafields->attribute_type[$key]]."'.$extrafields->attribute_size[$key]."'.yn($extrafields->attribute_unique[$key])."'.yn($extrafields->attribute_required[$key])."'.img_edit().''; + print "  ".img_delete()."
"; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '
'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation d'un champ optionnel + /* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition d'un champ optionnel */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); +?> diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index 86b9964bd03..eefc7a9ed8e 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -38,6 +38,7 @@ require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; if (! empty($conf->projet->enabled)) { require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; @@ -78,6 +79,7 @@ if (! empty($user->societe_id)) $socid=$user->societe_id; $result = restrictedArea($user, 'propal', $id); $object = new Propal($db); +$extrafields = new ExtraFields($db); // Load object if ($id > 0 || ! empty($ref)) @@ -1168,6 +1170,9 @@ $formfile = new FormFile($db); $formpropal = new FormPropal($db); $companystatic=new Societe($db); +// fetch optionals attributes and labels +$extralabels=$extrafields->fetch_name_optionals_label('propal'); + $now=dol_now(); // Add new proposal diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 4b3686db511..8d96690e9dd 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1149,6 +1149,20 @@ class Propal extends CommonObject return -1; } + // Retreive all extrafield for propal + // fetch optionals attributes and labels + if(!class_exists('Extrafields')) + require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label('propal',true); + if (count($extralabels)>0) { + $this->array_options = array(); + } + foreach($extrafields->attribute_label as $key=>$label) + { + $this->array_options['options_'.$key]=$label; + } + return 1; } diff --git a/htdocs/core/lib/propal.lib.php b/htdocs/core/lib/propal.lib.php index 92eb5e27459..d6348bdcb0e 100644 --- a/htdocs/core/lib/propal.lib.php +++ b/htdocs/core/lib/propal.lib.php @@ -103,5 +103,41 @@ function propal_prepare_head($object) return $head; } +/** + * Return array head with list of tabs to view object informations. + * + * @param Object $object Propal + * @return array head array with tabs + */ +function propal_admin_prepare_head($object) +{ + global $langs, $conf, $user; + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT.'/admin/propal.php'; + $head[$h][1] = $langs->trans("Miscellanous"); + $head[$h][2] = 'general'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab + complete_head_from_modules($conf,$langs,$object,$head,$h,'propal_admin'); + + $head[$h][0] = DOL_URL_ROOT.'/comm/admin/propal_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFields"); + $head[$h][2] = 'attributes'; + $h++; + + + + complete_head_from_modules($conf,$langs,$object,$head,$h,'propal_admin','remove'); + + return $head; +} + ?> \ No newline at end of file diff --git a/htdocs/install/mysql/migration/3.3.0-3.4.0.sql b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql index a854869223b..b028ec4571a 100755 --- a/htdocs/install/mysql/migration/3.3.0-3.4.0.sql +++ b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql @@ -82,3 +82,13 @@ ALTER TABLE llx_c_shipment_mode ADD COLUMN tracking VARCHAR(256) NOT NULL AFTER ALTER TABLE llx_c_shipment_mode MODIFY COLUMN rowid INT(11) NOT NULL AUTO_INCREMENT; ALTER TABLE llx_stock_mouvement MODIFY COLUMN value real; + +create table llx_propal_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; +ALTER TABLE llx_propal_extrafields ADD INDEX idx_propal_extrafields (fk_object); + diff --git a/htdocs/install/mysql/tables/llx_propal_extrafields.key.sql b/htdocs/install/mysql/tables/llx_propal_extrafields.key.sql new file mode 100755 index 00000000000..5c9cc922667 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_propal_extrafields.key.sql @@ -0,0 +1,20 @@ +-- =================================================================== +-- Copyright (C) 2011 Laurent Destailleur +-- +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_propal_extrafields ADD INDEX idx_propal_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_propal_extrafields.sql b/htdocs/install/mysql/tables/llx_propal_extrafields.sql new file mode 100755 index 00000000000..c285df56dd7 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_propal_extrafields.sql @@ -0,0 +1,26 @@ +-- ======================================================================== +-- Copyright (C) 2011 Laurent Destailleur +-- +-- 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 . +-- +-- ======================================================================== + +create table llx_propal_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; + From 59627408c0ec7570ef687d25cde44880d4c337ba Mon Sep 17 00:00:00 2001 From: jfefe Date: Mon, 4 Mar 2013 19:17:11 +0100 Subject: [PATCH 02/24] Edit extrafields on propal --- htdocs/comm/propal.php | 66 ++++++++++++++++++++++- htdocs/comm/propal/class/propal.class.php | 38 +++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index eefc7a9ed8e..b2dc55cc67d 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -1096,6 +1096,36 @@ else if ($action == 'down' && $user->rights->propal->creer) header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id.'#'.GETPOST('rowid')); exit; } +else if ($action == 'update_extras') +{ + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=$_POST[$key]; + } + } + + // 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'=>$object->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$object,$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=$object->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + +} if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->propal->creer) { @@ -1798,19 +1828,53 @@ else } // Other attributes + $res=$object->fetch_optionals($object->id,$extralabels); $parameters=array('colspan' => ' colspan="3"'); $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook if (empty($reshook) && ! empty($extrafields->attribute_label)) { + + if ($action == 'edit_extras') + { + print '
'; + print ''; + print ''; + print ''; + } + + foreach($extrafields->attribute_label as $key=>$label) { $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); print 'attribute_required[$key])) print ' class="fieldrequired"'; print '>'.$label.''; - print $extrafields->showInputField($key,$value); + if ($action == 'edit_extras') + { + print $extrafields->showInputField($key,$value); + } + else + { + print $extrafields->showOutputField($key,$value); + } + print ''."\n"; } + + if(count($extrafields->attribute_label) > 0) { + + if ($action == 'edit_extras') + { + print ''; + print ''; + print ''; + print ''; + + } + else { + print ''.img_picto('','edit').' Modifier les valeurs'; + } + } } // Amount HT diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 8d96690e9dd..7722900a1dc 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1176,6 +1176,44 @@ class Propal extends CommonObject return -1; } } + + /** + * Update value of extrafields on the proposal + * + * @param User $user Object user that modify + * @param double $remise Amount discount + * @return int <0 if ko, >0 if ok + */ + function update_extrafields($user) + { + // 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 From ff2a851ae801e6f46396e77e0ea09c4c9051d22d Mon Sep 17 00:00:00 2001 From: JF FERRY Date: Tue, 5 Mar 2013 08:38:41 +0100 Subject: [PATCH 03/24] Move substitution function for propal to common class & add extrafields display --- .../core/class/commondocgenerator.class.php | 97 +++++++++++++++++++ .../doc/doc_generic_proposal_odt.modules.php | 77 +-------------- 2 files changed, 100 insertions(+), 74 deletions(-) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 4f0a029993f..481e2c2ac33 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -189,6 +189,103 @@ abstract class CommonDocGenerator return $array_thirdparty; } + + /** + * Define array with couple substitution key => substitution value + * + * @param Object $object Main object to use as data source + * @param Translate $outputlangs Lang object to use for output + * @return array Array of substitution + */ + function get_substitutionarray_propal($object,$outputlangs) + { + global $conf; + + $array_propal=array( + 'object_id'=>$object->id, + 'object_ref'=>$object->ref, + 'object_ref_ext'=>$object->ref_ext, + 'object_ref_customer'=>$object->ref_client, + 'object_date'=>dol_print_date($object->date,'day'), + 'object_date_end'=>dol_print_date($object->fin_validite,'day'), + 'object_date_creation'=>dol_print_date($object->date_creation,'day'), + 'object_date_modification'=>dol_print_date($object->date_modification,'day'), + 'object_date_validation'=>dol_print_date($object->date_validation,'dayhour'), + 'object_payment_mode_code'=>$object->mode_reglement_code, + 'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), + 'object_payment_term_code'=>$object->cond_reglement_code, + 'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), + 'object_total_ht'=>price($object->total_ht,0,$outputlangs), + 'object_total_vat'=>price($object->total_tva,0,$outputlangs), + 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), + 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), + 'object_vatrate'=>vatrate($object->tva), + 'object_note_private'=>$object->note, + 'object_note'=>$object->note_public, + ); + + // Add vat by rates + foreach ($object->lines as $line) + { + if (empty($array_propal['object_total_vat_'.$line->tva_tx])) $array_propal['object_total_vat_'.$line->tva_tx]=0; + $array_propal['object_total_vat_'.$line->tva_tx]+=$line->total_tva; + } + + // Retrieve extrafields + if(is_array($object->array_options) && count($object->array_options)) + { + if(!class_exists('Extrafields')) + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label('propal',true); + $object->fetch_optionals($object->id,$extralabels); + + foreach($extrafields->attribute_label as $key=>$label) + { + if($extrafields->attribute_type[$key] == 'price') + { + $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); + } + else if($extrafields->attribute_type[$key] == 'select') + { + $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; + } + $array_propal=array_merge($array_propal,array('propal_options_'.$key => $object->array_options['options_'.$key])); + } + } + return $array_propal; + } + + + /** + * Define array with couple substitution key => substitution value + * + * @param array $line Array of lines + * @param Translate $outputlangs Lang object to use for output + * @return array Substitution array + */ + function get_substitutionarray_propal_lines($line,$outputlangs) + { + global $conf; + + return array( + 'line_fulldesc'=>doc_getlinedesc($line,$outputlangs), + 'line_product_ref'=>$line->product_ref, + 'line_product_label'=>$line->product_label, + 'line_desc'=>$line->desc, + 'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits), + 'line_up'=>price($line->subprice, 0, $outputlangs), + 'line_qty'=>$line->qty, + 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''), + 'line_price_ht'=>price($line->total_ht, 0, $outputlangs), + 'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs), + 'line_price_vat'=>price($line->total_tva, 0, $outputlangs), + 'line_date_start'=>$line->date_start, + 'line_date_end'=>$line->date_end + ); + } + + /** * Rect pdf * diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php index e6103f5a802..0f9e64c1fe2 100644 --- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php +++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php @@ -86,78 +86,6 @@ class doc_generic_proposal_odt extends ModelePDFPropales } - /** - * Define array with couple substitution key => substitution value - * - * @param Object $object Main object to use as data source - * @param Translate $outputlangs Lang object to use for output - * @return array Array of substitution - */ - function get_substitutionarray_object($object,$outputlangs) - { - global $conf; - - $resarray=array( - 'object_id'=>$object->id, - 'object_ref'=>$object->ref, - 'object_ref_ext'=>$object->ref_ext, - 'object_ref_customer'=>$object->ref_client, - 'object_date'=>dol_print_date($object->date,'day'), - 'object_date_end'=>dol_print_date($object->fin_validite,'day'), - 'object_date_creation'=>dol_print_date($object->date_creation,'day'), - 'object_date_modification'=>dol_print_date($object->date_modification,'day'), - 'object_date_validation'=>dol_print_date($object->date_validation,'dayhour'), - 'object_payment_mode_code'=>$object->mode_reglement_code, - 'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), - 'object_payment_term_code'=>$object->cond_reglement_code, - 'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), - 'object_total_ht'=>price($object->total_ht,0,$outputlangs), - 'object_total_vat'=>price($object->total_tva,0,$outputlangs), - 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), - 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), - 'object_vatrate'=>vatrate($object->tva), - 'object_note_private'=>$object->note, - 'object_note'=>$object->note_public, - ); - - // Add vat by rates - foreach ($object->lines as $line) - { - if (empty($resarray['object_total_vat_'.$line->tva_tx])) $resarray['object_total_vat_'.$line->tva_tx]=0; - $resarray['object_total_vat_'.$line->tva_tx]+=$line->total_tva; - } - - return $resarray; - } - - /** - * Define array with couple substitution key => substitution value - * - * @param array $line Array of lines - * @param Translate $outputlangs Lang object to use for output - * @return array Substitution array - */ - function get_substitutionarray_lines($line,$outputlangs) - { - global $conf; - - return array( - 'line_fulldesc'=>doc_getlinedesc($line,$outputlangs), - 'line_product_ref'=>$line->product_ref, - 'line_product_label'=>$line->product_label, - 'line_desc'=>$line->desc, - 'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits), - 'line_up'=>price($line->subprice, 0, $outputlangs), - 'line_qty'=>$line->qty, - 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''), - 'line_price_ht'=>price($line->total_ht, 0, $outputlangs), - 'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs), - 'line_price_vat'=>price($line->total_tva, 0, $outputlangs), - 'line_date_start'=>$line->date_start, - 'line_date_end'=>$line->date_end - ); - } - /** * Return description of a module * @@ -441,7 +369,8 @@ class doc_generic_proposal_odt extends ModelePDFPropales } } // Replace tags of object + external modules - $tmparray=$this->get_substitutionarray_object($object,$outputlangs); + $tmparray=$this->get_substitutionarray_propal($object,$outputlangs); + //print_r($tmparray); exit; complete_substitutions_array($tmparray, $outputlangs, $object); foreach($tmparray as $key=>$value) { @@ -466,7 +395,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales $listlines = $odfHandler->setSegment('lines'); foreach ($object->lines as $line) { - $tmparray=$this->get_substitutionarray_lines($line,$outputlangs); + $tmparray=$this->get_substitutionarray_propal_lines($line,$outputlangs); complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); foreach($tmparray as $key => $val) { From 5ce11d00ddd08a5c18d537fd1fd5928a1d406b47 Mon Sep 17 00:00:00 2001 From: jfefe Date: Tue, 5 Mar 2013 09:44:53 +0100 Subject: [PATCH 04/24] Display linked propal information into invoice ODT --- .../facture/doc/doc_generic_invoice_odt.modules.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index dc00f4370fa..8ed45a19cda 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -347,7 +347,14 @@ class doc_generic_invoice_odt extends ModelePDFFactures { $socobject=$object->client; } + + // Fetch info for linked propal + $linked_propal = $object->fetchObjectLinked('','','',''); + print '
';
+                //print_r($object->linkedObjects['propal']); exit;
 
+                $propal_object = $object->linkedObjects['propal'][0];
+                
                 // Make substitution
                 $substitutionarray=array(
                     '__FROM_NAME__' => $this->emetteur->nom,
@@ -397,8 +404,9 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 				$array_soc=$this->get_substitutionarray_mysoc($mysoc,$outputlangs);
 				$array_thirdparty=$this->get_substitutionarray_thirdparty($socobject,$outputlangs);
 				$array_objet=$this->get_substitutionarray_object($object,$outputlangs);
+				$array_propal=$this->get_substitutionarray_propal($propal_object,$outputlangs,'propal');
 
-				$tmparray = array_merge($array_user,$array_soc,$array_thirdparty,$array_objet);
+				$tmparray = array_merge($array_user,$array_soc,$array_thirdparty,$array_objet,$array_propal);
 				complete_substitutions_array($tmparray, $outputlangs, $object);
 
                 //var_dump($tmparray); exit;

From 9e612696f23182e7eef43914e213793b8aaa7551 Mon Sep 17 00:00:00 2001
From: jfefe 
Date: Tue, 5 Mar 2013 21:51:33 +0100
Subject: [PATCH 05/24] Add help about extrafields in ODT propal

---
 .../proposals/template_proposal.odt           | Bin 13444 -> 22009 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/htdocs/install/doctemplates/proposals/template_proposal.odt b/htdocs/install/doctemplates/proposals/template_proposal.odt
index e163fef76650e978fce7bcc887354774bd9d01fb..ef60d4751fa0a4869c25bac57ad1a40faa5fb4f3 100644
GIT binary patch
delta 17750
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

delta 9111
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�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

#2(`fU`PLqJz%Z97eC8 ziJe8u>Wix5okmL8SAKY;)S#D*_}Q+R(V?kZ2VivZ+j1Piew(eZBUF&MBWPQbmC72a zbL{fiM`;6zp`oXtKE>RAhDlIU=_N<;M+C~F%e)EF=#|cW8fls*>xAEeF>Ir_4Q71| zS2Z!RI^Fa<+~pjizE3l5Rjo;$2!H>&=pD#>GR9x*m0mEeK(Ry-qRIz87rNeF6?jW; zrlLqPpav`X%OY#TD)Cprqmn+e^TBREVjq(piS^@OnGXIev=pc}pqXXpOdc&WT|JcgE zIof}afk5hn&=fU#%HQ2#`UEL?`T+d>{JUV5)X-%$!UxOy+bp0<>cogu)X*Ds;=c(0 zWJvMn2WXiF>Zif_w;h&i5F?V)LWh;fvH!<-{)TALLd(JbD Date: Tue, 5 Mar 2013 22:22:10 +0100 Subject: [PATCH 06/24] Fix : incorrect function used to retrieve extrafields for propal --- htdocs/comm/propal/class/propal.class.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 7722900a1dc..5e8fac582a6 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1155,13 +1155,7 @@ class Propal extends CommonObject require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); $extrafields=new ExtraFields($this->db); $extralabels=$extrafields->fetch_name_optionals_label('propal',true); - if (count($extralabels)>0) { - $this->array_options = array(); - } - foreach($extrafields->attribute_label as $key=>$label) - { - $this->array_options['options_'.$key]=$label; - } + $this->fetch_optionals($this->id,$extralabels); return 1; } From bd229a941702b7321ef12ea8fef81f2c735de280 Mon Sep 17 00:00:00 2001 From: jfefe Date: Tue, 5 Mar 2013 09:43:45 +0100 Subject: [PATCH 07/24] Add param to define key name in return array of substitution function for propal --- .../core/class/commondocgenerator.class.php | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 481e2c2ac33..2b225c7c5cf 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -195,40 +195,41 @@ abstract class CommonDocGenerator * * @param Object $object Main object to use as data source * @param Translate $outputlangs Lang object to use for output + * @param key $key Name of the key for return array * @return array Array of substitution */ - function get_substitutionarray_propal($object,$outputlangs) + function get_substitutionarray_propal($object,$outputlangs,$key='object') { global $conf; $array_propal=array( - 'object_id'=>$object->id, - 'object_ref'=>$object->ref, - 'object_ref_ext'=>$object->ref_ext, - 'object_ref_customer'=>$object->ref_client, - 'object_date'=>dol_print_date($object->date,'day'), - 'object_date_end'=>dol_print_date($object->fin_validite,'day'), - 'object_date_creation'=>dol_print_date($object->date_creation,'day'), - 'object_date_modification'=>dol_print_date($object->date_modification,'day'), - 'object_date_validation'=>dol_print_date($object->date_validation,'dayhour'), - 'object_payment_mode_code'=>$object->mode_reglement_code, - 'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), - 'object_payment_term_code'=>$object->cond_reglement_code, - 'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), - 'object_total_ht'=>price($object->total_ht,0,$outputlangs), - 'object_total_vat'=>price($object->total_tva,0,$outputlangs), - 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), - 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), - 'object_vatrate'=>vatrate($object->tva), - 'object_note_private'=>$object->note, - 'object_note'=>$object->note_public, + $key.'_id'=>$object->id, + $key.'_ref'=>$object->ref, + $key.'_ref_ext'=>$object->ref_ext, + $key.'_ref_customer'=>$object->ref_client, + $key.'_date'=>dol_print_date($object->date,'day'), + $key.'_date_end'=>dol_print_date($object->fin_validite,'day'), + $key.'_date_creation'=>dol_print_date($object->date_creation,'day'), + $key.'_date_modification'=>dol_print_date($object->date_modification,'day'), + $key.'_date_validation'=>dol_print_date($object->date_validation,'dayhour'), + $key.'_payment_mode_code'=>$object->mode_reglement_code, + $key.'_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), + $key.'_payment_term_code'=>$object->cond_reglement_code, + $key.'_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), + $key.'_total_ht'=>price($object->total_ht,0,$outputlangs), + $key.'_total_vat'=>price($object->total_tva,0,$outputlangs), + $key.'_total_ttc'=>price($object->total_ttc,0,$outputlangs), + $key.'_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), + $key.'_vatrate'=>vatrate($object->tva), + $key.'_note_private'=>$object->note, + $key.'_note'=>$object->note_public, ); // Add vat by rates foreach ($object->lines as $line) { - if (empty($array_propal['object_total_vat_'.$line->tva_tx])) $array_propal['object_total_vat_'.$line->tva_tx]=0; - $array_propal['object_total_vat_'.$line->tva_tx]+=$line->total_tva; + if (empty($array_propal[$key.'_total_vat_'.$line->tva_tx])) $array_propal[$key.'_total_vat_'.$line->tva_tx]=0; + $array_propal[$key.'_total_vat_'.$line->tva_tx]+=$line->total_tva; } // Retrieve extrafields @@ -250,7 +251,7 @@ abstract class CommonDocGenerator { $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; } - $array_propal=array_merge($array_propal,array('propal_options_'.$key => $object->array_options['options_'.$key])); + $array_propal=array_merge($array_propal,array($key.'_options_'.$key => $object->array_options['options_'.$key])); } } return $array_propal; From 55bfdd341d5cb0e804aed418c2944f70c0a8d732 Mon Sep 17 00:00:00 2001 From: jfefe Date: Tue, 5 Mar 2013 23:51:42 +0100 Subject: [PATCH 08/24] Fix : change to variable with unused name --- .../core/class/commondocgenerator.class.php | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 2b225c7c5cf..fefc1bfcc89 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -195,41 +195,41 @@ abstract class CommonDocGenerator * * @param Object $object Main object to use as data source * @param Translate $outputlangs Lang object to use for output - * @param key $key Name of the key for return array + * @param array_key $array_key Name of the key for return array * @return array Array of substitution */ - function get_substitutionarray_propal($object,$outputlangs,$key='object') + function get_substitutionarray_propal($object,$outputlangs,$array_key='object') { global $conf; $array_propal=array( - $key.'_id'=>$object->id, - $key.'_ref'=>$object->ref, - $key.'_ref_ext'=>$object->ref_ext, - $key.'_ref_customer'=>$object->ref_client, - $key.'_date'=>dol_print_date($object->date,'day'), - $key.'_date_end'=>dol_print_date($object->fin_validite,'day'), - $key.'_date_creation'=>dol_print_date($object->date_creation,'day'), - $key.'_date_modification'=>dol_print_date($object->date_modification,'day'), - $key.'_date_validation'=>dol_print_date($object->date_validation,'dayhour'), - $key.'_payment_mode_code'=>$object->mode_reglement_code, - $key.'_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), - $key.'_payment_term_code'=>$object->cond_reglement_code, - $key.'_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), - $key.'_total_ht'=>price($object->total_ht,0,$outputlangs), - $key.'_total_vat'=>price($object->total_tva,0,$outputlangs), - $key.'_total_ttc'=>price($object->total_ttc,0,$outputlangs), - $key.'_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), - $key.'_vatrate'=>vatrate($object->tva), - $key.'_note_private'=>$object->note, - $key.'_note'=>$object->note_public, + $array_key.'_id'=>$object->id, + $array_key.'_ref'=>$object->ref, + $array_key.'_ref_ext'=>$object->ref_ext, + $array_key.'_ref_customer'=>$object->ref_client, + $array_key.'_date'=>dol_print_date($object->date,'day'), + $array_key.'_date_end'=>dol_print_date($object->fin_validite,'day'), + $array_key.'_date_creation'=>dol_print_date($object->date_creation,'day'), + $array_key.'_date_modification'=>dol_print_date($object->date_modification,'day'), + $array_key.'_date_validation'=>dol_print_date($object->date_validation,'dayhour'), + $array_key.'_payment_mode_code'=>$object->mode_reglement_code, + $array_key.'_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), + $array_key.'_payment_term_code'=>$object->cond_reglement_code, + $array_key.'_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), + $array_key.'_total_ht'=>price($object->total_ht,0,$outputlangs), + $array_key.'_total_vat'=>price($object->total_tva,0,$outputlangs), + $array_key.'_total_ttc'=>price($object->total_ttc,0,$outputlangs), + $array_key.'_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), + $array_key.'_vatrate'=>vatrate($object->tva), + $array_key.'_note_private'=>$object->note, + $array_key.'_note'=>$object->note_public, ); // Add vat by rates foreach ($object->lines as $line) { - if (empty($array_propal[$key.'_total_vat_'.$line->tva_tx])) $array_propal[$key.'_total_vat_'.$line->tva_tx]=0; - $array_propal[$key.'_total_vat_'.$line->tva_tx]+=$line->total_tva; + if (empty($array_propal[$array_key.'_total_vat_'.$line->tva_tx])) $array_propal[$array_key.'_total_vat_'.$line->tva_tx]=0; + $array_propal[$array_key.'_total_vat_'.$line->tva_tx]+=$line->total_tva; } // Retrieve extrafields @@ -251,7 +251,7 @@ abstract class CommonDocGenerator { $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; } - $array_propal=array_merge($array_propal,array($key.'_options_'.$key => $object->array_options['options_'.$key])); + $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key => $object->array_options['options_'.$key])); } } return $array_propal; From 98774665946d632da50c93dde630edd38baf0ccf Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 00:03:24 +0100 Subject: [PATCH 09/24] Add information about linked proposal into basic ODT template for invoice --- .../invoices/template_invoice.odt | Bin 18694 -> 22319 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/htdocs/install/doctemplates/invoices/template_invoice.odt b/htdocs/install/doctemplates/invoices/template_invoice.odt index 2c43d353bbb9d8fd01bfed0fc3802a5a17049898..670fcd41b3b84d158268225d8c64290354bc93f5 100644 GIT binary patch delta 20115 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 delta 16491 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 Date: Wed, 6 Mar 2013 00:18:41 +0100 Subject: [PATCH 10/24] Fix : extrafields for propale were note saved after creation --- htdocs/comm/propal.php | 9 +++++++++ htdocs/comm/propal/class/propal.class.php | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index b2dc55cc67d..4cb99d6395b 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -338,6 +338,15 @@ else if ($action == 'add' && $user->rights->propal->creer) } } + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=GETPOST($key); + } + } + $id = $object->create($user); } diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 5e8fac582a6..e10d1ecc0ea 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -622,7 +622,7 @@ class Propal extends CommonObject */ function create($user='', $notrigger=0) { - global $langs,$conf,$mysoc; + global $langs,$conf,$mysoc,$hookmanager; $error=0; $now=dol_now(); @@ -802,6 +802,24 @@ class Propal extends CommonObject $resql=$this->update_price(1); if ($resql) { + // 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) { // Appel des triggers From 61127e82f66a70e2f430acb40dd651fd4b1e0cdb Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 01:33:55 +0100 Subject: [PATCH 11/24] User must have write permission to edit extrafields on propale --- htdocs/comm/propal.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index 4cb99d6395b..20feee7b04f 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -1115,7 +1115,6 @@ else if ($action == 'update_extras') $object->array_options[$key]=$_POST[$key]; } } - // Actions on extra fields (by external module or standard code) // FIXME le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('propaldao')); @@ -1858,7 +1857,7 @@ else print 'attribute_required[$key])) print ' class="fieldrequired"'; print '>'.$label.''; - if ($action == 'edit_extras') + if ($action == 'edit_extras' && $user->rights->propal->creer) { print $extrafields->showInputField($key,$value); } @@ -1872,7 +1871,7 @@ else if(count($extrafields->attribute_label) > 0) { - if ($action == 'edit_extras') + if ($action == 'edit_extras' && $user->rights->propal->creer) { print ''; print ''; @@ -1880,8 +1879,11 @@ else print ''; } - else { - print ''.img_picto('','edit').' Modifier les valeurs'; + else { + if ($object->statut == 0 && $user->rights->propal->creer) + { + print ''.img_picto('','edit').' '.$langs->trans('Modify').''; + } } } } From 8b749eaafce7e54181c7c0b7f44d723ca915d636 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 01:34:32 +0100 Subject: [PATCH 12/24] Fix : extrafields are not saved on update (propale) --- htdocs/comm/propal/class/propal.class.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index e10d1ecc0ea..66f6bb3874d 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1173,8 +1173,14 @@ class Propal extends CommonObject require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); $extrafields=new ExtraFields($this->db); $extralabels=$extrafields->fetch_name_optionals_label('propal',true); - $this->fetch_optionals($this->id,$extralabels); - + //$this->fetch_optionals($this->id,$extralabels); + if (count($extralabels)>0) { + $this->array_options = array(); + } + foreach($extrafields->attribute_label as $key=>$label) + { + $this->array_options['options_'.$key]=$label; + } return 1; } From 49f1ef173aa4857ba2a4fdf236d4fca6e6d4000a Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 03:17:38 +0100 Subject: [PATCH 13/24] Add table for invoice extrafields --- .../install/mysql/migration/3.3.0-3.4.0.sql | 9 +++++++ .../tables/llx_facture_extrafields.key.sql | 20 ++++++++++++++ .../mysql/tables/llx_facture_extrafields.sql | 26 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100755 htdocs/install/mysql/tables/llx_facture_extrafields.key.sql create mode 100755 htdocs/install/mysql/tables/llx_facture_extrafields.sql diff --git a/htdocs/install/mysql/migration/3.3.0-3.4.0.sql b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql index a854869223b..d182af9f1ef 100755 --- a/htdocs/install/mysql/migration/3.3.0-3.4.0.sql +++ b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql @@ -82,3 +82,12 @@ ALTER TABLE llx_c_shipment_mode ADD COLUMN tracking VARCHAR(256) NOT NULL AFTER ALTER TABLE llx_c_shipment_mode MODIFY COLUMN rowid INT(11) NOT NULL AUTO_INCREMENT; ALTER TABLE llx_stock_mouvement MODIFY COLUMN value real; + +create table llx_facture_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; +ALTER TABLE llx_facture_extrafields ADD INDEX idx_facture_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_facture_extrafields.key.sql b/htdocs/install/mysql/tables/llx_facture_extrafields.key.sql new file mode 100755 index 00000000000..e44905ccc2e --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_extrafields.key.sql @@ -0,0 +1,20 @@ +-- =================================================================== +-- Copyright (C) 2013 Jean-Francois FERRY +-- +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_facture_extrafields ADD INDEX idx_facture_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_facture_extrafields.sql b/htdocs/install/mysql/tables/llx_facture_extrafields.sql new file mode 100755 index 00000000000..9ef15f4e012 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_extrafields.sql @@ -0,0 +1,26 @@ +-- ======================================================================== +-- Copyright (C) 2013 Jean-Francois FERRY +-- +-- 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 . +-- +-- ======================================================================== + +create table llx_facture_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; + From 88a042ec4168099eb35279b904be2d439066a8f8 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 03:36:43 +0100 Subject: [PATCH 14/24] Prepare invoice admin page to add extrafield support --- htdocs/admin/facture.php | 4 ++++ htdocs/core/lib/invoice.lib.php | 38 +++++++++++++++++++++++++++++++++ htdocs/langs/fr_FR/admin.lang | 1 + 3 files changed, 43 insertions(+) diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php index 57193dfdb71..35768104e39 100644 --- a/htdocs/admin/facture.php +++ b/htdocs/admin/facture.php @@ -28,11 +28,13 @@ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; $langs->load("admin"); $langs->load("errors"); $langs->load('other'); +$langs->load('bills'); if (! $user->admin) accessforbidden(); @@ -304,6 +306,8 @@ $linkback=''.$langs->trans("BackToM print_fiche_titre($langs->trans("BillsSetup"),$linkback,'setup'); print '
'; +$head = invoice_admin_prepare_head(null); +dol_fiche_head($head, 'general', $langs->trans("Invoices"), 0, 'invoice'); /* * Numbering module diff --git a/htdocs/core/lib/invoice.lib.php b/htdocs/core/lib/invoice.lib.php index e70f215df2d..03b8fa7240d 100644 --- a/htdocs/core/lib/invoice.lib.php +++ b/htdocs/core/lib/invoice.lib.php @@ -98,4 +98,42 @@ function facture_prepare_head($object) return $head; } +/** + * Return array head with list of tabs to view object informations. + * + * @param Object $object Invoice + * @return array head array with tabs + */ +function invoice_admin_prepare_head($object) +{ + global $langs, $conf, $user; + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT.'/admin/facture.php'; + $head[$h][1] = $langs->trans("Miscellanous"); + $head[$h][2] = 'general'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab + complete_head_from_modules($conf,$langs,$object,$head,$h,'invoice_admin'); + + $head[$h][0] = DOL_URL_ROOT.'/compta/facture/admin/facture_cust_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsCustomerInvoices"); + $head[$h][2] = 'attributes'; + $h++; + + + + complete_head_from_modules($conf,$langs,$object,$head,$h,'invoice_admin','remove'); + + return $head; +} + + + ?> \ No newline at end of file diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 2f96fd3c289..aaf072792a6 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -936,6 +936,7 @@ ExtraFieldsThirdParties=Attributs supplémentaires (tiers) ExtraFieldsContacts=Attributs supplémentaires (contacts/adresses) ExtraFieldsMember=Attributs supplémentaires (adhérents) ExtraFieldsMemberType=Attributs supplémentaires (type d'adhérents) +ExtraFieldsCustomerInvoices=Attributs supplémentaires (factures clients) ExtraFieldHasWrongValue=L'attribut %s a une valeur incorrecte. AlphaNumOnlyCharsAndNoSpace=uniquement caractères alphanumériques sans espace SendingMailSetup=Configuration de l'envoi par mail From 4314d4c7febe265e81f0df0951d04383c96f186b Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 03:50:41 +0100 Subject: [PATCH 15/24] Add admin screen for extrafields on customer invoices --- .../admin/facture_cust_extrafields.php | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 htdocs/compta/facture/admin/facture_cust_extrafields.php diff --git a/htdocs/compta/facture/admin/facture_cust_extrafields.php b/htdocs/compta/facture/admin/facture_cust_extrafields.php new file mode 100644 index 00000000000..d08d5fe0ba8 --- /dev/null +++ b/htdocs/compta/facture/admin/facture_cust_extrafields.php @@ -0,0 +1,160 @@ + +* Copyright (C) 2003 Jean-Louis Bergamo +* Copyright (C) 2004-2011 Laurent Destailleur +* Copyright (C) 2012 Regis Houssin +* Copyright (C) 2013 Jean-Francois FERRY +* +* 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/compta/facture/admin/facture_cust_extrafields.php +* \ingroup invoice +* \brief Page to setup extra fields of customer invoice +*/ + +require '../../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + +$langs->load("companies"); +$langs->load("admin"); +$langs->load("bills"); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=getStaticMember(get_class($extrafields),'type2label'); +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); +$elementtype='facture'; + +if (!$user->admin) accessforbidden(); + + +/* +* Actions +*/ + +require DOL_DOCUMENT_ROOT.'/core/admin_extrafields.inc.php'; + + + +/* +* View +*/ + +$textobject=strtolower($langs->transnoentitiesnoconv("BillsCustomers")); + + +llxHeader('',$langs->trans("BillsSetup")); + + +$linkback='
'.$langs->trans("BackToModuleList").''; +print_fiche_titre($langs->trans("BillsSetup"),$linkback,'setup'); +print '
'; + +$head = invoice_admin_prepare_head(null); + +dol_fiche_head($head, 'attributes', $langs->trans("Invoices"), 0, 'invoice'); + + +print $langs->trans("DefineHereComplementaryAttributes",$textobject).'
'."\n"; + +dol_htmloutput_errors($mesg); + +// Load attribute_label +$extrafields->fetch_name_optionals_label($elementtype); + +print ""; + +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +$var=True; +foreach($extrafields->attribute_type as $key => $value) +{ + $var=!$var; + print ""; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + print '\n"; + print '\n"; + print '\n"; + print '\n"; + print ""; + // $i++; +} + +print "
'.$langs->trans("Position").''.$langs->trans("Label").''.$langs->trans("AttributeCode").''.$langs->trans("Type").''.$langs->trans("Size").''.$langs->trans("Unique").''.$langs->trans("Required").' 
".$extrafields->attribute_pos[$key]."".$extrafields->attribute_label[$key]."".$key."".$type2label[$extrafields->attribute_type[$key]]."'.$extrafields->attribute_size[$key]."'.yn($extrafields->attribute_unique[$key])."'.yn($extrafields->attribute_required[$key])."'.img_edit().''; + print "  ".img_delete()."
"; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '

'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation d'un champ optionnel +/* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition d'un champ optionnel */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); +?> \ No newline at end of file From 7260e139dfac0c5f42b868e0605587dec11ed360 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 04:17:14 +0100 Subject: [PATCH 16/24] Add extrafields support when create a customer invoice --- htdocs/compta/facture.php | 13 ++++++++++++ htdocs/compta/facture/class/facture.class.php | 20 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index 7766cfeb862..26673dbd937 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -7,6 +7,7 @@ * Copyright (C) 2006 Andre Cianfarani * Copyright (C) 2010-2013 Juanjo Menent * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2013 Jean-Francois FERRY * * 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 @@ -38,6 +39,7 @@ require DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php'; require DOL_DOCUMENT_ROOT . '/core/lib/invoice.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; +require DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; if (! empty($conf->commande->enabled)) { require DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php'; @@ -87,6 +89,7 @@ $NBLINES=4; $usehm=(! empty($conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE)?$conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE:0); $object=new Facture($db); +$extrafields = new ExtraFields($db); // Load object if ($id > 0 || ! empty($ref)) @@ -613,6 +616,15 @@ else if ($action == 'add' && $user->rights->facture->creer) $db->begin(); $error=0; + + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=GETPOST($key); + } + } // Replacement invoice if ($_POST['type'] == 1) @@ -1743,6 +1755,7 @@ $now=dol_now(); if ($action == 'create') { $facturestatic=new Facture($db); + $extralabels=$extrafields->fetch_name_optionals_label('facture'); print_fiche_titre($langs->trans('NewBill')); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index fd3bb85a69b..31e45d40807 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -135,7 +135,7 @@ class Facture extends CommonInvoice */ function create($user,$notrigger=0,$forceduedate=0) { - global $langs,$conf,$mysoc; + global $langs,$conf,$mysoc,$hookmanager; $error=0; // Clean parameters @@ -437,6 +437,24 @@ class Facture extends CommonInvoice $result=$this->update_price(1); if ($result > 0) { + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('invoicedao')); + $parameters=array('invoiceid'=>$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++; + // Appel des triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; $interface=new Interfaces($this->db); From 3ccb0fb92cfc95434f693e1787cf8486836a159d Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 04:54:08 +0100 Subject: [PATCH 17/24] Edit extrafields on customer invoice --- htdocs/compta/facture.php | 95 ++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index 26673dbd937..6149a8f5480 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -1733,6 +1733,36 @@ if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->facture- } } +if ($action == 'update_extras') +{ + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=$_POST[$key]; + } + } + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('invoicedao')); + $parameters=array('id'=>$object->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$object,$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=$object->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + +} + /* * View @@ -2233,6 +2263,10 @@ else if ($id > 0 || ! empty($ref)) */ $result=$object->fetch($id,$ref); + + // fetch optionals attributes and labels + $extralabels=$extrafields->fetch_name_optionals_label('facture'); + if ($result > 0) { if ($user->societe_id>0 && $user->societe_id!=$object->socid) accessforbidden('',0); @@ -3041,21 +3075,58 @@ else if ($id > 0 || ! empty($ref)) print ''; print ''; } - + // Other attributes - $parameters=array('colspan' => ' colspan="3"'); - $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + $res=$object->fetch_optionals($object->id,$extralabels); + $parameters=array('colspan' => ' colspan="2"'); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook if (empty($reshook) && ! empty($extrafields->attribute_label)) { - foreach($extrafields->attribute_label as $key=>$label) - { - $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); - print 'attribute_required[$key])) print ' class="fieldrequired"'; - print '>'.$label.''; - print $extrafields->showInputField($key,$value); - print ''."\n"; - } + + if ($action == 'edit_extras') + { + print '
'; + print ''; + print ''; + print ''; + } + + + foreach($extrafields->attribute_label as $key=>$label) + { + $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); + print 'attribute_required[$key])) print ' class="fieldrequired"'; + print '>'.$label.''; + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print $extrafields->showInputField($key,$value); + } + else + { + print $extrafields->showOutputField($key,$value); + } + + print ''."\n"; + } + + if(count($extrafields->attribute_label) > 0) { + + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print ''; + print ''; + print ''; + print ''; + + } + else { + if ($object->statut == 0 && $user->rights->propal->creer) + { + print ''.img_picto('','edit').' '.$langs->trans('Modify').''; + } + } + } } print '
'; From dc1314f4f432fd8daf7ca185a12438c9979d34d1 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 05:31:19 +0100 Subject: [PATCH 18/24] Retreive extrafield when fetch invoice --- htdocs/compta/facture/class/facture.class.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 31e45d40807..b6c74203636 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -865,6 +865,20 @@ class Facture extends CommonInvoice $this->extraparams = (array) json_decode($obj->extraparams, true); if ($this->statut == 0) $this->brouillon = 1; + + // Retreive all extrafield for invoice + // fetch optionals attributes and labels + if(!class_exists('Extrafields')) + require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label('facture',true); + if (count($extralabels)>0) { + $this->array_options = array(); + } + foreach($extrafields->attribute_label as $key=>$label) + { + $this->array_options['options_'.$key]=$label; + } /* * Lines From 04617d0eb31852cf3f04408d46ad84fce19d4c15 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 6 Mar 2013 05:33:00 +0100 Subject: [PATCH 19/24] Show extrafields for object into invoice ODT document --- .../doc/doc_generic_invoice_odt.modules.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index dc00f4370fa..2370f102625 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -140,6 +140,28 @@ class doc_generic_invoice_odt extends ModelePDFFactures $resarray['object_total_vat_'.$line->tva_tx]+=$line->total_tva; } + // Retrieve extrafields + if(is_array($object->array_options) && count($object->array_options)) + { + if(!class_exists('Extrafields')) + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label('facture',true); + $object->fetch_optionals($object->id,$extralabels); + + foreach($extrafields->attribute_label as $key=>$label) + { + if($extrafields->attribute_type[$key] == 'price') + { + $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); + } + else if($extrafields->attribute_type[$key] == 'select') + { + $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; + } + $resarray=array_merge($resarray,array('object_options_'.$key => $object->array_options['options_'.$key])); + } + } return $resarray; } From 06807ce19867d972b510c1ee250204dce4d297bc Mon Sep 17 00:00:00 2001 From: jfefe Date: Thu, 7 Mar 2013 02:13:21 +0100 Subject: [PATCH 20/24] Fix : select correct value of extrafield (select list) --- htdocs/core/class/extrafields.class.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index f72ddc8d6e2..de828e8a237 100755 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -651,9 +651,11 @@ class ExtraFields elseif ($type == 'select') { $out=''; } From ac3116930c58d9593ee76f1a4ad1a30c3501b333 Mon Sep 17 00:00:00 2001 From: jfefe Date: Thu, 7 Mar 2013 02:23:37 +0100 Subject: [PATCH 21/24] Add value to store price type extrafield without currency in ODT --- htdocs/core/class/commondocgenerator.class.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index fefc1bfcc89..abb88070a6a 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -245,13 +245,20 @@ abstract class CommonDocGenerator { if($extrafields->attribute_type[$key] == 'price') { - $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); + $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]); + $object->array_options['options_'.$key.'_currency'] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); + // Add value to store price without currency + $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key.'_currency' => $object->array_options['options_'.$key.'_currency'])); } else if($extrafields->attribute_type[$key] == 'select') { $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; } - $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key => $object->array_options['options_'.$key])); + else if($extrafields->attribute_type[$key] == 'date') + { + + } + $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key => $object->array_options['options_'.$key])); } } return $array_propal; From 65ed01a251530f44a0794c50de654d5eb2e110ec Mon Sep 17 00:00:00 2001 From: jfefe Date: Thu, 7 Mar 2013 02:52:28 +0100 Subject: [PATCH 22/24] Extrafields on ODT (propal) : fix value of price with currency & display date with correct format --- htdocs/core/class/commondocgenerator.class.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index abb88070a6a..105936a0429 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -246,8 +246,8 @@ abstract class CommonDocGenerator if($extrafields->attribute_type[$key] == 'price') { $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]); - $object->array_options['options_'.$key.'_currency'] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); - // Add value to store price without currency + $object->array_options['options_'.$key.'_currency'] = $object->array_options['options_'.$key].' '.$outputlangs->getCurrencySymbol($conf->currency); + // Add value to store price with currency $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key.'_currency' => $object->array_options['options_'.$key.'_currency'])); } else if($extrafields->attribute_type[$key] == 'select') @@ -256,7 +256,11 @@ abstract class CommonDocGenerator } else if($extrafields->attribute_type[$key] == 'date') { - + $object->array_options['options_'.$key] = (strlen($object->array_options['options_'.$key])>0?dol_print_date($object->array_options['options_'.$key],'day'):''); + } + else if($extrafields->attribute_type[$key] == 'datetime') + { + $object->array_options['options_'.$key] = ($object->array_options['options_'.$key]!="0000-00-00 00:00:00"?dol_print_date($object->array_options['options_'.$key],'dayhour'):''); } $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key => $object->array_options['options_'.$key])); } From 289e2e788878e7033b31554de11bb398f8926056 Mon Sep 17 00:00:00 2001 From: jfefe Date: Thu, 7 Mar 2013 03:24:22 +0100 Subject: [PATCH 23/24] New function to fill ODT substitution array with extrafield of object --- .../core/class/commondocgenerator.class.php | 73 ++++++++++++------- .../doc/doc_generic_invoice_odt.modules.php | 13 +--- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 105936a0429..7c69c888a7a 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -161,18 +161,18 @@ abstract class CommonDocGenerator 'company_idprof4'=>$object->idprof4, 'company_idprof5'=>$object->idprof5, 'company_idprof6'=>$object->idprof6, - 'company_note'=>$object->note + 'company_note'=>$object->note ); // Retrieve extrafields if(is_array($object->array_options) && count($object->array_options)) { - if(!class_exists('Extrafields')) + if(!class_exists('Extrafields')) require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; $extrafields = new ExtraFields($this->db); $extralabels = $extrafields->fetch_name_optionals_label('company',true); $object->fetch_optionals($object->id,$extralabels); - + foreach($extrafields->attribute_label as $key=>$label) { if($extrafields->attribute_type[$key] == 'price') @@ -180,7 +180,7 @@ abstract class CommonDocGenerator $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); } else if($extrafields->attribute_type[$key] == 'select') - { + { $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; } $array_thirdparty=array_merge($array_thirdparty,array('company_options_'.$key => $object->array_options['options_'.$key])); @@ -241,29 +241,7 @@ abstract class CommonDocGenerator $extralabels = $extrafields->fetch_name_optionals_label('propal',true); $object->fetch_optionals($object->id,$extralabels); - foreach($extrafields->attribute_label as $key=>$label) - { - if($extrafields->attribute_type[$key] == 'price') - { - $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]); - $object->array_options['options_'.$key.'_currency'] = $object->array_options['options_'.$key].' '.$outputlangs->getCurrencySymbol($conf->currency); - // Add value to store price with currency - $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key.'_currency' => $object->array_options['options_'.$key.'_currency'])); - } - else if($extrafields->attribute_type[$key] == 'select') - { - $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; - } - else if($extrafields->attribute_type[$key] == 'date') - { - $object->array_options['options_'.$key] = (strlen($object->array_options['options_'.$key])>0?dol_print_date($object->array_options['options_'.$key],'day'):''); - } - else if($extrafields->attribute_type[$key] == 'datetime') - { - $object->array_options['options_'.$key] = ($object->array_options['options_'.$key]!="0000-00-00 00:00:00"?dol_print_date($object->array_options['options_'.$key],'dayhour'):''); - } - $array_propal=array_merge($array_propal,array($array_key.'_options_'.$key => $object->array_options['options_'.$key])); - } + $array_propal = $this->fill_substitutionarray_with_extrafields($object,$array_propal,$extrafields,$array_key,$outputlangs); } return $array_propal; } @@ -297,6 +275,47 @@ abstract class CommonDocGenerator ); } + /** + * Fill array with couple extrafield key => extrafield value + * + * @param Object $object Object with extrafields (must have $object->array_options filled) + * @param array $array_to_fill Substitution array + * @param Extrafields $extrafields Extrafields object + * @param array_key $array_key Name of the key for return array + * @param Translate $outputlangs Lang object to use for output + * @return array Substitution array + */ + function fill_substitutionarray_with_extrafields($object,$array_to_fill,$extrafields,$array_key,$outputlangs) + { + global $conf; + foreach($extrafields->attribute_label as $key=>$label) + { + if($extrafields->attribute_type[$key] == 'price') + { + $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]); + $object->array_options['options_'.$key.'_currency'] = $object->array_options['options_'.$key].' '.$outputlangs->getCurrencySymbol($conf->currency); + //Add value to store price with currency + $array_to_fill=array_merge($array_to_fill,array($array_key.'_options_'.$key.'_currency' => $object->array_options['options_'.$key.'_currency'])); + } + else if($extrafields->attribute_type[$key] == 'select') + { + $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; + } + else if($extrafields->attribute_type[$key] == 'date') + { + $object->array_options['options_'.$key] = (strlen($object->array_options['options_'.$key])>0?dol_print_date($object->array_options['options_'.$key],'day'):''); + } + else if($extrafields->attribute_type[$key] == 'datetime') + { + $object->array_options['options_'.$key] = ($object->array_options['options_'.$key]!="0000-00-00 00:00:00"?dol_print_date($object->array_options['options_'.$key],'dayhour'):''); + } + $array_to_fill=array_merge($array_to_fill,array($array_key.'_options_'.$key => $object->array_options['options_'.$key])); + } + + return $array_to_fill; + + } + /** * Rect pdf diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index 02c53d76a1a..adf5c2ec2a6 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -149,18 +149,7 @@ class doc_generic_invoice_odt extends ModelePDFFactures $extralabels = $extrafields->fetch_name_optionals_label('facture',true); $object->fetch_optionals($object->id,$extralabels); - foreach($extrafields->attribute_label as $key=>$label) - { - if($extrafields->attribute_type[$key] == 'price') - { - $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); - } - else if($extrafields->attribute_type[$key] == 'select') - { - $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; - } - $resarray=array_merge($resarray,array('object_options_'.$key => $object->array_options['options_'.$key])); - } + $resarray = $this->fill_substitutionarray_with_extrafields($object,$resarray,$extrafields,$array_key='object',$outputlangs); } return $resarray; } From fcd81e47eb35a52f3d87200af97e40680b08b864 Mon Sep 17 00:00:00 2001 From: jfefe Date: Thu, 7 Mar 2013 03:43:23 +0100 Subject: [PATCH 24/24] Use price2num() function instead of price() to use calcul in ODT. Libre/Open Office wants number with dot and no space to allow make calcul in ODT document --- htdocs/core/class/commondocgenerator.class.php | 18 +++++++++--------- .../doc/doc_generic_invoice_odt.modules.php | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 7c69c888a7a..faccaa31545 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -216,10 +216,10 @@ abstract class CommonDocGenerator $array_key.'_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), $array_key.'_payment_term_code'=>$object->cond_reglement_code, $array_key.'_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), - $array_key.'_total_ht'=>price($object->total_ht,0,$outputlangs), - $array_key.'_total_vat'=>price($object->total_tva,0,$outputlangs), - $array_key.'_total_ttc'=>price($object->total_ttc,0,$outputlangs), - $array_key.'_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), + $array_key.'_total_ht'=>price2num($object->total_ht2,2), + $array_key.'_total_vat'=>price2num($object->total_tva,2), + $array_key.'_total_ttc'=>price2num($object->total_ttc,2), + $array_key.'_total_discount_ht' => price2num($object->getTotalDiscount(),2), $array_key.'_vatrate'=>vatrate($object->tva), $array_key.'_note_private'=>$object->note, $array_key.'_note'=>$object->note_public, @@ -264,12 +264,12 @@ abstract class CommonDocGenerator 'line_product_label'=>$line->product_label, 'line_desc'=>$line->desc, 'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits), - 'line_up'=>price($line->subprice, 0, $outputlangs), + 'line_up'=>price2num($line->subprice, 2), 'line_qty'=>$line->qty, 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''), - 'line_price_ht'=>price($line->total_ht, 0, $outputlangs), - 'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs), - 'line_price_vat'=>price($line->total_tva, 0, $outputlangs), + 'line_price_ht'=>price2num($line->total_ht,2), + 'line_price_ttc'=>price2num($line->total_ttc,2), + 'line_price_vat'=>price2num($line->total_tva,2), 'line_date_start'=>$line->date_start, 'line_date_end'=>$line->date_end ); @@ -292,7 +292,7 @@ abstract class CommonDocGenerator { if($extrafields->attribute_type[$key] == 'price') { - $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]); + $object->array_options['options_'.$key] = price2num($object->array_options['options_'.$key],2); $object->array_options['options_'.$key.'_currency'] = $object->array_options['options_'.$key].' '.$outputlangs->getCurrencySymbol($conf->currency); //Add value to store price with currency $array_to_fill=array_merge($array_to_fill,array($array_key.'_options_'.$key.'_currency' => $object->array_options['options_'.$key.'_currency'])); diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index adf5c2ec2a6..957b5d85428 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -121,16 +121,16 @@ class doc_generic_invoice_odt extends ModelePDFFactures 'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), 'object_payment_term_code'=>$object->cond_reglement_code, 'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), - 'object_total_ht'=>price($object->total_ht,0,$outputlangs), - 'object_total_vat'=>price($object->total_tva,0,$outputlangs), - 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), - 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), + 'object_total_ht'=>price2num($object->total_ht,2), + 'object_total_vat'=>price2num($object->total_tva,2), + 'object_total_ttc'=>price2num($object->total_ttc,2), + 'object_total_discount_ht' => price2num($object->getTotalDiscount(), 0, $outputlangs), 'object_vatrate'=>(isset($object->tva)?vatrate($object->tva):''), 'object_note_private'=>$object->note, 'object_note'=>$object->note_public, // Payments 'object_already_payed'=>$alreadypayed, - 'object_remain_to_pay'=>price($object->total_ttc - $sumpayed,0,$outputlangs) + 'object_remain_to_pay'=>price2num($object->total_ttc - $sumpayed,2) ); // Add vat by rates @@ -174,9 +174,9 @@ class doc_generic_invoice_odt extends ModelePDFFactures 'line_up'=>price($line->subprice, 0, $outputlangs), 'line_qty'=>$line->qty, 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''), - 'line_price_ht'=>price($line->total_ht, 0, $outputlangs), - 'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs), - 'line_price_vat'=>price($line->total_tva, 0, $outputlangs), + 'line_price_ht'=>price2num($line->total_ht, 2), + 'line_price_ttc'=>price2num($line->total_ttc, 2), + 'line_price_vat'=>price2num($line->total_tva, 2), 'line_date_start'=>dol_print_date($line->date_start, 'day', false, $outputlangs), 'line_date_end'=>dol_print_date($line->date_end, 'day', false, $outputlangs), );