30require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
31require_once DOL_DOCUMENT_ROOT.
'/multicurrency/class/currencyrate.class.php';
44 public $element =
'multicurrency';
49 public $table_element =
'multicurrency';
54 public $table_element_line =
"multicurrency_rate";
59 public $rates = array();
102 const MULTICURRENCY_APP_ENDPOINT_DEFAULT =
'https://api.currencylayer.com/live?access_key=__MULTICURRENCY_APP_KEY__&source=__MULTICURRENCY_APP_SOURCE__';
107 const MULTICURRENCY_APP_ENDPOINT_FRANKFURTER_DEFAULT =
'https://api.frankfurter.dev/v1/latest?base=__MULTICURRENCY_APP_SOURCE__';
122 $defaultendpoint = ($provider ==
'frankfurter') ? self::MULTICURRENCY_APP_ENDPOINT_FRANKFURTER_DEFAULT : self::MULTICURRENCY_APP_ENDPOINT_DEFAULT;
125 $this->urlendpoint = str_replace(array(
'__MULTICURRENCY_APP_KEY__',
'__MULTICURRENCY_APP_SOURCE__'), array($key, $source), $urlendpoint);
137 global
$conf, $langs;
139 dol_syslog(
'MultiCurrency::create', LOG_DEBUG);
143 if (self::checkCodeAlreadyExists($this->code)) {
145 $this->errors[] = $langs->trans(
'multicurrency_code_already_added');
149 if (empty($this->entity) || $this->entity <= 0) {
150 $this->entity =
$conf->entity;
155 $sql =
"INSERT INTO ".MAIN_DB_PREFIX.$this->table_element.
"(";
159 $sql .=
' date_create,';
161 $sql .=
') VALUES (';
162 $sql .=
" '".$this->db->escape($this->code).
"',";
163 $sql .=
" '".$this->db->escape($this->
name).
"',";
164 $sql .=
" ".((int) $this->entity).
",";
165 $sql .=
" '".$this->db->idate($now).
"',";
166 $sql .=
" ".((int) $user->id);
172 $resql = $this->db->query($sql);
175 $this->errors[] =
'Error '.$this->db->lasterror();
176 dol_syslog(
'MultiCurrency::create '.implode(
',', $this->errors), LOG_ERR);
180 $this->
id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
181 $this->date_create = $now;
182 $this->fk_user = $user->id;
184 if (empty($notrigger)) {
185 $result = $this->call_trigger(
'CURRENCY_CREATE', $user);
193 $this->db->rollback();
210 public function fetch($id, $code =
null)
212 dol_syslog(
'MultiCurrency::fetch', LOG_DEBUG);
214 $sql =
"SELECT c.rowid, c.name, c.code, c.entity, c.date_create, c.fk_user";
215 $sql .=
" FROM ".MAIN_DB_PREFIX.$this->table_element.
" AS c";
217 $sql .=
" WHERE c.code = '".$this->db->escape($code).
"'";
218 $sql .=
" AND c.entity IN (".getEntity($this->element).
")";
220 $sql .=
' WHERE c.rowid = '.((int) $id);
224 $resql = $this->db->query($sql);
227 $numrows = $this->db->num_rows($resql);
229 $obj = $this->db->fetch_object($resql);
231 $this->
id = $obj->rowid;
232 $this->
name = $obj->name;
233 $this->code = $obj->code;
234 $this->entity = $obj->entity;
235 $this->date_create = $obj->date_create;
236 $this->fk_user = $obj->fk_user;
241 $this->db->free($resql);
249 $this->errors[] =
'Error '.$this->db->lasterror();
250 dol_syslog(
'MultiCurrency::fetch '.implode(
',', $this->errors), LOG_ERR);
263 $sql =
"SELECT cr.rowid";
264 $sql .=
" FROM ".MAIN_DB_PREFIX.$this->table_element_line.
" as cr";
265 $sql .=
" WHERE cr.entity IN (".getEntity($this->element).
")";
266 $sql .=
" AND cr.fk_multicurrency = ".((int) $this->
id);
267 $sql .=
" ORDER BY cr.date_sync DESC";
269 $this->rates = array();
272 $resql = $this->db->query($sql);
274 $num = $this->db->num_rows($resql);
276 while ($obj = $this->db->fetch_object($resql)) {
278 $rate->fetch($obj->rowid);
280 $this->rates[] = $rate;
282 $this->db->free($resql);
286 $this->errors[] =
'Error '.$this->db->lasterror();
287 dol_syslog(
'MultiCurrency::fetchAllCurrencyRate '.implode(
',', $this->errors), LOG_ERR);
304 dol_syslog(
'MultiCurrency::update', LOG_DEBUG);
308 $this->code = trim($this->code);
311 if (empty($this->code)) {
313 dol_syslog(
'MultiCurrency::update $this->code can not be empty', LOG_ERR);
319 $sql =
"UPDATE ".MAIN_DB_PREFIX.$this->table_element.
" SET";
320 $sql .=
" name = '".$this->db->escape($this->
name).
"',";
321 $sql .=
" code = '".$this->db->escape($this->code).
"'";
322 $sql .=
" WHERE rowid = ".((int) $this->
id);
326 $resql = $this->db->query($sql);
329 $this->errors[] =
'Error '.$this->db->lasterror();
330 dol_syslog(
'MultiCurrency::update '.implode(
',', $this->errors), LOG_ERR);
333 if (!$error && empty($notrigger)) {
334 $result = $this->call_trigger(
'CURRENCY_MODIFY', $user);
342 $this->db->rollback();
359 public function delete(
User $user, $notrigger = 0)
361 dol_syslog(
'MultiCurrency::delete', LOG_DEBUG);
367 if (empty($notrigger)) {
368 $result = $this->call_trigger(
'CURRENCY_DELETE', $user);
378 $this->errors[] =
'Error '.$this->db->lasterror();
379 dol_syslog(
'Currency::delete '.implode(
',', $this->errors), LOG_ERR);
382 $sql =
"DELETE FROM ".MAIN_DB_PREFIX.$this->table_element;
383 $sql .=
" WHERE rowid = ".((int) $this->
id);
386 $resql = $this->db->query($sql);
389 $this->errors[] =
'Error '.$this->db->lasterror();
390 dol_syslog(
'MultiCurrency::delete '.implode(
',', $this->errors), LOG_ERR);
396 $this->db->rollback();
415 foreach ($this->rates as &$rate) {
416 if ($rate->delete($user) <= 0) {
435 $currencyRate->rate = (float)
price2num($rate);
437 if ($currencyRate->create($user, $this->id) > 0) {
438 $this->rate = $currencyRate;
442 $this->errors = $currencyRate->errors;
459 $currency->code = $code;
460 $currency->name = $code;
462 $sql =
"SELECT label FROM ".MAIN_DB_PREFIX.
"c_currencies WHERE code_iso = '".$this->db->escape($code).
"'";
465 $resql = $this->db->query($sql);
466 if ($resql && ($line = $this->db->fetch_object($resql))) {
467 $currency->name = $line->label;
470 if ($currency->create($user) > 0) {
471 $currency->addRate($rate);
501 $sql =
"SELECT cr.rowid";
502 $sql .=
" FROM ".MAIN_DB_PREFIX.$this->table_element_line.
" as cr";
503 $sql .=
" WHERE cr.entity IN (".getEntity($this->element).
")";
504 $sql .=
" AND cr.fk_multicurrency = ".((int) $this->
id);
505 $sql .=
" AND cr.date_sync = (SELECT MAX(cr2.date_sync) FROM ".MAIN_DB_PREFIX.$this->table_element_line.
" AS cr2";
506 $sql .=
" WHERE cr2.entity IN (".getEntity($this->element).
") AND cr2.fk_multicurrency = ".((int) $this->
id).
")";
510 $resql = $this->db->query($sql);
511 if ($resql && ($obj = $this->db->fetch_object($resql))) {
513 return $this->rate->fetch($obj->rowid);
531 $sql =
"SELECT rowid FROM ".MAIN_DB_PREFIX.
"multicurrency WHERE code = '".$dbs->escape($code).
"' AND entity = ".((int)
$conf->entity);
534 $resql = $dbs->query($sql);
535 if ($resql && $obj = $dbs->fetch_object($resql)) {
554 $sql1 =
"SELECT m.rowid, mc.rate, mc.rate_direct FROM ".MAIN_DB_PREFIX.
"multicurrency m";
555 $sql1 .=
' LEFT JOIN '.MAIN_DB_PREFIX.
'multicurrency_rate mc ON (m.rowid = mc.fk_multicurrency)';
556 $sql1 .=
" WHERE m.code = '".$dbs->escape($code).
"'";
557 $sql1 .=
" AND m.entity IN (".getEntity(
'multicurrency').
")";
559 if (
getDolGlobalString(
'MULTICURRENCY_USE_RATE_ON_DOCUMENT_DATE') && !empty($date_document)) {
561 $sql2 .=
" AND mc.date_sync <= '".$dbs->idate(
dol_mktime(23, 59, 59, $tmparray[
'mon'], $tmparray[
'mday'], $tmparray[
'year'],
true)).
"'";
563 $sql3 =
" ORDER BY mc.date_sync DESC LIMIT 1";
566 $resql = $dbs->query($sql1.$sql2.$sql3);
568 if ($resql && $obj = $dbs->fetch_object($resql)) {
569 return array($obj->rowid, $obj->rate);
572 $resql = $dbs->query($sql1.$sql3);
573 if ($resql && $obj = $dbs->fetch_object($resql)) {
574 return array($obj->rowid, $obj->rate, $obj->rate_direct);
594 if (!is_null($invoice_rate)) {
595 $multicurrency_tx = $invoice_rate;
598 $multicurrency_tx = $tmparray[
'invoice_multicurrency_tx'];
601 if ($multicurrency_tx) {
602 if ($way ==
'dolibarr') {
603 return (
float)
price2num($amount * $multicurrency_tx,
'MU');
605 return (
float)
price2num($amount / $multicurrency_tx,
'MU');
623 $sql =
"SELECT multicurrency_tx, multicurrency_code";
624 $sql .=
" FROM ".MAIN_DB_PREFIX.$db->sanitize($table);
625 $sql .=
" WHERE rowid = ".((int) $fk_facture);
628 $resql = $db->query($sql);
629 if ($resql && ($line = $db->fetch_object($resql))) {
630 return array(
'invoice_multicurrency_tx' => $line->multicurrency_tx,
'invoice_multicurrency_code' => $line->multicurrency_code);
647 $alternate_source =
'USD'.getDolCurrency();
648 if (!empty($TRate->$alternate_source)) {
649 $coef = 1 / $TRate->$alternate_source;
650 foreach ($TRate as $attr => &$rate) {
653 $TRate->USDUSD = $coef;
672 public function syncRates($nu = 0, $addifnotfound = 0, $mode =
"")
677 $this->output = $langs->trans(
'Use of API for currency update is disabled by option MULTICURRENCY_DISABLE_SYNC_CURRENCYLAYER');
678 $this->errors[] = $this->output;
682 include_once DOL_DOCUMENT_ROOT.
'/core/lib/geturl.lib.php';
685 $urlendpoint = $this->urlendpoint;
687 dol_syslog(
"Call url endpoint ".$urlendpoint);
690 $addheaders = array();
691 if ($provider !=
'frankfurter') {
692 $addheaders[] =
'apikey: '.getDolGlobalString(
'MULTICURRENCY_APP_KEY');
695 $resget =
getURLContent($urlendpoint,
'GET',
'', 1, $addheaders);
708 if (empty($resget[
'content'])) {
709 $this->output = $resget[
'curl_error_msg'];
710 $this->errors[] = $this->output;
715 $response = json_decode($resget[
'content']);
719 $error_info_syslog =
'';
721 if ($provider ==
'frankfurter') {
722 if (!empty($response->rates) && is_object($response->rates)) {
726 $sourcecode = !empty($response->base) ? $response->base :
getDolGlobalString(
'MULTICURRENCY_APP_SOURCE',
'USD');
728 foreach ($response->rates as $code => $rate) {
729 $TRate->{$sourcecode.$code} = $rate;
731 $TRate->{$sourcecode.$sourcecode} = 1.0;
733 $error_info = !empty($response->message) ? $response->message : (!empty($response->error) ? $response->error : json_encode($response));
734 $error_info_syslog = $error_info;
738 if (!empty($response->success)) {
739 $TRate = $response->quotes;
742 if (isset($response->error->info)) {
743 $error_info_syslog = $response->error->info;
744 $error_info = $error_info_syslog;
746 $error_info_syslog = json_encode($response);
747 $error_info = $resget[
'content'];
752 if ($TRate !==
null) {
754 if ($this->recalculRates($TRate) >= 0) {
755 foreach ($TRate as $currency_code => $rate) {
756 $code = substr($currency_code, 3, 3);
758 if ($obj->fetch(0, $code) > 0) {
759 $obj->updateRate($rate);
760 } elseif ($addifnotfound) {
761 $this->addRateFromDolibarr($code, $rate);
766 if ($mode ==
"cron") {
771 dol_syslog(
"Failed to call endpoint ".$error_info_syslog, LOG_WARNING);
773 $this->output = $langs->trans(
'multicurrency_syncronize_error', $error_info);
774 $this->errors[] = $this->output;
789 if ($currencytmp->fetch(0, $code) > 0) {
Class to manage Dolibarr database access.
static getInvoiceRate($fk_facture, $table='facture')
Get current invoite rate.
getRate()
Fetch CurrencyRate object in $this->rate.
static getIdAndTxFromCode($dbs, $code, $date_document=0)
Get id and rate of currency from code.
update(User $user, $notrigger=0)
Update object into database.
syncRates($nu=0, $addifnotfound=0, $mode="")
Sync rates from API.
fetchAllCurrencyRate()
Load all rates in object from the database.
static getAmountConversionFromInvoiceRate($fk_facture, $amount, $way='dolibarr', $table='facture', $invoice_rate=null)
Get the conversion of amount with invoice rate.
checkCodeAlreadyExists($code)
Check in database if the current code already exists.
updateRate($rate)
Add new entry into llx_multicurrency_rate.
static getIdFromCode($dbs, $code)
Get id of currency from code.
__construct(DoliDB $db)
Constructor.
deleteRates()
Delete rates in database.
create(User $user, $notrigger=0)
Create object into database.
addRateFromDolibarr($code, $rate)
Try get label of code in llx_currency then add rate.
recalculRates(&$TRate)
With free account we can't set source to something else than US, to we recalculate all rates to force...
fetch($id, $code=null)
Load object in memory from the database.
addRate($rate)
Add a Rate into database.
Class to manage Dolibarr users.
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getDolCurrency()
Return the main currency ('EUR', 'USD', ...)
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
getURLContent($url, $postorget='GET', $param='', $followlocation=1, $addheaders=array(), $allowedschemes=array('http', 'https'), $localurl=0, $ssl_verifypeer=-1, $timeoutconnect=0, $timeoutresponse=0, $otherCurlOptions=array(), $morelogsuffix='')
Function to get a content from an URL (use proxy if proxy defined).
$conf db name
Only used if Module[ID]Name translation string is not found.