mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 15:06:06 +00:00
currency no-join-mode
This commit is contained in:
@@ -29,17 +29,17 @@
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Fields;
|
||||
|
||||
use Espo\ORM\Query\Part\Expression as Expr;
|
||||
|
||||
class Currency extends Base
|
||||
{
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @param string $entityType
|
||||
* @return array<string,mixed>
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function load($fieldName, $entityType)
|
||||
{
|
||||
$alias = $fieldName . 'CurrencyRate';
|
||||
|
||||
$defs = [
|
||||
$entityType => [
|
||||
'fields' => [
|
||||
@@ -50,109 +50,19 @@ class Currency extends Base
|
||||
],
|
||||
];
|
||||
|
||||
$leftJoins = [
|
||||
[
|
||||
'Currency',
|
||||
$alias,
|
||||
[$alias . '.id:' => $fieldName . 'Currency'],
|
||||
]
|
||||
];
|
||||
|
||||
$foreignCurrencyAlias = "{$alias}{$entityType}{alias}Foreign";
|
||||
|
||||
$mulExpression = "MUL:({$fieldName}, {$alias}.rate)";
|
||||
|
||||
$params = $this->getFieldParams($fieldName);
|
||||
|
||||
if (!empty($params['notStorable'])) {
|
||||
$defs[$entityType]['fields'][$fieldName]['notStorable'] = true;
|
||||
}
|
||||
else {
|
||||
$defs[$entityType]['fields'][$fieldName . 'Converted'] = [
|
||||
'type' => 'float',
|
||||
'select' => [
|
||||
'select' => $mulExpression,
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
'selectForeign' => [
|
||||
'select' => "MUL:({alias}.{$fieldName}, {$foreignCurrencyAlias}.rate)",
|
||||
'leftJoins' => [
|
||||
[
|
||||
'Currency',
|
||||
$foreignCurrencyAlias,
|
||||
[
|
||||
$foreignCurrencyAlias . '.id:' => "{alias}.{$fieldName}Currency",
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
'where' => [
|
||||
"=" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
">" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '>' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"<" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '<' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
">=" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '>=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"<=" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '<=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"<>" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '!=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"IS NULL" => [
|
||||
'whereClause' => [
|
||||
$fieldName . '=' => null,
|
||||
],
|
||||
],
|
||||
"IS NOT NULL" => [
|
||||
'whereClause' => [
|
||||
$fieldName . '!=' => null,
|
||||
],
|
||||
],
|
||||
],
|
||||
'notStorable' => true,
|
||||
'order' => [
|
||||
'order' => [
|
||||
[$mulExpression, '{direction}'],
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
'additionalSelect' => ["{$alias}.rate"],
|
||||
],
|
||||
'attributeRole' => 'valueConverted',
|
||||
'fieldType' => 'currency',
|
||||
];
|
||||
if ($this->config->get('currencyNoJoinMode')) {
|
||||
$this->applyNoJoinMode($fieldName, $entityType, $defs);
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName]['order'] = [
|
||||
"order" => [
|
||||
[$mulExpression, '{direction}'],
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
'additionalSelect' => ["{$alias}.rate"],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$this->applyJoinMode($fieldName, $entityType, $defs);
|
||||
}
|
||||
}
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName]['attributeRole'] = 'value';
|
||||
@@ -163,4 +73,256 @@ class Currency extends Base
|
||||
|
||||
return $defs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @param string $entityType
|
||||
* @param array<string, mixed> $defs
|
||||
*/
|
||||
private function applyJoinMode(
|
||||
string $fieldName,
|
||||
string $entityType,
|
||||
array &$defs
|
||||
): void {
|
||||
|
||||
$alias = $fieldName . 'CurrencyRate';
|
||||
$leftJoins = [
|
||||
[
|
||||
'Currency',
|
||||
$alias,
|
||||
[$alias . '.id:' => $fieldName . 'Currency'],
|
||||
]
|
||||
];
|
||||
$foreignCurrencyAlias = "{$alias}{$entityType}{alias}Foreign";
|
||||
$mulExpression = "MUL:({$fieldName}, {$alias}.rate)";
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName . 'Converted'] = [
|
||||
'type' => 'float',
|
||||
'select' => [
|
||||
'select' => $mulExpression,
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
'selectForeign' => [
|
||||
'select' => "MUL:({alias}.{$fieldName}, {$foreignCurrencyAlias}.rate)",
|
||||
'leftJoins' => [
|
||||
[
|
||||
'Currency',
|
||||
$foreignCurrencyAlias,
|
||||
[
|
||||
$foreignCurrencyAlias . '.id:' => "{alias}.{$fieldName}Currency",
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
'where' => [
|
||||
"=" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
">" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '>' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"<" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '<' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
">=" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '>=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"<=" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '<=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"<>" => [
|
||||
'whereClause' => [
|
||||
$mulExpression . '!=' => '{value}',
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
"IS NULL" => [
|
||||
'whereClause' => [
|
||||
$fieldName . '=' => null,
|
||||
],
|
||||
],
|
||||
"IS NOT NULL" => [
|
||||
'whereClause' => [
|
||||
$fieldName . '!=' => null,
|
||||
],
|
||||
],
|
||||
],
|
||||
'notStorable' => true,
|
||||
'order' => [
|
||||
'order' => [
|
||||
[$mulExpression, '{direction}'],
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
'additionalSelect' => ["{$alias}.rate"],
|
||||
],
|
||||
'attributeRole' => 'valueConverted',
|
||||
'fieldType' => 'currency',
|
||||
];
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName]['order'] = [
|
||||
"order" => [
|
||||
[$mulExpression, '{direction}'],
|
||||
],
|
||||
'leftJoins' => $leftJoins,
|
||||
'additionalSelect' => ["{$alias}.rate"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @param string $entityType
|
||||
* @param array<string, mixed> $defs
|
||||
*/
|
||||
private function applyNoJoinMode(
|
||||
string $fieldName,
|
||||
string $entityType,
|
||||
array &$defs
|
||||
): void {
|
||||
|
||||
$currencyAttribute = $fieldName . 'Currency';
|
||||
|
||||
$defaultCurrency = $this->config->get('defaultCurrency');
|
||||
$baseCurrency = $this->config->get('baseCurrency');
|
||||
$rates = $this->config->get('currencyRates');
|
||||
|
||||
if ($defaultCurrency !== $baseCurrency) {
|
||||
$rates = $this->exchangeRates($baseCurrency, $defaultCurrency, $rates);
|
||||
}
|
||||
|
||||
$expr = Expr::multiply(
|
||||
Expr::column($fieldName),
|
||||
Expr::if(
|
||||
Expr::equal(Expr::column($currencyAttribute), $defaultCurrency),
|
||||
1.0,
|
||||
$this->buildExpression($currencyAttribute, $rates)
|
||||
)
|
||||
)->getValue();
|
||||
|
||||
$exprForeign = Expr::multiply(
|
||||
Expr::column("ALIAS.{$fieldName}"),
|
||||
Expr::if(
|
||||
Expr::equal(Expr::column("ALIAS.{$fieldName}Currency"), $defaultCurrency),
|
||||
1.0,
|
||||
$this->buildExpression("ALIAS.{$fieldName}Currency", $rates)
|
||||
)
|
||||
)->getValue();
|
||||
|
||||
$exprForeign = str_replace('ALIAS', '{alias}', $exprForeign);
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName . 'Converted'] = [
|
||||
'type' => 'float',
|
||||
'select' => [
|
||||
'select' => $expr,
|
||||
],
|
||||
'selectForeign' => [
|
||||
'select' => $exprForeign,
|
||||
],
|
||||
'where' => [
|
||||
"=" => [
|
||||
'whereClause' => [
|
||||
$expr . '=' => '{value}',
|
||||
],
|
||||
],
|
||||
">" => [
|
||||
'whereClause' => [
|
||||
$expr . '>' => '{value}',
|
||||
],
|
||||
],
|
||||
"<" => [
|
||||
'whereClause' => [
|
||||
$expr . '<' => '{value}',
|
||||
],
|
||||
],
|
||||
">=" => [
|
||||
'whereClause' => [
|
||||
$expr . '>=' => '{value}',
|
||||
],
|
||||
],
|
||||
"<=" => [
|
||||
'whereClause' => [
|
||||
$expr . '<=' => '{value}',
|
||||
],
|
||||
],
|
||||
"<>" => [
|
||||
'whereClause' => [
|
||||
$expr . '!=' => '{value}',
|
||||
],
|
||||
],
|
||||
"IS NULL" => [
|
||||
'whereClause' => [
|
||||
$expr . '=' => null,
|
||||
],
|
||||
],
|
||||
"IS NOT NULL" => [
|
||||
'whereClause' => [
|
||||
$expr . '!=' => null,
|
||||
],
|
||||
],
|
||||
],
|
||||
'notStorable' => true,
|
||||
'order' => [
|
||||
'order' => [
|
||||
[$expr, '{direction}'],
|
||||
],
|
||||
],
|
||||
'attributeRole' => 'valueConverted',
|
||||
'fieldType' => 'currency',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, float> $currencyRates
|
||||
* @return array<string, float>
|
||||
*/
|
||||
private function exchangeRates(string $baseCurrency, string $defaultCurrency, array $currencyRates): array
|
||||
{
|
||||
$precision = 5;
|
||||
$defaultCurrencyRate = round(1 / $currencyRates[$defaultCurrency], $precision);
|
||||
|
||||
$exchangedRates = [];
|
||||
$exchangedRates[$baseCurrency] = $defaultCurrencyRate;
|
||||
|
||||
unset($currencyRates[$baseCurrency], $currencyRates[$defaultCurrency]);
|
||||
|
||||
foreach ($currencyRates as $currencyName => $rate) {
|
||||
$exchangedRates[$currencyName] = round($rate * $defaultCurrencyRate, $precision);
|
||||
}
|
||||
|
||||
return $exchangedRates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, float> $rates
|
||||
*/
|
||||
private function buildExpression(string $currencyAttribute, array $rates): Expr|float
|
||||
{
|
||||
if ($rates === []) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$currency = array_key_first($rates);
|
||||
$value = $rates[$currency];
|
||||
unset($rates[$currency]);
|
||||
|
||||
return Expr::if(
|
||||
Expr::equal(Expr::column($currencyAttribute), $currency),
|
||||
$value,
|
||||
$this->buildExpression($currencyAttribute, $rates)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ return [
|
||||
'defaultCurrency' => 'USD',
|
||||
'baseCurrency' => 'USD',
|
||||
'currencyRates' => [],
|
||||
'currencyNoJoinMode' => false,
|
||||
'outboundEmailIsShared' => true,
|
||||
'outboundEmailFromName' => 'EspoCRM',
|
||||
'outboundEmailFromAddress' => '',
|
||||
|
||||
@@ -191,6 +191,7 @@ return [
|
||||
'thumbImageCacheDisabled',
|
||||
'emailReminderPortionSize',
|
||||
'outboundSmsFromNumber',
|
||||
'currencyNoJoinMode',
|
||||
'latestVersion',
|
||||
],
|
||||
'superAdminItems' => [
|
||||
|
||||
Reference in New Issue
Block a user