From f7afbcff6894a28445bea07439d8b8a2aff02038 Mon Sep 17 00:00:00 2001 From: phf Date: Mon, 18 Jan 2016 19:45:27 +0100 Subject: [PATCH] NEW integration of multicurrency module (creation fields in database and admin) NEW add multicurrency_code on create, update and fetch company object NEW add multicurrency on propal FIX travis FIX back quote into sql file --- htdocs/admin/multicurrency.php | 289 +++++++ htdocs/comm/propal.php | 81 ++ htdocs/comm/propal/class/propal.class.php | 92 ++- htdocs/core/class/commonobject.class.php | 99 ++- htdocs/core/class/html.form.class.php | 105 +++ htdocs/core/lib/multicurrency.lib.php | 54 ++ htdocs/core/lib/price.lib.php | 11 +- .../core/modules/modMultiCurrency.class.php | 290 +++++++ htdocs/core/tpl/objectline_create.tpl.php | 12 + htdocs/core/tpl/objectline_view.tpl.php | 9 +- .../install/mysql/migration/3.9.0-4.0.0.sql | 99 +++ htdocs/install/mysql/tables/llx_commande.sql | 8 +- .../mysql/tables/llx_commande_fournisseur.sql | 8 +- .../tables/llx_commande_fournisseurdet.sql | 9 +- .../install/mysql/tables/llx_commandedet.sql | 9 +- htdocs/install/mysql/tables/llx_facture.sql | 9 +- .../mysql/tables/llx_facture_fourn.sql | 8 +- .../mysql/tables/llx_facture_fourn_det.sql | 9 +- .../install/mysql/tables/llx_facturedet.sql | 8 +- .../mysql/tables/llx_multicurrency.sql | 28 + .../mysql/tables/llx_multicurrency_rate.sql | 28 + .../mysql/tables/llx_paiement_facture.sql | 6 +- .../tables/llx_paiementfourn_facturefourn.sql | 6 +- .../mysql/tables/llx_product_price.sql | 6 +- htdocs/install/mysql/tables/llx_propal.sql | 8 +- htdocs/install/mysql/tables/llx_propaldet.sql | 8 +- htdocs/install/mysql/tables/llx_societe.sql | 5 +- htdocs/langs/en_US/main.lang | 4 +- .../class/multicurrency.class.php | 726 ++++++++++++++++++ htdocs/societe/class/societe.class.php | 35 +- htdocs/societe/soc.php | 37 + .../theme/eldy/img/object_multicurrency.png | Bin 0 -> 733 bytes 32 files changed, 2080 insertions(+), 26 deletions(-) create mode 100644 htdocs/admin/multicurrency.php create mode 100644 htdocs/core/lib/multicurrency.lib.php create mode 100644 htdocs/core/modules/modMultiCurrency.class.php create mode 100644 htdocs/install/mysql/tables/llx_multicurrency.sql create mode 100644 htdocs/install/mysql/tables/llx_multicurrency_rate.sql create mode 100644 htdocs/multicurrency/class/multicurrency.class.php create mode 100644 htdocs/theme/eldy/img/object_multicurrency.png diff --git a/htdocs/admin/multicurrency.php b/htdocs/admin/multicurrency.php new file mode 100644 index 00000000000..b5485392816 --- /dev/null +++ b/htdocs/admin/multicurrency.php @@ -0,0 +1,289 @@ + + * Copyright (C) 2015 ATM Consulting + * + * 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 admin/multicurrency.php + * \ingroup quickpriceupdate + * \brief This file is an example module setup page + * Put some comments here + */ +// Dolibarr environment + +require '../main.inc.php'; + +// Libraries +dol_include_once('/core/lib/admin.lib.php'); +dol_include_once('/core/lib/multicurrency.lib.php'); +dol_include_once('/multicurrency/class/multicurrency.class.php'); + +// Translations +$langs->load("multicurrency"); + +// Access control +if (! $user->admin) { + accessforbidden(); +} + +// Parameters +$action = GETPOST('action', 'alpha'); + +/* + * Actions + */ +if (preg_match('/set_(.*)/',$action,$reg)) +{ + $code=$reg[1]; + if (dolibarr_set_const($db, $code, GETPOST($code), 'chaine', 0, '', $conf->entity) > 0) + { + header("Location: ".$_SERVER["PHP_SELF"]); + exit; + } + else + { + dol_print_error($db); + } +} + +if (preg_match('/del_(.*)/',$action,$reg)) +{ + $code=$reg[1]; + if (dolibarr_del_const($db, $code, 0) > 0) + { + Header("Location: ".$_SERVER["PHP_SELF"]); + exit; + } + else + { + dol_print_error($db); + } +} + +if ($action == 'add_currency') +{ + $code = GETPOST('code', 'alpha'); + $name = GETPOST('name', 'alpha'); + $rate = GETPOST('rate', 'alpha'); + + $currency = new MultiCurrency($db); + $currency->code = $code; + $currency->name = $name; + + if ($currency->create($user) > 0) + { + if ($currency->addRate($rate)) setEventMessages($langs->trans('SuccessAddRate'), array()); + else setEventMessages($langs->trans('ErrorAddRateFail'), array(), 'errors'); + } + else setEventMessages($langs->trans('ErrorAddCurrencyFail'), array()); +} +elseif ($action == 'update_currency') +{ + $submit = GETPOST('submit', 'alpha'); + + if ($submit == $langs->trans('Modify')) + { + $fk_multicurrency = GETPOST('fk_multicurrency', 'int'); + $rate = GETPOST('rate', 'float'); + $currency = new MultiCurrency($db); + + if ($currency->fetch($fk_multicurrency) > 0) + { + $currency->updateRate($rate); + } + } + elseif ($submit == $langs->trans('Delete')) + { + $fk_multicurrency = GETPOST('fk_multicurrency', 'int'); + $currency = new MultiCurrency($db); + + if ($currency->fetch($fk_multicurrency) > 0) + { + if ($currency->delete() > 0) setEventMessages($langs->trans('SuccessDeleteCurrency'), array()); + else setEventMessages($langs->trans('ErrorDeleteCurrencyFail'), array(), 'errors'); + } + } +} + +$TCurrency = array(); +$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'multicurrency WHERE entity = '.$conf->entity; +$resql = $db->query($sql); +if ($resql) +{ + while ($obj = $db->fetch_object($resql)) + { + $currency = new MultiCurrency($db); + $currency->fetch($obj->rowid); + $TCurrency[] = $currency; + } +} + +/* + * View + */ +$page_name = "multicurrency"; +llxHeader('', $langs->trans($page_name)); + +// Subheader +$linkback = '' + . $langs->trans("BackToModuleList") . ''; +print_fiche_titre($langs->trans($page_name), $linkback); + +// Configuration header +$head = multicurrencyAdminPrepareHead(); +dol_fiche_head( + $head, + 'settings', + $langs->trans("Module500000Name"), + 0, + "multicurrency" +); + +// Setup page goes here +$form=new Form($db); + +$var=false; +print ''; +print ''; +print ''."\n"; +print ''; +print ''."\n"; + +$var=!$var; +print ''; +print ''; +print ''; +print ''; + +$var=!$var; +print ''; +print ''; +print ''; +print ''; + +$var=!$var; +print ''; +print ''; +print ''; +print ''; + +$var=!$var; +print ''; +print ''; +print ''; +print ''; + +$var=!$var; +print ''; +print ''; +print ''; +print ''; + +$var=!$var; +print ''; +print ''; +print ''; +print ''; + +print '
'.$langs->trans("Parameters").' '.$langs->trans("Value").'
'.$langs->transnoentitiesnoconv("multicurrency_useRateOnInvoiceDate").' '; +print '
'; +print ''; +print ''; +print $form->selectyesno("MULTICURRENCY_USE_RATE_ON_INVOICE_DATE",$conf->global->MULTICURRENCY_USE_RATE_ON_INVOICE_DATE,1); +print ''; +print '
'; +print '
'.$langs->transnoentitiesnoconv("multicurrency_useOriginTx").' '; +print '
'; +print ''; +print ''; +print $form->selectyesno("MULTICURRENCY_USE_ORIGIN_TX",$conf->global->MULTICURRENCY_USE_ORIGIN_TX,1); +print ''; +print '
'; +print '
'.$langs->transnoentitiesnoconv("multicurrency_buyPriceInCurrency").' '; +print '
'; +print ''; +print ''; +print $form->selectyesno("MULTICURRENCY_BUY_PRICE_IN_CURRENCY",$conf->global->MULTICURRENCY_BUY_PRICE_IN_CURRENCY,1); +print ''; +print '
'; +print '
'.$langs->transnoentitiesnoconv("multicurrency_modifyRateApplication").' '; +print '
'; +print ''; +print ''; +print $form->selectarray('MULTICURRENCY_MODIFY_RATE_APPLICATION', array('PU_DOLIBARR' => 'PU_DOLIBARR', 'PU_CURRENCY' => 'PU_CURRENCY')); +print ''; +print '
'; +print '
'.$langs->transnoentitiesnoconv("multicurrency_appId").' '; +print '
'; +print ''; +print ''; +print ' '; +print ''; +print '
'; +print '
'.$langs->transnoentitiesnoconv("multicurrency_currencyFromToRate").' '; +print '
'; +print ''; +print ''; +print ' '; // CURRENCY_BASE - CURRENCY_ENTITY - ID_ENTITY +print ''; +print '
'; +print '
'; + +print ''; + +print '
'; +print ''; + +print ''; +print ''."\n"; +print ''; +print ''."\n"; + +$var=!$var; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +foreach ($TCurrency as &$currency) +{ + $var=!$var; + print ''; + print ''; + print ''; + print ''; +} + +print '
'.$langs->trans("Currencies").' '.$langs->trans("Rate").'
-  '; +print ' '; +print ''; +print '
'.$currency->code.' - '.$currency->name.' '; + print '
'; + print ''; + print ''; + print ''; + print ' '; + print ' '; + print ''; + print '
'; + print '
'; + +llxFooter(); + +$db->close(); \ No newline at end of file diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index e039342dd38..d83beedc9c5 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -344,6 +344,12 @@ if (empty($reshook)) $object->origin = GETPOST('origin'); $object->origin_id = GETPOST('originid'); + + // Multicurrency + if (!empty($conf->multicurrency->enabled)) + { + $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); + } for($i = 1; $i <= $conf->global->PRODUCT_SHOW_WHEN_CREATE; $i ++) { @@ -1084,6 +1090,16 @@ if (empty($reshook)) $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int')); } + // Multicurrency Code + else if ($action == 'setmulticurrencycode' && $user->rights->propal->creer) { + $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha')); + } + + // Multicurrency rate + else if ($action == 'setmulticurrencyrate' && $user->rights->propal->creer) { + $result = $object->setMulticurrencyRate(GETPOST('multicurrency_tx', 'int')); + } + // bank account else if ($action == 'setbankaccount' && $user->rights->propal->creer) { $result=$object->setBankAccount(GETPOST('fk_account', 'int')); @@ -1422,6 +1438,17 @@ if ($action == 'create') print $form->selectarray('model', $liste, ($conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT ? $conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT : $conf->global->PROPALE_ADDON_PDF)); print ""; + // Multicurrency + if (! empty($conf->multicurrency->enabled)) + { + print ''; + print ''.fieldLabel('Currency','multicurrency_code').''; + print ''; + $currency_code = (!empty($soc->multicurrency_code) ? $soc->multicurrency_code : ($object->multicurrency_code ? $object->multicurrency_code : $conf->currency)); + print $form->selectMultiCurrency($currency_code, 'multicurrency_code'); + print ''; + } + // Public note print ''; print '' . $langs->trans('NotePublic') . ''; @@ -1991,6 +2018,45 @@ if ($action == 'create') print ''; } + // Multicurrency + if (! empty($conf->multicurrency->enabled)) + { + // Multicurrency code + print ''; + print ''; + print ''; + if ($action != 'editmulticurrencycode' && ! empty($object->brouillon)) + print ''; + print '
'; + print fieldLabel('Currency','multicurrency_code'); + print 'id . '">' . img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1) . '
'; + print ''; + if ($action == 'editmulticurrencycode') { + $form->form_multicurrency_code($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->multicurrency_code, 'multicurrency_code'); + } else { + $form->form_multicurrency_code($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->multicurrency_code, 'none'); + } + print ''; + + // Multicurrency rate + print ''; + print ''; + print ''; + if ($action != 'editmulticurrencyrate' && ! empty($object->brouillon)) + print ''; + print '
'; + print fieldLabel('Rate','multicurrency_tx'); + print 'id . '">' . img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1) . '
'; + print ''; + if ($action == 'editmulticurrencyrate') { + $form->form_multicurrency_rate($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->multicurrency_tx, 'multicurrency_tx'); + } else { + $form->form_multicurrency_rate($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->multicurrency_tx, 'none'); + } + print ''; + } + + // Other attributes $cols = 5; include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; @@ -2034,6 +2100,21 @@ if ($action == 'create') print '' . $langs->trans('AmountTTC') . ''; print '' . price($object->total_ttc, '', $langs, 0, - 1, - 1, $conf->currency) . ''; print ''; + + // Multicurrency Amount HT + print '' . fieldLabel('MulticurrencyAmountHT','multicurrency_total_ht') . ''; + print '' . price($object->multicurrency_total_ht, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)) . ''; + print ''; + + // Multicurrency Amount VAT + print '' . fieldLabel('MulticurrencyAmountVAT','multicurrency_total_tva') . ''; + print '' . price($object->multicurrency_total_tva, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)) . ''; + print ''; + + // Multicurrency Amount TTC + print '' . fieldLabel('MulticurrencyAmountTTC','multicurrency_total_ttc') . ''; + print '' . price($object->multicurrency_total_ttc, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)) . ''; + print ''; // Statut print '' . $langs->trans('Status') . '' . $object->getLibStatut(4) . ''; diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index b530b011d81..d9ba1e7ef59 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -37,6 +37,7 @@ require_once DOL_DOCUMENT_ROOT ."/core/class/commonobjectline.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'; +dol_include_once('/multicurrency/class/multicurrency.class.php'); /** * Class to manage proposals @@ -156,6 +157,14 @@ class Propal extends CommonObject var $specimen; + // Multicurrency + var $fk_multicurrency; + var $multicurrency_code; + var $multicurrency_tx; + var $multicurrency_total_ht; + var $multicurrency_total_tva; + var $multicurrency_total_ttc; + /** * Draft status */ @@ -441,7 +450,7 @@ class Propal extends CommonObject $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc); $txtva = preg_replace('/\s*\(.*\)/','',$txtva); // Remove code into vatrate. - $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type); + $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx); $total_ht = $tabprice[0]; $total_tva = $tabprice[1]; @@ -449,6 +458,11 @@ class Propal extends CommonObject $total_localtax1 = $tabprice[9]; $total_localtax2 = $tabprice[10]; + // MultiCurrency + $multicurrency_total_ht = $tabprice[16]; + $multicurrency_total_tva = $tabprice[17]; + $multicurrency_total_ttc = $tabprice[18]; + // Rang to use $rangtouse = $rang; if ($rangtouse == -1) @@ -505,6 +519,14 @@ class Propal extends CommonObject $this->line->origin_id = $origin_id; $this->line->origin = $origin; + // Multicurrency + $this->line->fk_multicurrency = $this->fk_multicurrency; + $this->line->multicurrency_code = $this->multicurrency_code; + $this->line->multicurrency_subprice = price2num($pu_ht * $this->multicurrency_tx); + $this->line->multicurrency_total_ht = $multicurrency_total_ht; + $this->line->multicurrency_total_tva = $multicurrency_total_tva; + $this->line->multicurrency_total_ttc = $multicurrency_total_ttc; + // Mise en option de la ligne if (empty($qty) && empty($special_code)) $this->line->special_code=3; @@ -756,6 +778,14 @@ class Propal extends CommonObject if (empty($this->availability_id)) $this->availability_id=0; if (empty($this->demand_reason_id)) $this->demand_reason_id=0; + if (!empty($this->multicurrency_code)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code); + if (empty($this->fk_multicurrency)) + { + $this->multicurrency_code = ''; + $this->fk_multicurrency = 0; + $this->multicurrency_tx = 1; + } + dol_syslog(get_class($this)."::create"); // Check parameters @@ -819,6 +849,9 @@ class Propal extends CommonObject $sql.= ", fk_incoterms"; $sql.= ", location_incoterms"; $sql.= ", entity"; + $sql.= ", fk_multicurrency"; + $sql.= ", multicurrency_code"; + $sql.= ", multicurrency_tx"; $sql.= ") "; $sql.= " VALUES ("; $sql.= $this->socid; @@ -848,6 +881,9 @@ class Propal extends CommonObject $sql.= ", ".(int) $this->fk_incoterms; $sql.= ", '".$this->db->escape($this->location_incoterms)."'"; $sql.= ", ".$conf->entity; + $sql.= ", ".(int) $this->fk_multicurrency; + $sql.= ", '".$this->db->escape($this->multicurrency_code)."'"; + $sql.= ", ".(double) $this->multicurrency_tx; $sql.= ")"; dol_syslog(get_class($this)."::create", LOG_DEBUG); @@ -1184,6 +1220,7 @@ class Propal extends CommonObject $sql.= ', p.fk_account'; $sql.= ", p.fk_shipping_method"; $sql.= ", p.fk_incoterms, p.location_incoterms"; + $sql.= ", p.fk_multicurrency, p.multicurrency_code, p.multicurrency_tx, p.multicurrency_total_ht, p.multicurrency_total_tva, p.multicurrency_total_ttc"; $sql.= ", i.libelle as libelle_incoterms"; $sql.= ", c.label as statut_label"; $sql.= ", ca.code as availability_code, ca.label as availability"; @@ -1268,6 +1305,14 @@ class Propal extends CommonObject $this->location_incoterms = $obj->location_incoterms; $this->libelle_incoterms = $obj->libelle_incoterms; + // Multicurrency + $this->fk_multicurrency = $obj->fk_multicurrency; + $this->multicurrency_code = $obj->multicurrency_code; + $this->multicurrency_tx = $obj->multicurrency_tx; + $this->multicurrency_total_ht = $obj->multicurrency_total_ht; + $this->multicurrency_total_tva = $obj->multicurrency_total_tva; + $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc; + if ($obj->fk_statut == self::STATUS_DRAFT) { $this->brouillon = 1; @@ -1292,6 +1337,7 @@ class Propal extends CommonObject $sql.= " d.fk_unit,"; $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.= ' ,d.fk_multicurrency, d.multicurrency_code, d.multicurrency_subprice, d.multicurrency_total_ht, d.multicurrency_total_tva, d.multicurrency_total_ttc'; $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; @@ -1357,6 +1403,15 @@ class Propal extends CommonObject $line->date_start = $objp->date_start; $line->date_end = $objp->date_end; + + // Multicurrency + $line->fk_multicurrency = $objp->fk_multicurrency; + $line->multicurrency_code = $objp->multicurrency_code; + $line->multicurrency_subprice = $objp->multicurrency_subprice; + $line->multicurrency_total_ht = $objp->multicurrency_total_ht; + $line->multicurrency_total_tva = $objp->multicurrency_total_tva; + $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc; + $line->fetch_optionals($line->id,$extralabelsline); $this->lines[$i] = $line; @@ -2785,6 +2840,7 @@ class Propal extends CommonObject $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,'; $sql.= ' p.description as product_desc,'; $sql.= ' p.entity'; + $sql.= ' ,pt.fk_multicurrency, pt.multicurrency_code, pt.multicurrency_subprice, pt.multicurrency_total_ht, pt.multicurrency_total_tva, pt.multicurrency_total_ttc'; $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; @@ -2833,6 +2889,14 @@ class Propal extends CommonObject $this->lines[$i]->date_start = $this->db->jdate($obj->date_start); $this->lines[$i]->date_end = $this->db->jdate($obj->date_end); $this->lines[$i]->fk_unit = $obj->fk_unit; + + // Multicurrency + $this->lines[$i]->fk_multicurrency = $obj->fk_multicurrency; + $this->lines[$i]->multicurrency_code = $obj->multicurrency_code; + $this->lines[$i]->multicurrency_subprice = $obj->multicurrency_subprice; + $this->lines[$i]->multicurrency_total_ht = $obj->multicurrency_total_ht; + $this->lines[$i]->multicurrency_total_tva = $obj->multicurrency_total_tva; + $this->lines[$i]->multicurrency_total_ttc = $obj->multicurrency_total_ttc; $i++; } @@ -3003,6 +3067,14 @@ class PropaleLigne extends CommonObjectLine var $skip_update_total; // Skip update price total for special lines + // Multicurrency + var $fk_multicurrency; + var $multicurrency_code; + var $multicurrency_subprice; + var $multicurrency_total_ht; + var $multicurrency_total_tva; + var $multicurrency_total_ttc; + /** * Class line Contructor * @@ -3026,6 +3098,7 @@ class PropaleLigne extends CommonObjectLine $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.fk_unit,'; $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,'; + $sql.= ' pd.fk_multicurrency, pd.multicurrency_code, pd.multicurrency_subprice, pd.multicurrency_total_ht, pd.multicurrency_total_tva, pd.multicurrency_total_ttc,'; $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'; @@ -3078,6 +3151,14 @@ class PropaleLigne extends CommonObjectLine $this->date_start = $this->db->jdate($objp->date_start); $this->date_end = $this->db->jdate($objp->date_end); + // Multicurrency + $this->fk_multicurrency = $objp->fk_multicurrency; + $this->multicurrency_code = $objp->multicurrency_code; + $this->multicurrency_subprice = $objp->multicurrency_subprice; + $this->multicurrency_total_ht = $objp->multicurrency_total_ht; + $this->multicurrency_total_tva = $objp->multicurrency_total_tva; + $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc; + $this->db->free($result); return 1; @@ -3148,7 +3229,8 @@ class PropaleLigne extends CommonObjectLine $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.= ' fk_unit,'; - $sql.= ' date_start, date_end)'; + $sql.= ' date_start, date_end'; + $sql.= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc)'; $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").","; @@ -3177,6 +3259,12 @@ class PropaleLigne extends CommonObjectLine $sql.= ' '.(!$this->fk_unit ? 'NULL' : $this->fk_unit).','; $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.= ", ".$this->fk_multicurrency; + $sql.= ", '".$this->db->escape($this->multicurrency_code)."'"; + $sql.= ", ".$this->multicurrency_subprice; + $sql.= ", ".$this->multicurrency_total_ht; + $sql.= ", ".$this->multicurrency_total_tva; + $sql.= ", ".$this->multicurrency_total_ttc; $sql.= ')'; dol_syslog(get_class($this).'::insert', LOG_DEBUG); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 6b19a8ebe44..3e04f98574d 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -1414,6 +1414,80 @@ abstract class CommonObject } } + /** + * Change the multicurrency code + * + * @param string $code multicurrency code + * @return int >0 if OK, <0 if KO + */ + function setMulticurrencyCode($code) + { + dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')'); + if ($this->statut >= 0 || $this->element == 'societe') + { + $fieldname = 'multicurrency_code'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET '.$fieldname.' = "'.$this->db->escape($code).'"'; + $sql .= ' WHERE rowid='.$this->id; + + if ($this->db->query($sql)) + { + $this->multicurrency_code = $code; + return 1; + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible'); + $this->error='Status of the object is incompatible '.$this->statut; + return -2; + } + } + + /** + * Change the multicurrency rate + * + * @param double $rate multicurrency rate + * @return int >0 if OK, <0 if KO + */ + function setMulticurrencyRate($rate) + { + dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')'); + if ($this->statut >= 0 || $this->element == 'societe') + { + $fieldname = 'multicurrency_tx'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET '.$fieldname.' = '.$rate; + $sql .= ' WHERE rowid='.$this->id; + + if ($this->db->query($sql)) + { + $this->multicurrency_tx = $rate; + return 1; + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible'); + $this->error='Status of the object is incompatible '.$this->statut; + return -2; + } + } + /** * Change the payments terms * @@ -2076,6 +2150,7 @@ abstract class CommonObject $sql = 'SELECT rowid, qty, '.$fieldup.' as up, remise_percent, total_ht, '.$fieldtva.' as total_tva, total_ttc, '.$fieldlocaltax1.' as total_localtax1, '.$fieldlocaltax2.' as total_localtax2,'; $sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type'; if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent'; + $sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc'; $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line; $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; if ($exclspec) @@ -2098,6 +2173,9 @@ abstract class CommonObject $total_ht_by_vats = array(); $total_tva_by_vats = array(); $total_ttc_by_vats = array(); + $this->multicurrency_total_ht = 0; + $this->multicurrency_total_tva = 0; + $this->multicurrency_total_ttc = 0; $num = $this->db->num_rows($resql); $i = 0; @@ -2106,11 +2184,11 @@ abstract class CommonObject $obj = $this->db->fetch_object($resql); // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none' - + $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1; if ($forcedroundingmode == '0') // Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto' { $localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx); - $tmpcal=calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100)); + $tmpcal=calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100), $multicurrency_tx); $diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1); if ($diff) { @@ -2129,6 +2207,7 @@ abstract class CommonObject $this->total_localtax1 += $obj->total_localtax1; $this->total_localtax2 += $obj->total_localtax2; $this->total_ttc += $obj->total_ttc; + if (! isset($total_ht_by_vats[$obj->vatrate])) $total_ht_by_vats[$obj->vatrate]=0; if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0; if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0; @@ -2174,7 +2253,12 @@ abstract class CommonObject $this->total_ttc -= $sit->total_ttc; } } - + + // Multicurrency + $this->multicurrency_total_ht += $this->total_ht * $multicurrency_tx; + $this->multicurrency_total_tva += $this->total_tva * $multicurrency_tx; + $this->multicurrency_total_ttc += $this->total_ttc * $multicurrency_tx; + $this->db->free($resql); // Now update global field total_ht, total_ttc and tva @@ -2198,6 +2282,9 @@ abstract class CommonObject $sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',"; $sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',"; $sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'"; + $sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'"; + $sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'"; + $sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'"; $sql .= ' WHERE rowid = '.$this->id; //print "xx".$sql; @@ -3062,6 +3149,9 @@ abstract class CommonObject // Price HT print ''.$langs->trans('PriceUHT').''; + // Multicurrency + if (!empty($conf->multicurrency->enabled)) print ''.$langs->trans('PriceUHTCurrency').''; + if ($inputalsopricewithtax) print ''.$langs->trans('PriceUTTC').''; // Qty @@ -3095,6 +3185,9 @@ abstract class CommonObject // Total HT print ''.$langs->trans('TotalHTShort').''; + // Multicurrency + if (!empty($conf->multicurrency->enabled)) print ''.$langs->trans('TotalHTShortCurrency').''; + print ''; // No width to allow autodim print ''; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index e081d902b16..c9f9bbe9d03 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -3722,6 +3722,65 @@ class Form } } } + + /** + * Show form with multicurrency code + * + * @param string $page Page + * @param string $selected code pre-selectionne + * @param string $htmlname Name of select html field + * @return void + */ + function form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code') + { + global $langs; + if ($htmlname != "none") + { + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print $this->selectMultiCurrency($selected,$htmlname); + print '
'; + } + else + { + dol_include_once('/core/lib/company.lib.php'); + print !empty($selected) ? currency_name($selected,1) : ' '; + } + } + + /** + * Show form with multicurrency rate + * + * @param string $page Page + * @param double $rate Current rate + * @param string $htmlname Name of select html field + * @return void + */ + function form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx') + { + global $langs; + if ($htmlname != "none") + { + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print ''; + print '
'; + } + else + { + print !empty($rate) ? $rate : 1; + } + } /** @@ -3925,7 +3984,53 @@ class Form return $out; } + /** + * Return array of currencies in user language + * + * @param string $selected preselected currency code + * @param string $htmlname name of HTML select list + * @param integer $useempty 1=Add empty line + * @return string + */ + function selectMultiCurrency($selected='',$htmlname='multicurrency_code', $useempty=0) + { + global $db,$conf,$langs,$user; + $langs->loadCacheCurrencies(''); + + $TCurrency = array(); + + $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency'; + $resql = $db->query($sql); + + if ($resql) + { + while ($obj = $db->fetch_object($resql)) $TCurrency[$obj->code] = $obj->code; + } + + $out=''; + $out.= ''; + return $out; + } + /** * Load into the cache vat rates of a country * diff --git a/htdocs/core/lib/multicurrency.lib.php b/htdocs/core/lib/multicurrency.lib.php new file mode 100644 index 00000000000..c3844309dd5 --- /dev/null +++ b/htdocs/core/lib/multicurrency.lib.php @@ -0,0 +1,54 @@ + + * Copyright (C) 2015 ATM Consulting + * + * 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 lib/multicurrency.lib.php + * \ingroup multicurency + * \brief This file is an example module library + * Put some comments here + */ + +/** + * Prepare array with list of tabs + * + * @return array Array of tabs to show + */ +function multicurrencyAdminPrepareHead() +{ + global $langs, $conf; + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/admin/multicurrency.php", 1); + $head[$h][1] = $langs->trans("Parameters"); + $head[$h][2] = 'settings'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@quickpriceupdate:/quickpriceupdate/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@quickpriceupdate:/quickpriceupdate/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'multicurrency'); + + return $head; +} diff --git a/htdocs/core/lib/price.lib.php b/htdocs/core/lib/price.lib.php index 528abfcd6a5..d6ab9f51fab 100644 --- a/htdocs/core/lib/price.lib.php +++ b/htdocs/core/lib/price.lib.php @@ -49,6 +49,7 @@ * @param Societe $seller Thirdparty seller (we need $seller->country_id property). Provided only if seller is the supplier, otherwise $seller will be $mysoc. * @param array $localtaxes_array Array with localtaxes info (loaded by getLocalTaxesFromRate(vatrate, 0, ...) function). * @param integer $progress Situation invoices progress (value from 0 to 100, 100 by default) + * @param double $multicurrency_tx Currency rate (1 by default) * @return result[ 0=total_ht, * 1=total_vat, (main vat only) * 2=total_ttc, (total_ht + main vat + local taxes) @@ -65,8 +66,11 @@ * 13=!! should not be used * 14=total_tax1 for total_ht_without_discount, * 15=total_tax2 for total_ht_without_discount] + * 16=multicurrency_total_ht + * 17=multicurrency_total_tva + * 18=multicurrency_total_ttc */ -function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller = '', $localtaxes_array='', $progress=100) +function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller = '', $localtaxes_array='', $progress=100, $multicurrency_tx=1) { global $conf,$mysoc,$db; @@ -242,6 +246,11 @@ function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocalt $result[4] = price2num($result[5] - ($result3bis + $localtaxes[2]), 'MU'); } + // Multicurrency + $result[16] = price2num($result[0] * $multicurrency_tx, 'MT'); + $result[17] = price2num($result[1] * $multicurrency_tx, 'MT'); + $result[18] = price2num($result[2] * $multicurrency_tx, 'MT'); + // if there's some localtax without vat, we calculate localtaxes (we will add them at end) //If input unit price is 'TTC', we need to have the totals without main VAT for a correct calculation diff --git a/htdocs/core/modules/modMultiCurrency.class.php b/htdocs/core/modules/modMultiCurrency.class.php new file mode 100644 index 00000000000..6642e33719f --- /dev/null +++ b/htdocs/core/modules/modMultiCurrency.class.php @@ -0,0 +1,290 @@ + + * Copyright (C) 2004-2015 Laurent Destailleur + * Copyright (C) 2005-2016 Regis Houssin + * Copyright (C) 2016 Pierre-Henry Favre + * + * 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 multicurrency Module MultiCurrency + * \brief Handle multiple currencies on company/propal/orders ... + * \file htdocs/core/modules/modMultiCurrency.class.php + * \ingroup multicurrency + * \brief Description and activation file for module MultiCurrency + */ +include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; + + +/** + * Description and activation class for module MyModule + */ +class modMultiCurrency extends DolibarrModules +{ + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $langs,$conf; + + $this->db = $db; + + // Id for module (must be unique). + // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). + $this->numero = 500000; // TODO Go on page http://wiki.dolibarr.org/index.php/List_of_modules_id to reserve id number for your module + // Key text used to identify module (for permissions, menus, etc...) + $this->rights_class = 'multicurrency'; + + // Family can be 'crm','financial','hr','projects','products','ecm','technic','other' + // It is used to group modules in module setup page + $this->family = "financial"; + // Module position in the family + $this->module_position = 500; + // Gives the possibility to the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this) + $this->familyinfo = array('financial' => array('position'=>'009', 'label'=>$langs->trans("ModuleFamilyFinancial"))); + + // 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)); + // Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module) + $this->description = "Description of module MyModule"; + + // Possible values for version are: 'development', 'experimental', 'dolibarr' or 'dolibarr_deprecated' or version + $this->version = 'development'; + // Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase) + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + // Where to store the module in setup page (0=common,1=interface,2=others,3=very specific) + $this->special = 0; + // Name of image file used for this module. + // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' + // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' + $this->picto='multicurrency'; + + // Defined all module parts (triggers, login, substitutions, menus, css, etc...) + // for default path (eg: /multicurrency/core/xxxxx) (0=disable, 1=enable) + // for specific path of parts (eg: /multicurrency/core/modules/barcode) + // for specific css file (eg: /multicurrency/css/multicurrency.css.php) + //$this->module_parts = array( + // 'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers) + // 'login' => 0, // Set this to 1 if module has its own login method directory (core/login) + // 'substitutions' => 0, // Set this to 1 if module has its own substitution function file (core/substitutions) + // 'menus' => 0, // Set this to 1 if module has its own menus handler directory (core/menus) + // 'theme' => 0, // Set this to 1 if module has its own theme directory (theme) + // 'tpl' => 0, // Set this to 1 if module overwrite template dir (core/tpl) + // 'barcode' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode) + // 'models' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx) + // 'css' => array('/multicurrency/css/multicurrency.css.php'), // Set this to relative path of css file if module has its own css file + // 'js' => array('/multicurrency/js/multicurrency.js'), // Set this to relative path of js file if module must load a js on all pages + // 'hooks' => array('hookcontext1','hookcontext2') // Set here all hooks context managed by module + // 'dir' => array('output' => 'othermodulename'), // To force the default directories names + // 'workflow' => array('WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2'=>array('enabled'=>'! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)', 'picto'=>'yourpicto@multicurrency')) // Set here all workflow context managed by module + // ); + $this->module_parts = array(); + + // Data directories to create when module is enabled. + // Example: this->dirs = array("/multicurrency/temp"); + $this->dirs = array(); + + // Config pages. Put here list of php page, stored into multicurrency/admin directory, to use to setup module. + $this->config_page_url = array("multicurrency.php"); + + // Dependencies + $this->hidden = false; // A condition to hide module + $this->depends = array(); // List of modules id that must be enabled if this module is enabled + $this->requiredby = array(); // List of modules id to disable if this one is disabled + $this->conflictwith = array(); // List of modules id this module is in conflict with + $this->phpmin = array(5,0); // Minimum version of PHP required by module + $this->need_dolibarr_version = array(3,0); // Minimum version of Dolibarr required by module + $this->langfiles = array("multicurrency"); + + // Constants + // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) + // Example: $this->const=array(0=>array('MYMODULE_MYNEWCONST1','chaine','myvalue','This is a constant to add',1), + // 1=>array('MYMODULE_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1) + // ); + $this->const = array(); + + // Array to add new pages in new tabs + // Example: $this->tabs = array('objecttype:+tabname1:Title1:mylangfile@multicurrency:$user->rights->multicurrency->read:/multicurrency/mynewtab1.php?id=__ID__', // To add a new tab identified by code tabname1 + // 'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@multicurrency:$user->rights->othermodule->read:/multicurrency/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. + // 'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname + // where objecttype can be + // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) + // 'contact' to add a tab in contact view + // 'contract' to add a tab in contract view + // 'group' to add a tab in group view + // 'intervention' to add a tab in intervention view + // 'invoice' to add a tab in customer invoice view + // 'invoice_supplier' to add a tab in supplier invoice view + // 'member' to add a tab in fundation member view + // 'opensurveypoll' to add a tab in opensurvey poll view + // 'order' to add a tab in customer order view + // 'order_supplier' to add a tab in supplier order view + // 'payment' to add a tab in payment view + // 'payment_supplier' to add a tab in supplier payment view + // 'product' to add a tab in product view + // 'propal' to add a tab in propal view + // 'project' to add a tab in project view + // 'stock' to add a tab in stock view + // 'thirdparty' to add a tab in third party view + // 'user' to add a tab in user view + $this->tabs = array(); + + // Dictionaries + if (! isset($conf->multicurrency->enabled)) + { + $conf->multicurrency=new stdClass(); + $conf->multicurrency->enabled=0; + } + $this->dictionaries=array(); + /* Example: + if (! isset($conf->multicurrency->enabled)) $conf->multicurrency->enabled=0; // This is to avoid warnings + $this->dictionaries=array( + 'langs'=>'mylangfile@multicurrency', + 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor + 'tablib'=>array("Table1","Table2","Table3"), // Label of tables + 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields + 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order + 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary) + 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record) + 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert) + 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid') + 'tabcond'=>array($conf->multicurrency->enabled,$conf->multicurrency->enabled,$conf->multicurrency->enabled) // Condition to show each dictionary + ); + */ + + // Boxes + // Add here list of php file(s) stored in core/boxes that contains class to show a box. + $this->boxes = array(); // List of boxes + // Example: + //$this->boxes=array( + // 0=>array('file'=>'myboxa.php@multicurrency','note'=>'','enabledbydefaulton'=>'Home'), + // 1=>array('file'=>'myboxb.php@multicurrency','note'=>''), + // 2=>array('file'=>'myboxc.php@multicurrency','note'=>'') + //); + + // Cronjobs + $this->cronjobs = array(); // List of cron jobs entries to add + // Example: $this->cronjobs=array(0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>3600, 'unitfrequency'=>3600), + // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>3600, 'unitfrequency'=>3600) + // ); + + // Permissions + $this->rights = array(); // Permission array used by this module + $r=0; + + // Add here list of permission defined by an id, a label, a boolean and two constant strings. + // Example: + // $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) + // $this->rights[$r][1] = 'Permision label'; // Permission label + // $this->rights[$r][3] = 1; // Permission by default for new user (0/1) + // $this->rights[$r][4] = 'level1'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + // $this->rights[$r][5] = 'level2'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + // $r++; + + // Main menu entries + $this->menu = array(); // List of menus to add + $r=0; + + // Add here entries to declare new menus + // + // Example to declare a new Top Menu entry and its Left menu entry: + // $this->menu[$r]=array( 'fk_menu'=>'', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + // 'type'=>'top', // This is a Top menu entry + // 'titre'=>'MyModule top menu', + // 'mainmenu'=>'multicurrency', + // 'leftmenu'=>'multicurrency', + // 'url'=>'/multicurrency/pagetop.php', + // 'langs'=>'mylangfile@multicurrency', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + // 'position'=>100, + // 'enabled'=>'$conf->multicurrency->enabled', // Define condition to show or hide menu entry. Use '$conf->multicurrency->enabled' if entry must be visible if module is enabled. + // 'perms'=>'1', // Use 'perms'=>'$user->rights->multicurrency->level1->level2' if you want your menu with a permission rules + // 'target'=>'', + // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + // $r++; + // + // Example to declare a Left Menu entry into an existing Top menu entry: + // $this->menu[$r]=array( 'fk_menu'=>'fk_mainmenu=xxx', // '' if this is a top menu. For left menu, 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'=>'MyModule left menu', + // 'mainmenu'=>'xxx', + // 'leftmenu'=>'multicurrency', + // 'url'=>'/multicurrency/pagelevel2.php', + // 'langs'=>'mylangfile@multicurrency', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + // 'position'=>100, + // 'enabled'=>'$conf->multicurrency->enabled', // Define condition to show or hide menu entry. Use '$conf->multicurrency->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + // 'perms'=>'1', // Use 'perms'=>'$user->rights->multicurrency->level1->level2' if you want your menu with a permission rules + // 'target'=>'', + // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + // $r++; + + + // Exports + $r=1; + + // Example: + // $this->export_code[$r]=$this->rights_class.'_'.$r; + // $this->export_label[$r]='MyModule'; // Translation key (used only if key ExportDataset_xxx_z not found) + // $this->export_enabled[$r]='1'; // Condition to show export in list (ie: '$user->id==3'). Set to 1 to always show when module is enabled. + // $this->export_icon[$r]='generic:MyModule'; + // $this->export_permission[$r]=array(array("multicurrency","level1","level2")); + // $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','s.fk_pays'=>'Country','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.code_compta'=>'CustomerAccountancyCode','s.code_compta_fournisseur'=>'SupplierAccountancyCode','f.rowid'=>"InvoiceId",'f.facnumber'=>"InvoiceRef",'f.datec'=>"InvoiceDateCreation",'f.datef'=>"DateInvoice",'f.total'=>"TotalHT",'f.total_ttc'=>"TotalTTC",'f.tva'=>"TotalVAT",'f.paye'=>"InvoicePaid",'f.fk_statut'=>'InvoiceStatus','f.note'=>"InvoiceNote",'fd.rowid'=>'LineId','fd.description'=>"LineDescription",'fd.price'=>"LineUnitPrice",'fd.tva_tx'=>"LineVATRate",'fd.qty'=>"LineQty",'fd.total_ht'=>"LineTotalHT",'fd.total_tva'=>"LineTotalTVA",'fd.total_ttc'=>"LineTotalTTC",'fd.date_start'=>"DateStart",'fd.date_end'=>"DateEnd",'fd.fk_product'=>'ProductId','p.ref'=>'ProductRef'); + // $this->export_TypeFields_array[$r]=array('t.date'=>'Date', 't.qte'=>'Numeric', 't.poids'=>'Numeric', 't.fad'=>'Numeric', 't.paq'=>'Numeric', 't.stockage'=>'Numeric', 't.fadparliv'=>'Numeric', 't.livau100'=>'Numeric', 't.forfait'=>'Numeric', 's.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text','c.code'=>'Text','s.phone'=>'Text','s.siren'=>'Text','s.siret'=>'Text','s.ape'=>'Text','s.idprof4'=>'Text','s.code_compta'=>'Text','s.code_compta_fournisseur'=>'Text','s.tva_intra'=>'Text','f.facnumber'=>"Text",'f.datec'=>"Date",'f.datef'=>"Date",'f.date_lim_reglement'=>"Date",'f.total'=>"Numeric",'f.total_ttc'=>"Numeric",'f.tva'=>"Numeric",'f.paye'=>"Boolean",'f.fk_statut'=>'Status','f.note_private'=>"Text",'f.note_public'=>"Text",'fd.description'=>"Text",'fd.subprice'=>"Numeric",'fd.tva_tx'=>"Numeric",'fd.qty'=>"Numeric",'fd.total_ht'=>"Numeric",'fd.total_tva'=>"Numeric",'fd.total_ttc'=>"Numeric",'fd.date_start'=>"Date",'fd.date_end'=>"Date",'fd.special_code'=>'Numeric','fd.product_type'=>"Numeric",'fd.fk_product'=>'List:product:label','p.ref'=>'Text','p.label'=>'Text','p.accountancy_code_sell'=>'Text'); + // $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.siret'=>'company','s.ape'=>'company','s.idprof4'=>'company','s.code_compta'=>'company','s.code_compta_fournisseur'=>'company','f.rowid'=>"invoice",'f.facnumber'=>"invoice",'f.datec'=>"invoice",'f.datef'=>"invoice",'f.total'=>"invoice",'f.total_ttc'=>"invoice",'f.tva'=>"invoice",'f.paye'=>"invoice",'f.fk_statut'=>'invoice','f.note'=>"invoice",'fd.rowid'=>'invoice_line','fd.description'=>"invoice_line",'fd.price'=>"invoice_line",'fd.total_ht'=>"invoice_line",'fd.total_tva'=>"invoice_line",'fd.total_ttc'=>"invoice_line",'fd.tva_tx'=>"invoice_line",'fd.qty'=>"invoice_line",'fd.date_start'=>"invoice_line",'fd.date_end'=>"invoice_line",'fd.fk_product'=>'product','p.ref'=>'product'); + // $this->export_dependencies_array[$r]=array('invoice_line'=>'fd.rowid','product'=>'fd.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.'facture as f, '.MAIN_DB_PREFIX.'facturedet as fd, '.MAIN_DB_PREFIX.'societe as s)'; + // $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (fd.fk_product = p.rowid)'; + // $this->export_sql_end[$r] .=' WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture'; + // $this->export_sql_order[$r] .=' ORDER BY s.nom'; + // $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 + */ + public function init($options='') + { + $sql = array(); + + //$this->_load_tables('/multicurrency/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 + */ + public function remove($options = '') + { + $sql = array(); + + return $this->_remove($sql, $options); + } + +} + diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index e17648a7643..ba1f037370e 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -61,6 +61,9 @@ if (in_array($object->element,array('propal', 'supplier_proposal','facture','inv trans('VAT'); ?> trans('PriceUHT'); ?> + multicurrency->enabled)) { $colspan++;?> + trans('PriceUHTCurrency'); ?> + trans('PriceUTTC'); ?> @@ -227,6 +230,13 @@ else { "> + + multicurrency->enabled)) { $colspan++;?> + + "> + + + "> @@ -354,6 +364,8 @@ if ((! empty($conf->service->enabled) || ($object->element == 'contrat')) && $da } } + if (!empty($conf->multicurrency->enabled)) $colspan+=2; + if (! empty($usemargins)) { $colspan++; // For the buying price diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index f71b2b484d1..3abc0fb14c0 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -130,7 +130,11 @@ if (empty($usemargins)) $usemargins=0; tva_tx,'%',$line->info_bits); ?> subprice); ?> - + + multicurrency->enabled)) { ?> + multicurrency_subprice); ?> + + pu_ttc)?price($line->pu_ttc):price($line->subprice)); ?> @@ -190,6 +194,9 @@ if (empty($usemargins)) $usemargins=0; trans('Option'); ?> total_ht); ?> + multicurrency->enabled)) { ?> + multicurrency_total_ht); ?> + statut == 0 && ($object_rights->creer)) { ?> diff --git a/htdocs/install/mysql/migration/3.9.0-4.0.0.sql b/htdocs/install/mysql/migration/3.9.0-4.0.0.sql index c6e8606c28f..7e9260c595e 100644 --- a/htdocs/install/mysql/migration/3.9.0-4.0.0.sql +++ b/htdocs/install/mysql/migration/3.9.0-4.0.0.sql @@ -37,3 +37,102 @@ ALTER TABLE llx_cronjob MODIFY COLUMN unitfrequency varchar(255) NOT NULL DEFAUL ALTER TABLE llx_facture ADD INDEX idx_facture_fk_statut (fk_statut); + +CREATE TABLE IF NOT EXISTS `llx_multicurrency` +( + `rowid` integer AUTO_INCREMENT PRIMARY KEY, + `date_create` datetime DEFAULT NULL, + `code` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `entity` integer DEFAULT NULL, + `fk_user` integer DEFAULT NULL, + KEY `code` (`code`) +) ENGINE=innodb; + +CREATE TABLE IF NOT EXISTS `llx_multicurrency_rate` +( + `rowid` integer AUTO_INCREMENT PRIMARY KEY, + `date_sync` datetime DEFAULT NULL, + `rate` double NOT NULL DEFAULT '0', + `fk_multicurrency` integer NOT NULL DEFAULT '0', + `entity` integer NOT NULL DEFAULT '0', + KEY `fk_multicurrency` (`fk_multicurrency`), + KEY `entity` (`entity`) +) ENGINE=innodb; + +ALTER TABLE llx_societe ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_societe ADD COLUMN multicurrency_code varchar(255); + +ALTER TABLE llx_product_price ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_product_price ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_product_price ADD COLUMN multicurrency_price double(24,8) DEFAULT 0; + +ALTER TABLE llx_commande ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_commande ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_commande ADD COLUMN multicurrency_tx double(24,8) DEFAULT 1; +ALTER TABLE llx_commande ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_commande ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_commande ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_commandedet ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_commandedet ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_commandedet ADD COLUMN multicurrency_subprice double(24,8) DEFAULT 0; +ALTER TABLE llx_commandedet ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_commandedet ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_commandedet ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_commande_fournisseur ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_commande_fournisseur ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_commande_fournisseur ADD COLUMN multicurrency_tx double(24,8) DEFAULT 1; +ALTER TABLE llx_commande_fournisseur ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_commande_fournisseur ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_commande_fournisseur ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_commande_fournisseurdet ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_commande_fournisseurdet ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_commande_fournisseurdet ADD COLUMN multicurrency_subprice double(24,8) DEFAULT 0; +ALTER TABLE llx_commande_fournisseurdet ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_commande_fournisseurdet ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_commande_fournisseurdet ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_facture_fourn ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_facture_fourn ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_facture_fourn ADD COLUMN multicurrency_tx double(24,8) DEFAULT 1; +ALTER TABLE llx_facture_fourn ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_facture_fourn ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_facture_fourn ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_facture_fourn_det ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_facture_fourn_det ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_facture_fourn_det ADD COLUMN multicurrency_subprice double(24,8) DEFAULT 0; +ALTER TABLE llx_facture_fourn_det ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_facture_fourn_det ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_facture_fourn_det ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_facture ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_facture ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_facture ADD COLUMN multicurrency_tx double(24,8) DEFAULT 1; +ALTER TABLE llx_facture ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_facture ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_facture ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_facturedet ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_facturedet ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_facturedet ADD COLUMN multicurrency_subprice double(24,8) DEFAULT 0; +ALTER TABLE llx_facturedet ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_facturedet ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_facturedet ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_propal ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_propal ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_propal ADD COLUMN multicurrency_tx double(24,8) DEFAULT 1; +ALTER TABLE llx_propal ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_propal ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_propal ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; + +ALTER TABLE llx_propaldet ADD COLUMN fk_multicurrency integer; +ALTER TABLE llx_propaldet ADD COLUMN multicurrency_code varchar(255); +ALTER TABLE llx_propaldet ADD COLUMN multicurrency_subprice double(24,8) DEFAULT 0; +ALTER TABLE llx_propaldet ADD COLUMN multicurrency_total_ht double(24,8) DEFAULT 0; +ALTER TABLE llx_propaldet ADD COLUMN multicurrency_total_tva double(24,8) DEFAULT 0; +ALTER TABLE llx_propaldet ADD COLUMN multicurrency_total_ttc double(24,8) DEFAULT 0; \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_commande.sql b/htdocs/install/mysql/tables/llx_commande.sql index 553b2facad7..98740c232ac 100644 --- a/htdocs/install/mysql/tables/llx_commande.sql +++ b/htdocs/install/mysql/tables/llx_commande.sql @@ -70,6 +70,12 @@ create table llx_commande fk_incoterms integer, -- for incoterms location_incoterms varchar(255), -- for incoterms import_key varchar(14), - extraparams varchar(255) -- for stock other parameters with json format + extraparams varchar(255), -- for stock other parameters with json format + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur.sql index 18744a8ca2f..6d291dcfa00 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseur.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur.sql @@ -66,6 +66,12 @@ create table llx_commande_fournisseur fk_incoterms integer, -- for incoterms location_incoterms varchar(255), -- for incoterms import_key varchar(14), - extraparams varchar(255) -- for stock other parameters with json format + extraparams varchar(255), -- for stock other parameters with json format + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseurdet.sql b/htdocs/install/mysql/tables/llx_commande_fournisseurdet.sql index a3dbd87d359..f7b10c8e35e 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseurdet.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseurdet.sql @@ -49,5 +49,12 @@ create table llx_commande_fournisseurdet special_code integer DEFAULT 0, -- code pour les lignes speciales rang integer DEFAULT 0, import_key varchar(14), - fk_unit integer DEFAULT NULL + fk_unit integer DEFAULT NULL, + + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_subprice double(24,8) DEFAULT 0, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_commandedet.sql b/htdocs/install/mysql/tables/llx_commandedet.sql index b01c270cc3e..9608c2ae44b 100644 --- a/htdocs/install/mysql/tables/llx_commandedet.sql +++ b/htdocs/install/mysql/tables/llx_commandedet.sql @@ -55,7 +55,14 @@ create table llx_commandedet special_code integer DEFAULT 0, -- code pour les lignes speciales rang integer DEFAULT 0, fk_unit integer DEFAULT NULL, -- lien vers table des unités - import_key varchar(14) + import_key varchar(14), + + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_subprice double(24,8) DEFAULT 0, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; -- diff --git a/htdocs/install/mysql/tables/llx_facture.sql b/htdocs/install/mysql/tables/llx_facture.sql index e6da2bda214..b503401cd37 100644 --- a/htdocs/install/mysql/tables/llx_facture.sql +++ b/htdocs/install/mysql/tables/llx_facture.sql @@ -84,5 +84,12 @@ create table llx_facture situation_final smallint, -- is the situation final ? import_key varchar(14), - extraparams varchar(255) -- for other parameters with json format + extraparams varchar(255), -- for other parameters with json format + + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_facture_fourn.sql b/htdocs/install/mysql/tables/llx_facture_fourn.sql index 1e7fa12d565..2517f17ad96 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn.sql @@ -70,6 +70,12 @@ create table llx_facture_fourn location_incoterms varchar(255), -- for incoterms model_pdf varchar(255), import_key varchar(14), - extraparams varchar(255) -- for stock other parameters with json format + extraparams varchar(255), -- for stock other parameters with json format + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_det.sql b/htdocs/install/mysql/tables/llx_facture_fourn_det.sql index ad066752ea0..feff72e39b9 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn_det.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn_det.sql @@ -49,5 +49,12 @@ create table llx_facture_fourn_det special_code integer DEFAULT 0, -- code pour les lignes speciales rang integer DEFAULT 0, import_key varchar(14), - fk_unit integer DEFAULT NULL + fk_unit integer DEFAULT NULL, + + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_subprice double(24,8) DEFAULT 0, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_facturedet.sql b/htdocs/install/mysql/tables/llx_facturedet.sql index 63cd9ab3bc1..81074f299e0 100644 --- a/htdocs/install/mysql/tables/llx_facturedet.sql +++ b/htdocs/install/mysql/tables/llx_facturedet.sql @@ -61,8 +61,14 @@ create table llx_facturedet situation_percent real, -- % progression of lines invoicing fk_prev_id integer, -- id of the line in the previous situation, - fk_unit integer DEFAULT NULL -- id of the unit code¡ + fk_unit integer DEFAULT NULL, -- id of the unit code¡ + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_subprice double(24,8) DEFAULT 0, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; -- diff --git a/htdocs/install/mysql/tables/llx_multicurrency.sql b/htdocs/install/mysql/tables/llx_multicurrency.sql new file mode 100644 index 00000000000..2f01236a3b9 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_multicurrency.sql @@ -0,0 +1,28 @@ +-- ======================================================================== +-- Copyright (C) 2016 Pierre-Henry Favre +-- +-- 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_multicurrency +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + date_create datetime DEFAULT NULL, + code varchar(255) DEFAULT NULL, + name varchar(255) DEFAULT NULL, + entity integer DEFAULT NULL, + fk_user integer DEFAULT NULL, + KEY code (code) +) ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_multicurrency_rate.sql b/htdocs/install/mysql/tables/llx_multicurrency_rate.sql new file mode 100644 index 00000000000..a403071930c --- /dev/null +++ b/htdocs/install/mysql/tables/llx_multicurrency_rate.sql @@ -0,0 +1,28 @@ +-- ======================================================================== +-- Copyright (C) 2016 Pierre-Henry Favre +-- +-- 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_multicurrency_rate +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + date_sync datetime DEFAULT NULL, + rate double NOT NULL DEFAULT '0', + fk_multicurrency integer NOT NULL DEFAULT '0', + entity integer NOT NULL DEFAULT '0', + KEY fk_multicurrency (fk_multicurrency), + KEY entity (entity) +) ENGINE=innodb; \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_paiement_facture.sql b/htdocs/install/mysql/tables/llx_paiement_facture.sql index 2dcf95b0dfc..9526ca3aa9d 100644 --- a/htdocs/install/mysql/tables/llx_paiement_facture.sql +++ b/htdocs/install/mysql/tables/llx_paiement_facture.sql @@ -21,5 +21,9 @@ create table llx_paiement_facture rowid integer AUTO_INCREMENT PRIMARY KEY, fk_paiement integer, fk_facture integer, - amount double(24,8) DEFAULT 0 + amount double(24,8) DEFAULT 0, + + multicurrency_code varchar(255), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_amount double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_paiementfourn_facturefourn.sql b/htdocs/install/mysql/tables/llx_paiementfourn_facturefourn.sql index 58d51867d96..a9e8da8a530 100644 --- a/htdocs/install/mysql/tables/llx_paiementfourn_facturefourn.sql +++ b/htdocs/install/mysql/tables/llx_paiementfourn_facturefourn.sql @@ -23,5 +23,9 @@ create table llx_paiementfourn_facturefourn rowid integer AUTO_INCREMENT PRIMARY KEY, fk_paiementfourn INTEGER DEFAULT NULL, fk_facturefourn INTEGER DEFAULT NULL, - amount double(24,8) DEFAULT 0 + amount double(24,8) DEFAULT 0, + + multicurrency_code varchar(255), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_amount double(24,8) DEFAULT 0 )ENGINE=innodb; \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_product_price.sql b/htdocs/install/mysql/tables/llx_product_price.sql index 1341c49dcaa..b101b8b0250 100755 --- a/htdocs/install/mysql/tables/llx_product_price.sql +++ b/htdocs/install/mysql/tables/llx_product_price.sql @@ -39,6 +39,10 @@ create table llx_product_price tosell tinyint DEFAULT 1, price_by_qty integer NOT NULL DEFAULT 0, fk_price_expression integer, -- Link to the rule for dynamic price calculation - import_key varchar(14) + import_key varchar(14), + + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_price double(24,8) DEFAULT NULL )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_propal.sql b/htdocs/install/mysql/tables/llx_propal.sql index 8090b1fcb4d..2566769e7be 100644 --- a/htdocs/install/mysql/tables/llx_propal.sql +++ b/htdocs/install/mysql/tables/llx_propal.sql @@ -69,6 +69,12 @@ create table llx_propal location_incoterms varchar(255), -- for incoterms import_key varchar(14), extraparams varchar(255), -- for stock other parameters with json format - fk_delivery_address integer -- delivery address (deprecated) + fk_delivery_address integer, -- delivery address (deprecated) + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_propaldet.sql b/htdocs/install/mysql/tables/llx_propaldet.sql index 299767ae2ed..3f372894182 100644 --- a/htdocs/install/mysql/tables/llx_propaldet.sql +++ b/htdocs/install/mysql/tables/llx_propaldet.sql @@ -53,8 +53,14 @@ create table llx_propaldet special_code integer DEFAULT 0, -- code pour les lignes speciales rang integer DEFAULT 0, -- ordre affichage sur la propal - fk_unit integer DEFAULT NULL -- lien vers table des unités + fk_unit integer DEFAULT NULL, -- lien vers table des unités + fk_multicurrency integer, + multicurrency_code varchar(255), + multicurrency_subprice double(24,8) DEFAULT 0, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 )ENGINE=innodb; -- diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index 0244b9ea757..82e3b420e29 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -99,5 +99,8 @@ create table llx_societe canvas varchar(32), -- type of canvas if used (null by default) import_key varchar(14), -- import key webservices_url varchar(255), -- supplier webservice url - webservices_key varchar(128) -- supplier webservice key + webservices_key varchar(128), -- supplier webservice key + + fk_multicurrency integer, + multicurrency_code varchar(255) )ENGINE=innodb; diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 7a23657123f..90e84d9a271 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -310,7 +310,8 @@ UnitPrice=Unit price UnitPriceHT=Unit price (net) UnitPriceTTC=Unit price PriceU=U.P. -PriceUHT=U.P. (net) +PriceUHT=U.P. (net in currency) +PriceUHTCurrency=U.P (currency) SupplierProposalUHT=U.P. net Requested PriceUTTC=U.P. (inc. tax) Amount=Amount @@ -335,6 +336,7 @@ Percentage=Percentage Total=Total SubTotal=Subtotal TotalHTShort=Total (net) +TotalHTShortCurrency=Total (net in currency) TotalTTCShort=Total (inc. tax) TotalHT=Total (net of tax) TotalHTforthispage=Total (net of tax) for this page diff --git a/htdocs/multicurrency/class/multicurrency.class.php b/htdocs/multicurrency/class/multicurrency.class.php new file mode 100644 index 00000000000..2000d27d3d4 --- /dev/null +++ b/htdocs/multicurrency/class/multicurrency.class.php @@ -0,0 +1,726 @@ + + * Copyright (C) 2014 Juanjo Menent + * Copyright (C) 2015 Florian Henry + * Copyright (C) 2015 Raphaël Doursenaud + * Copyright (C) 2016 Pierre-Henry Favre + * + * 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 dev/skeletons/skeleton_class.class.php + * \ingroup mymodule othermodule1 othermodule2 + * \brief This file is an example for a CRUD class file (Create/Read/Update/Delete) + * Put some comments here + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT ."/core/class/commonobjectline.class.php"; + +/** + * Class Currency + * + * Put here description of your class + * @see CommonObject + */ +class MultiCurrency extends CommonObject +{ + /** + * @var string Id to identify managed objects + */ + public $element = 'multicurrency'; + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'multicurrency'; + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element_line="multicurrency_rate"; + + /** + * @var CurrencyRate[] rates + */ + public $rates = array(); + + /** + * @var mixed Sample property 1 + */ + public $id; + /** + * @var mixed Sample property 1 + */ + public $code; + /** + * @var mixed Sample property 2 + */ + public $name; + /** + * @var mixed Sample property 2 + */ + public $entity; + /** + * @var mixed Sample property 2 + */ + public $date_create; + /** + * @var mixed Sample property 2 + */ + public $fk_user; + /** + * @var mixed Sample property 2 + */ + public $rate; + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + $this->db = &$db; + + return 1; + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $trigger true=launch triggers after, false=disable triggers + * + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $trigger = true) + { + global $conf; + + dol_syslog('Currency::create', LOG_DEBUG); + + $error = 0; + + if (empty($this->entity) || $this->entity <= 0) $this->entity = $conf->entity; + $now=date('Y-m-d H:i:s'); + + // Insert request + $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '('; + $sql .= ' code,'; + $sql .= ' name,'; + $sql .= ' entity,'; + $sql .= ' date_create,'; + $sql .= ' fk_user'; + $sql .= ') VALUES ('; + $sql .= ' \'' . $this->db->escape($this->code) . '\','; + $sql .= ' \'' . $this->db->escape($this->name) . '\','; + $sql .= ' \'' . $this->entity . '\','; + $sql .= ' \'' . $now . '\','; + $sql .= ' \'' . $user->id . '\''; + $sql .= ')'; + + $this->db->begin(); + + $resql = $this->db->query($sql); + if (!$resql) { + $error ++; + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('Currency::create ' . join(',', $this->errors), LOG_ERR); + } + + if (!$error) { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); + $this->date_create = $now; + $this->fk_user = $user->id; + + if ($trigger) { + $result=$this->call_trigger('CURRENCY_CREATE', $user); + if ($result < 0) $error++; + } + } + + if ($error) { + $this->db->rollback(); + + return - 1 * $error; + } else { + $this->db->commit(); + + return $this->id; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $code code + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $code = null) + { + dol_syslog('Currency::fetch', LOG_DEBUG); + + $sql = 'SELECT'; + $sql .= ' c.rowid, c.name, c.code, c.entity, c.date_create, c.fk_user'; + $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' AS c'; + if (!empty($code)) $sql .= ' WHERE c.code = "'.$this->db->escape($code).'"'; + else $sql .= ' WHERE c.rowid = ' . $id; + + $resql = $this->db->query($sql); + + if ($resql) { + $numrows = $this->db->num_rows($resql); + if ($numrows) { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + $this->name = $obj->name; + $this->code = $obj->code; + $this->entity = $obj->entity; + $this->date_create = $obj->date_create; + $this->fk_user = $obj->fk_user; + + $this->fetchAllCurrencyRate(); + $this->getRate(); + } + $this->db->free($resql); + + if ($numrows) { + return 1; + } else { + return 0; + } + } else { + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('Currency::fetch ' . join(',', $this->errors), LOG_ERR); + + return - 1; + } + } + + /** + * Load all rates in object from the database + * + * @return int <0 if KO, >=0 if OK + */ + public function fetchAllCurrencyRate() + { + dol_syslog('Currency::fetchAllCurrencyRate', LOG_DEBUG); + + $sql = 'SELECT cr.rowid'; + $sql.= ' FROM ' . MAIN_DB_PREFIX . $this->table_element_line. ' as cr'; + $sql.= ' WHERE cr.fk_multicurrency = '.$this->id; + $sql.= ' ORDER BY cr.date_sync DESC'; + + $this->rates = array(); + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + + while ($obj = $this->db->fetch_object($resql)) { + $rate = new CurrencyRate($this->db); + $rate->fetch($obj->rowid); + + $this->rates[] = $rate; + } + $this->db->free($resql); + + return $num; + } else { + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('Currency::fetchAllCurrencyRate ' . join(',', $this->errors), LOG_ERR); + + return - 1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $trigger true=launch triggers after, false=disable triggers + * + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $trigger = true) + { + $error = 0; + + dol_syslog('Currency::update', LOG_DEBUG); + + // Clean parameters + $this->name = trim($this->name); + $this->code = trim($this->code); + + // Check parameters + if (empty($this->code)) { + $error++; + dol_syslog('Currency::update $this->code can not be empty', LOG_ERR); + + return -1; + } + + // Update request + $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET'; + $sql .= ' name="'.$this->db->escape($this->name).'"'; + $sql .= ' code="'.$this->db->escape($this->code).'"'; + $sql .= ' WHERE rowid=' . $this->id; + + $this->db->begin(); + + $resql = $this->db->query($sql); + if (!$resql) { + $error ++; + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('Currency::update ' . join(',', $this->errors), LOG_ERR); + } + + if (!$error && $trigger) { + $result=$this->call_trigger('CURRENCY_MODIFY',$user); + if ($result < 0) $error++; + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + + return - 1 * $error; + } else { + $this->db->commit(); + + return 1; + } + } + + /** + * Delete object in database + * + * @param bool $trigger true=launch triggers after, false=disable triggers + * + * @return int <0 if KO, >0 if OK + */ + public function delete($trigger = true) + { + global $user; + + dol_syslog('Currency::delete', LOG_DEBUG); + + $error = 0; + + $this->db->begin(); + + if ($trigger) { + $result=$this->call_trigger('CURRENCY_DELETE',$user); + if ($result < 0) $error++; + } + + if (!$error) { + // Delete all rates before + if (!$this->deleteRates()) { + $error ++; + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('Currency::delete ' . join(',', $this->errors), LOG_ERR); + } + + $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element; + $sql .= ' WHERE rowid=' . $this->id; + + $resql = $this->db->query($sql); + if (!$resql) { + $error ++; + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('Currency::delete ' . join(',', $this->errors), LOG_ERR); + } + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + + return - 1 * $error; + } else { + $this->db->commit(); + + return 1; + } + } + + /** + * Delete rates in database + * + * @return bool false if KO, true if OK + */ + public function deleteRates() + { + foreach ($this->rates as &$rate) + { + if ($rate->delete() <= 0) + { + return false; + } + } + + return true; + } + + /** + * Delete rate in database + * + * @param double $rate rate value + * + * @return bool false if KO, true if OK + */ + public function addRate($rate) + { + $currencyRate = new CurrencyRate($this->db); + $currencyRate->rate = $rate; + + if ($currencyRate->create($this->id) > 0) + { + $this->rate = $currencyRate; + return 1; + } + else + { + $this->rate = null; + return -1; + } + } + + /** + * Update rate in database + * + * @param double $rate rate value + * + * @return int <0 if KO, >0 if OK + */ + public function updateRate($rate) + { + if (is_object($this->rate)) + { + $this->rate->rate = $rate; + return $this->rate->update(); + } + else + { + return $this->addRate($rate); + } + } + + /** + * Fetch CurrencyRate object in $this->rate + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function getRate() + { + $sql = 'SELECT cr.rowid'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as cr'; + $sql.= ' WHERE cr.fk_multicurrency = '.$this->id; + $sql.= ' AND cr.date_sync >= ALL (SELECT cr2.date_sync FROM '.MAIN_DB_PREFIX.$this->table_element_line.' AS cr2 WHERE cr.rowid = cr2.rowid)'; + + $resql = $this->db->query($sql); + if ($resql && ($obj = $this->db->fetch_object($resql))) { + $this->rate = new CurrencyRate($this->db); + return $this->rate->fetch($obj->rowid); + } + + } + + /** + * Get id of currency from code + * + * @param DoliDB $db object db + * @param string $code code value search + * + * @return 0 if not found, >0 if OK + */ + public static function getIdFromCode(&$db, $code) + { + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'multicurrency WHERE code = "'.$db->escape($code).'"'; + $resql = $db->query($sql); + if ($resql && $obj = $db->fetch_object($resql)) return $obj->rowid; + else return 0; + } + + /** + * Get id and rate of currency from code + * + * @param DoliDB $db object db + * @param string $code code value search + * + * @return array [0] => id currency + * [1] => rate + */ + public static function getIdAndTxFromCode(&$db, $code) + { + $sql = 'SELECT m.rowid, mc.rate FROM '.MAIN_DB_PREFIX.'multicurrency m'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'multicurrency_rate mc ON (m.rowid = mc.fk_multicurrency)'; + $sql.= ' WHERE m.code = "'.$db->escape($code).'" AND mc.date_sync >= ALL (SELECT date_sync FROM '.MAIN_DB_PREFIX.'multicurrency_rate)'; + $resql = $db->query($sql); + if ($resql && $obj = $db->fetch_object($resql)) return array($obj->rowid, $obj->rate); + else return array(0, 1); + } +} + +/** + * Class CurrencyRate + */ +class CurrencyRate extends CommonObjectLine +{ + /** + * @var string Id to identify managed objects + */ + public $element = 'multicurrency_rate'; + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'multicurrency_rate'; + /** + * @var int ID + */ + public $id; + /** + * @var double Rate + */ + public $rate; + /** + * @var date Date synchronisation + */ + public $date_sync; + /** + * @var int Id of currency + */ + public $fk_multicurrency; + /** + * @var int Id of entity + */ + public $entity; + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + $this->db = &$db; + + return 1; + } + + /** + * Create object into database + * + * @param int $fk_multicurrency Id of currency + * @param bool $trigger true=launch triggers after, false=disable triggers + * + * @return int <0 if KO, Id of created object if OK + */ + public function create($fk_multicurrency, $trigger = true) + { + global $conf, $user; + + dol_syslog('CurrencyRate::create', LOG_DEBUG); + + $error = 0; + $this->rate = price2num($this->rate); + if (empty($this->entity) || $this->entity <= 0) $this->entity = $conf->entity; + $now=date('Y-m-d H:i:s'); + + // Insert request + $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '('; + $sql .= ' rate,'; + $sql .= ' date_sync,'; + $sql .= ' fk_multicurrency,'; + $sql .= ' entity'; + $sql .= ') VALUES ('; + $sql .= ' '.$this->rate.','; + $sql .= ' \'' . $now . '\','; + $sql .= ' \'' . $fk_multicurrency . '\','; + $sql .= ' \'' . $this->entity . '\''; + $sql .= ')'; + + $this->db->begin(); + + $resql = $this->db->query($sql); + if (!$resql) { + $error ++; + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('CurrencyRate::create ' . join(',', $this->errors), LOG_ERR); + } + + if (!$error) { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); + $this->fk_multicurrency = $fk_multicurrency; + $this->date_sync = $now; + + if ($trigger) { + $result=$this->call_trigger('CURRENCYRATE_CREATE', $user); + if ($result < 0) $error++; + } + } + + if ($error) { + $this->db->rollback(); + + return - 1 * $error; + } else { + $this->db->commit(); + + return $this->id; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id) + { + dol_syslog('CurrencyRate::fetch', LOG_DEBUG); + + $sql = 'SELECT cr.rowid, cr.rate, cr.date_sync, cr.fk_multicurrency, cr.entity'; + $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' AS cr'; + $sql .= ' WHERE cr.rowid = ' . $id; + + $resql = $this->db->query($sql); + if ($resql) { + $numrows = $this->db->num_rows($resql); + if ($numrows) { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + $this->rate = $obj->rate; + $this->date_sync = $obj->date_sync; + $this->fk_multicurrency = $obj->fk_multicurrency; + $this->entity = $obj->entity; + } + $this->db->free($resql); + + if ($numrows) { + return 1; + } else { + return 0; + } + } else { + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('CurrencyRate::fetch ' . join(',', $this->errors), LOG_ERR); + + return - 1; + } + } + + /** + * Update object into database + * + * @param bool $trigger true=launch triggers after, false=disable triggers + * + * @return int <0 if KO, >0 if OK + */ + public function update($trigger = true) + { + global $user; + + $error = 0; + + dol_syslog('CurrencyRate::update', LOG_DEBUG); + + $this->rate = price2num($this->rate); + + // Update request + $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET'; + $sql .= ' rate='.$this->rate; + $sql .= ' WHERE rowid=' . $this->id; + + $this->db->begin(); + + $resql = $this->db->query($sql); + if (!$resql) { + $error ++; + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('CurrencyRate::update ' . join(',', $this->errors), LOG_ERR); + } + + if (!$error && $trigger) { + $result=$this->call_trigger('CURRENCYRATE_MODIFY',$user); + if ($result < 0) $error++; + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + + return - 1 * $error; + } else { + $this->db->commit(); + + return 1; + } + } + + /** + * Delete object in database + * + * @param bool $trigger true=launch triggers after, false=disable triggers + * + * @return int <0 if KO, >0 if OK + */ + public function delete($trigger = true) + { + global $user; + + dol_syslog('CurrencyRate::delete', LOG_DEBUG); + + $error = 0; + + $this->db->begin(); + + if ($trigger) { + $result=$this->call_trigger('CURRENCYRATE_DELETE',$user); + if ($result < 0) $error++; + } + + if (!$error) { + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' WHERE rowid='.$this->id; + + $resql = $this->db->query($sql); + if (!$resql) { + $error ++; + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog('CurrencyRate::delete ' . join(',', $this->errors), LOG_ERR); + } + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + + return - 1 * $error; + } else { + $this->db->commit(); + + return 1; + } + } + +} diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 1184a490495..b7cd05bf93c 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -33,7 +33,7 @@ * \brief File for third party class */ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; - +dol_include_once('/multicurrency/class/multicurrency.class.php'); /** * Class to manage third parties objects (customers, suppliers, prospects...) @@ -354,6 +354,10 @@ class Societe extends CommonObject var $location_incoterms; var $libelle_incoterms; //Used into tooltip + // Multicurrency + var $fk_multicurrency; + var $multicurrency_code; + /** * To contains a clone of this when we need to save old properties of object * @var Societe @@ -402,7 +406,14 @@ class Societe extends CommonObject if (empty($this->client)) $this->client=0; if (empty($this->fournisseur)) $this->fournisseur=0; $this->import_key = trim($this->import_key); - + + if (!empty($this->multicurrency_code)) $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code); + if (empty($this->fk_multicurrency)) + { + $this->multicurrency_code = ''; + $this->fk_multicurrency = 0; + } + dol_syslog(get_class($this)."::create ".$this->name); // Check parameters @@ -427,7 +438,7 @@ class Societe extends CommonObject if ($result >= 0) { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."societe (nom, name_alias, entity, datec, fk_user_creat, canvas, status, ref_int, ref_ext, fk_stcomm, fk_incoterms, location_incoterms ,import_key)"; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."societe (nom, name_alias, entity, datec, fk_user_creat, canvas, status, ref_int, ref_ext, fk_stcomm, fk_incoterms, location_incoterms ,import_key, fk_multicurrency, multicurrency_code)"; $sql.= " VALUES ('".$this->db->escape($this->name)."', '".$this->db->escape($this->name_alias)."', ".$conf->entity.", '".$this->db->idate($now)."'"; $sql.= ", ".(! empty($user->id) ? "'".$user->id."'":"null"); $sql.= ", ".(! empty($this->canvas) ? "'".$this->db->escape($this->canvas)."'":"null"); @@ -437,7 +448,9 @@ class Societe extends CommonObject $sql.= ", 0"; $sql.= ", ".(int) $this->fk_incoterms; $sql.= ", '".$this->db->escape($this->location_incoterms)."'"; - $sql.= ", ".(! empty($this->import_key) ? "'".$this->db->escape($this->import_key)."'":"null").")"; + $sql.= ", ".(! empty($this->import_key) ? "'".$this->db->escape($this->import_key)."'":"null"); + $sql.= ", ".(int) $this->fk_multicurrency; + $sql.= ", '".$this->db->escape($this->multicurrency_code)."')"; dol_syslog(get_class($this)."::create", LOG_DEBUG); $result=$this->db->query($sql); @@ -670,6 +683,13 @@ class Societe extends CommonObject $this->tva_intra = dol_sanitizeFileName($this->tva_intra,''); if (empty($this->status)) $this->status = 0; + if (!empty($this->multicurrency_code)) $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code); + if (empty($this->fk_multicurrency)) + { + $this->multicurrency_code = ''; + $this->fk_multicurrency = 0; + } + // Local taxes $this->localtax1_assuj=trim($this->localtax1_assuj); $this->localtax2_assuj=trim($this->localtax2_assuj); @@ -841,6 +861,8 @@ class Societe extends CommonObject $sql .= ", code_compta_fournisseur = ".(! empty($this->code_compta_fournisseur)?"'".$this->db->escape($this->code_compta_fournisseur)."'":"null"); } $sql .= ", fk_user_modif = ".(! empty($user->id)?"'".$user->id."'":"null"); + $sql .= ", fk_multicurrency = ".(int) $this->fk_multicurrency; + $sql .= ', multicurrency_code = "'.$this->db->escape($this->multicurrency_code).'"'; $sql .= " WHERE rowid = '" . $id ."'"; @@ -992,6 +1014,7 @@ class Societe extends CommonObject $sql .= ', s.fk_departement, s.fk_pays as country_id, s.fk_stcomm, s.remise_client, s.mode_reglement, s.cond_reglement, s.tva_assuj'; $sql .= ', s.mode_reglement_supplier, s.cond_reglement_supplier, s.localtax1_assuj, s.localtax1_value, s.localtax2_assuj, s.localtax2_value, s.fk_prospectlevel, s.default_lang, s.logo'; $sql .= ', s.outstanding_limit, s.import_key, s.canvas, s.fk_incoterms, s.location_incoterms'; + $sql .= ', s.fk_multicurrency, s.multicurrency_code'; $sql .= ', fj.libelle as forme_juridique'; $sql .= ', e.libelle as effectif'; $sql .= ', c.code as country_code, c.label as country'; @@ -1142,6 +1165,10 @@ class Societe extends CommonObject $this->location_incoterms = $obj->location_incoterms; $this->libelle_incoterms = $obj->libelle_incoterms; + // multicurrency + $this->fk_multicurrency = $obj->fk_multicurrency; + $this->multicurrency_code = $obj->multicurrency_code; + $result = 1; // Retreive all extrafield for thirdparty diff --git a/htdocs/societe/soc.php b/htdocs/societe/soc.php index 1eaff21f05f..8852f22686f 100644 --- a/htdocs/societe/soc.php +++ b/htdocs/societe/soc.php @@ -338,6 +338,13 @@ if (empty($reshook)) $object->fk_incoterms = GETPOST('incoterm_id', 'int'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); } + + // Multicurrency + if (!empty($conf->multicurrency->enabled)) + { + $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); + } + // Fill array 'array_options' with data from add form $ret = $extrafields->setOptionalsFromPost($extralabels,$object); if ($ret < 0) @@ -1249,6 +1256,16 @@ else } } + // Multicurrency + if (! empty($conf->multicurrency->enabled)) + { + print ''; + print ''.fieldLabel('Currency','multicurrency_code').''; + print ''; + print $form->selectMultiCurrency(($object->multicurrency_code ? $object->multicurrency_code : $conf->currency), 'multicurrency_code', 1); + print ''; + } + // Other attributes $parameters=array('colspan' => ' colspan="3"', 'colspanvalue' => '3'); $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook @@ -1801,6 +1818,16 @@ else } } + // Multicurrency + if (! empty($conf->multicurrency->enabled)) + { + print ''; + print ''.fieldLabel('Currency','multicurrency_code').''; + print ''; + print $form->selectMultiCurrency(($object->multicurrency_code ? $object->multicurrency_code : $conf->currency), 'multicurrency_code', 1); + print ''; + } + // Other attributes $parameters=array('colspan' => ' colspan="3"', 'colspanvalue' => '3'); $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook @@ -2212,6 +2239,16 @@ else print ''; } + // Multicurrency + if (! empty($conf->multicurrency->enabled)) + { + print ''; + print ''.fieldLabel('Currency','multicurrency_code').''; + print ''; + print !empty($object->multicurrency_code) ? currency_name($object->multicurrency_code,1) : ''; + print ''; + } + // Other attributes $parameters=array('socid'=>$socid, 'colspan' => ' colspan="3"', 'colspanvalue' => '3'); $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook diff --git a/htdocs/theme/eldy/img/object_multicurrency.png b/htdocs/theme/eldy/img/object_multicurrency.png new file mode 100644 index 0000000000000000000000000000000000000000..51896a4c051a345c09fcffbe9c24d08dd8f70a88 GIT binary patch literal 733 zcmV<30wVp1P)j&|t~VM)>s4Kk57SvccsX5PFvZ~4BjON&a-@BTad7lJjk4?ISE=m-!Q zL~HjRxjY&mrs?q1VwS!dJ;4CraQ_6zD(UhR;@8`-``mb-Ze!VY#`&odRjIaZY8a;T z#59WW_)yydfWPA2-f>KibYf@ESo!9Ls%xQ;ug~xI*qpIN#<^-)ZZw}SCNgQg-_WfI zVc+?O0D$R{P5>Zv_2on1u-a!^PArl5);Tr#u6_39=cCJ+!XP-dFv?CkE)@v??7#HL z&s=&&E%DUX)JA)=nl7Z5^23rWE(jo^ZM$MtE4(c&3#vuaPHM}APo%zmRESiC&qgZ3 zqlzNAk|au$GH`GQ9E5W&Sf-QwKA-8CjdeZ!9Zgca3dyB)s%wQ|HKZOAB%#^Tt=o(; z?ND@=oMMA76u2YGB0vZ@2qdq30h|K>7-e=*x2~>iUz<-rqPEdN z9c6|(#3BR%+3VTrIL>4F|n)pt6{py2#1u`8O$z#|Q3< zviF!>(68i{=3SH!oj_5f#mhht=J