Passed
Push — developer ( 796144...7f419d )
by Radosław
16:31
created

getCRMConversionRate()   C

Complexity

Conditions 12
Paths 54

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 28.075

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 34
ccs 14
cts 27
cp 0.5185
rs 6.9666
c 0
b 0
f 0
cc 12
nc 54
nop 3
crap 28.075

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @copyright YetiForce S.A.
5
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
6
 * @author    Mariusz Krzaczkowski <[email protected]>
7
 * @author    Maciej Stencel <[email protected]>
8
 * @author    Radosław Skrzypczak <[email protected]>
9
 */
10
class Settings_CurrencyUpdate_Module_Model extends \App\Base
11
{
12
	// Returns objects instance
13
14 3
	public static function getCleanInstance()
15
	{
16 3
		return new self();
17
	}
18
19
	/**
20
	 * Returns CRMS active currency name by currency code.
21
	 *
22
	 * @param mixed $code
23
	 *
24 2
	 * @return string - currency name
25
	 */
26 2
	public static function getCRMCurrencyName($code)
27 2
	{
28 2
		return (new \App\Db\Query())
0 ignored issues
show
Bug Best Practice introduced by
The expression return new App\Db\Query(...e' => $code))->scalar() could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
29 2
			->select(['currency_name'])
30 2
			->from('vtiger_currencies')
31
			->where(['currency_code' => $code])
32
			->scalar();
33
	}
34
35
	/**
36
	 * Returns list of active currencies in CRM.
37
	 *
38 1
	 * @return <Integer> - number of currencies
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
39
	 */
40 1
	public function getCurrencyNum()
41
	{
42
		return \count(\App\Fields\Currency::getAll(true));
43
	}
44
45
	/**
46
	 * Returns currency exchange rates for systems active currencies from bank.
47
	 *
48
	 * @param string $dateCur - date for which to fetch exchange rates
49
	 * @param bool   $cron    - true if fired by server, and so updates systems currency conversion rates
50 1
	 *
51
	 * @return bool - true if fetched new exchange rates, false otherwise
52 1
	 */
53
	public function fetchCurrencyRates($dateCur, $cron = false): bool
0 ignored issues
show
Unused Code introduced by
The parameter $cron is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

53
	public function fetchCurrencyRates($dateCur, /** @scrutinizer ignore-unused */ $cron = false): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
54
	{
55 1
		if (!\App\RequestUtil::isNetConnection() || \count(($currencies = \App\Fields\Currency::getAll(true))) <= 1) {
56 1
			return false;
57 1
		}
58 1
		$notifyNewRates = false;
59 1
60 1
		$defaultId = \App\Fields\Currency::getDefault()['id'];
61 1
		unset($currencies[$defaultId]);
62 1
		$currIds = array_column($currencies, 'id', 'currency_code');
63 1
64 1
		$selectBankName = $this->getActiveBankName();
65 1
		$modelClassName = Vtiger_Loader::getComponentClassName('BankModel', $selectBankName, 'Settings:CurrencyUpdate');
66 1
67 1
		if (class_exists($modelClassName) && (new \App\Db\Query())->from('yetiforce_currencyupdate')
68 1
			->where(['exchange_date' => $dateCur, 'currency_id' => array_values($currIds), 'bank_id' => $this->getActiveBankId()])->count(1) !== \count($currIds)) {
69 1
			$bank = new $modelClassName();
70 1
			$bank->getRates($currIds, $dateCur, false);
71
			$notifyNewRates = true;
72 1
		}
73 1
74 1
		return $notifyNewRates;
75 1
	}
76
77 1
	// Synchronises database banks list with the bank classes existing on ftp
78
79
	public function refreshBanks()
80
	{
81
		$db = App\Db::getInstance();
82
		$dataReader = (new \App\Db\Query())->select(['id', 'bank_name'])
83 1
			->from('yetiforce_currencyupdate_banks')
84
			->createCommand()->query();
85
		while ($row = $dataReader->read()) {
86
			$id = $row['id'];
87
			$bankPath = ROOT_DIRECTORY . "/modules/Settings/CurrencyUpdate/bankmodels/{$row['bank_name']}.php";
88 1
			if (!file_exists($bankPath)) { // delete bank from database
89
				$db->createCommand()->delete('yetiforce_currencyupdate_banks', ['id' => $id])->execute();
90 1
			}
91 1
		}
92 1
		$dataReader->close();
93 1
		foreach (new DirectoryIterator(ROOT_DIRECTORY . '/modules/Settings/CurrencyUpdate/bankmodels/') as $fileInfo) {
94 1
			if (!$fileInfo->isFile() || 'php' !== $fileInfo->getExtension()) {
95
				continue;
96
			}
97
			$bankClassName = $fileInfo->getBasename('.php');
98
			$isExists = (new \App\Db\Query())->from('yetiforce_currencyupdate_banks')->where(['bank_name' => $bankClassName])->exists();
99
			if (!$isExists) {
100
				$db->createCommand()->insert('yetiforce_currencyupdate_banks', ['bank_name' => $bankClassName, 'active' => 0])->execute();
101 1
			}
102 1
		}
103 1
		if (!$this->getActiveBankId()) {
104 1
			$db->createCommand()->update('yetiforce_currencyupdate_banks', ['active' => 1], ['bank_name' => 'NBP'])->execute();
105
		}
106 1
		\App\Cache::delete('ActiveBankForExchangeRate', '');
107 1
	}
108
109
	/**
110 1
	 * Update currency rate in archives.
111 1
	 *
112 1
	 * @param <Integer> $id       - exchange rate id
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
113
	 * @param <Float>   $exchange - exchange rate
114
	 */
115 1
	public function updateCurrencyRate($id, $exchange)
116 1
	{
117
		\App\Db::getInstance()->createCommand()
118 1
			->update('yetiforce_currencyupdate', ['exchange' => $exchange], ['id' => $id])
119
			->execute();
120
	}
121
122
	/**
123
	 * Adds currency exchange rate to archive.
124
	 *
125
	 * @param <Integer> $currId       - currency id
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
126 1
	 * @param <Date>    $exchangeDate - exchange date
127
	 * @param <Float>   $exchange     - exchange rate
128 1
	 * @param <Integer> $bankId       - bank id
129 1
	 */
130 1
	public function addCurrencyRate($currId, $exchangeDate, $exchange, $bankId)
131 1
	{
132
		\App\Db::getInstance()->createCommand()->insert('yetiforce_currencyupdate', [
133
			'currency_id' => $currId,
134
			'fetch_date' => date('Y-m-d'),
135
			'exchange_date' => $exchangeDate,
136
			'exchange' => $exchange,
137
			'bank_id' => $bankId,
138
		])->execute();
139
	}
140
141 1
	/**
142
	 * Returns currency exchange rate id.
143 1
	 *
144 1
	 * @param <Integer> $currencyId   - systems currency id
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
145 1
	 * @param <Date>    $exchangeDate - date of exchange rate
146 1
	 * @param <Integer> $bankId       - id of bank
147 1
	 *
148 1
	 * @return <Integer> - currency rate id
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
149 1
	 */
150 1
	public function getCurrencyRateId($currencyId, $exchangeDate, $bankId)
151
	{
152
		return (new \App\Db\Query())->select(['id'])
153
			->from('yetiforce_currencyupdate')
154
			->where(['exchange_date' => $exchangeDate, 'currency_id' => $currencyId, 'bank_id' => $bankId])
155
			->scalar();
156
	}
157
158
	/**
159
	 * Returns currency rates from archive.
160 1
	 *
161
	 * @param int    $bankId    - bank id
162 1
	 * @param string $dateStart - date
163 1
	 * @param string $dateEnd   - date
164 1
	 *
165 1
	 * @return <Array> - array containing currency rates
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Array> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Array>.
Loading history...
166
	 */
167
	public function getRatesHistory(int $bankId, string $dateStart, string $dateEnd)
168
	{
169
		$query = (new App\Db\Query())->select(['exchange', 'currency_name', 'currency_code', 'currency_symbol', 'fetch_date', 'exchange_date', 'currency_id'])
170
			->from('yetiforce_currencyupdate')
171
			->innerJoin('vtiger_currency_info', 'vtiger_currency_info.id = yetiforce_currencyupdate.currency_id')
172
			->innerJoin('yetiforce_currencyupdate_banks', 'yetiforce_currencyupdate_banks.id = yetiforce_currencyupdate.bank_id')
173
			->where(['yetiforce_currencyupdate.bank_id' => $bankId]);
174
		// filter by date - if not exists then display this months history
175
		if ($dateEnd) {
176
			$query->andWhere(['between', 'exchange_date', $dateStart, $dateEnd]);
177
		} else {
178
			$query->andWhere(['exchange_date' => $dateStart]);
179
		}
180
		return $query->orderBy(['exchange_date' => SORT_DESC, 'currency_id' => SORT_ASC])->all();
181
	}
182
183
	/**
184
	 * Returns list of supported currencies by active bank.
185
	 *
186
	 * @param string $bankName - bank name
187
	 *
188
	 * @return <Array> - array of supported currencies
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Array> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Array>.
Loading history...
189
	 */
190
	public function getSupportedCurrencies($bankName = null)
191
	{
192
		if (!\App\RequestUtil::isNetConnection()) {
193
			return [];
194
		}
195
		if (!$bankName) {
196
			$bankName = 'Settings_CurrencyUpdate_' . $this->getActiveBankName() . '_BankModel';
197 1
		}
198
		$currencies = [];
199 1
		try {
200
			$bank = new $bankName();
201
			$currencies = $bank->getSupportedCurrencies();
202 1
		} catch (\Throwable $ex) {
203 1
			\App\Log::error('Error during downloading table: ' . PHP_EOL . $ex->__toString() . PHP_EOL, 'CurrencyUpdate');
204
		}
205 1
		return $currencies;
206
	}
207 1
208
	/**
209
	 * Returns list of unsupported currencies by active bank.
210
	 *
211
	 * @param string $bankName - bank name
212
	 *
213
	 * @return <Array> - array of unsupported currencies
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Array> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Array>.
Loading history...
214
	 */
215
	public function getUnSupportedCurrencies($bankName = null)
216 1
	{
217
		if (!\App\RequestUtil::isNetConnection()) {
218 1
			return [];
219
		}
220
		if (!$bankName) {
221 1
			$bankName = 'Settings_CurrencyUpdate_' . $this->getActiveBankName() . '_BankModel';
222 1
		}
223
		$bank = new $bankName();
224 1
		$supported = $bank->getSupportedCurrencies($bankName);
225 1
		$dataReader = (new \App\Db\Query())->select(['currency_name', 'currency_code'])
226 1
			->from('vtiger_currency_info')
227 1
			->where(['currency_status' => 'Active', 'deleted' => 0])
228 1
			->createCommand()->query();
229 1
		while ($row = $dataReader->read()) {
230 1
			$name = $row['currency_name'];
231 1
			$code = $row['currency_code'];
232 1
			$unsupported[$name] = $code;
233 1
		}
234
		$dataReader->close();
235 1
236
		return array_diff($unsupported, $supported);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $unsupported does not seem to be defined for all execution paths leading up to this point.
Loading history...
237 1
	}
238
239
	/**
240
	 * Sets systems exchange rate for chosen currency.
241
	 *
242
	 * @param string  $currency - currency code
243
	 * @param <Float> $exchange - exchange rate
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Float> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Float>.
Loading history...
244
	 */
245
	public function setCRMConversionRate($currency, $exchange)
246 1
	{
247
		$rate = (float) $exchange;
248 1
		\App\Db::getInstance()->createCommand()
249 1
			->update('vtiger_currency_info', ['conversion_rate' => $rate], ['currency_code' => $currency])
250 1
			->execute();
251 1
	}
252 1
253
	/**
254
	 * Function that retrieves conversion rate from and to specified currency.
255
	 *
256
	 * @param int    $from - currency id
257
	 * @param int    $to   - currency id
258
	 * @param string $date - date of the exchange rate
259
	 *
260
	 * @return <Float> - conversion rate
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Float> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Float>.
Loading history...
261
	 */
262 1
	public function getCRMConversionRate(int $from, int $to, string $date)
263
	{
264 1
		$mainCurrencyCode = \App\Fields\Currency::getDefault()['id'];
265 1
		$exchange = 0;
266 1
267 1
		if ($to != $mainCurrencyCode && ($activeBankId = self::getActiveBankId())) {
0 ignored issues
show
Bug Best Practice introduced by
The method Settings_CurrencyUpdate_...odel::getActiveBankId() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

267
		if ($to != $mainCurrencyCode && ($activeBankId = self::/** @scrutinizer ignore-call */ getActiveBankId())) {
Loading history...
268
			$exchange = (float) (\App\Fields\Currency::getCurrencyRatesFromArchive($date, $to, $activeBankId)['exchange'] ?? 0);
269
			if (empty($exchange) && \App\RequestUtil::isNetConnection()) {
270 1
				self::fetchCurrencyRates($date);
0 ignored issues
show
Bug Best Practice introduced by
The method Settings_CurrencyUpdate_...l::fetchCurrencyRates() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

270
				self::/** @scrutinizer ignore-call */ 
271
          fetchCurrencyRates($date);
Loading history...
271
				$exchange = (float) (\App\Fields\Currency::getCurrencyRatesFromArchive($date, $to, $activeBankId)['exchange'] ?? 0);
272
			}
273
		}
274 1
275 1
		if ($exchange) {
276 1
			$exchange = 1 / $exchange;
277 1
		}
278 1
279 1
		if ($from != $mainCurrencyCode && ($activeBankId = self::getActiveBankId())) {
280 1
			$convertToMainCurrency = 0 == $exchange ? 1 : 1 / $exchange;
281 1
282
			$fromExchange = (float) (\App\Fields\Currency::getCurrencyRatesFromArchive($date, $from, $activeBankId)['exchange'] ?? 0);
283
			if (empty($fromExchange) && \App\RequestUtil::isNetConnection()) {
284
				self::fetchCurrencyRates($date);
285
				$fromExchange = (float) (\App\Fields\Currency::getCurrencyRatesFromArchive($date, $from, $activeBankId)['exchange'] ?? 0);
286
			}
287
288
			if ($to != $mainCurrencyCode) {
289
				$exchange = $fromExchange / $convertToMainCurrency;
290
			} else {
291
				$exchange = $fromExchange * $convertToMainCurrency;
292
			}
293
		}
294
295
		return $exchange = round($exchange, 5);
0 ignored issues
show
Unused Code introduced by
The assignment to $exchange is dead and can be removed.
Loading history...
296
	}
297
298
	/**
299
	 * Returns id of active bank.
300
	 *
301
	 * @return <Integer> - bank id
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
302
	 */
303
	public function getActiveBankId()
304
	{
305
		return \App\Fields\Currency::getActiveBankForExchangeRateUpdate()['id'] ?? 0;
306
	}
307
308
	/**
309
	 * Saves new active bank by id.
310
	 *
311
	 * @param <Integer> $bankId - bank id
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
312
	 *
313
	 * @return bool - true on success or false
314
	 */
315
	public function setActiveBankById($bankId)
316
	{
317
		$db = \App\Db::getInstance();
318
		$db->createCommand()->update('yetiforce_currencyupdate_banks', ['active' => 0])->execute();
319
		$result = $db->createCommand()->update('yetiforce_currencyupdate_banks', ['active' => 1], ['id' => $bankId])->execute();
320
		\App\Cache::delete('ActiveBankForExchangeRate', '');
321
322
		return (bool) $result;
323
	}
324
325
	/**
326
	 * Returns active banks name.
327
	 *
328
	 * @return string - bank name
329
	 */
330
	public function getActiveBankName()
331
	{
332
		return \App\Fields\Currency::getActiveBankForExchangeRateUpdate()['bank_name'] ?? '';
333
	}
334
}
335