Skip to content

Commit c533ed0

Browse files
Support automatic currency exchanges
1 parent a646554 commit c533ed0

File tree

2 files changed

+71
-52
lines changed

2 files changed

+71
-52
lines changed

Model/ProductData/Repository.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -382,10 +382,7 @@ private function prepareAttribute(string $attribute, array $productData)
382382
case 'min_price':
383383
case 'max_price':
384384
case 'sales_price':
385-
if ($value !== null) {
386-
return number_format((float)$value, 2, '.', '');
387-
}
388-
// no break
385+
return $value !== null ? number_format(round((float)$value, 2), 2, '.', '') : null;
389386
case 'visibility':
390387
switch ($value) {
391388
case 1:

Service/ProductData/AttributeCollector/Data/Price.php

Lines changed: 70 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -32,30 +32,12 @@ class Price
3232
'bundle_price_type'
3333
];
3434

35-
/**
36-
* @var CatalogPrice
37-
*/
38-
private $commonPriceModel;
39-
/**
40-
* @var RuleFactory
41-
*/
42-
private $resourceRuleFactory;
43-
/**
44-
* @var CatalogHelper
45-
*/
46-
private $catalogHelper;
47-
/**
48-
* @var StoreManagerInterface
49-
*/
50-
private $storeManager;
51-
/**
52-
* @var TimezoneInterface
53-
*/
54-
private $localeDate;
55-
/**
56-
* @var CollectionFactory
57-
*/
58-
private $collectionFactory;
35+
private CatalogPrice $commonPriceModel;
36+
private RuleFactory $resourceRuleFactory;
37+
private CatalogHelper $catalogHelper;
38+
private StoreManagerInterface $storeManager;
39+
private TimezoneInterface $localeDate;
40+
private CollectionFactory $collectionFactory;
5941

6042
private $price = null;
6143
private $finalPrice = null;
@@ -66,6 +48,7 @@ class Price
6648
private $maxPrice = null;
6749
private $totalPrice = null;
6850
private $websiteId = null;
51+
private $currecy = null;
6952
private $taxClasses = [];
7053
private $bundlePriceType = null;
7154
private $groupedPriceType = null;
@@ -102,45 +85,76 @@ public function execute(
10285
int $storeId = 0
10386
): array {
10487
$store = $this->getStore((int)$storeId);
88+
$this->currecy = $store->getDefaultCurrencyCode();
10589
$this->websiteId = $store->getWebsiteId();
10690
$this->taxClasses = [];
10791

108-
$this->setData('products', $this->getProductData($productIds));
92+
$this->setData('products', $this->getProductData($productIds, $storeId));
10993
$this->setData('grouped_price_type', $groupedPriceType);
11094
$this->setData('bundle_price_type', $bundlePriceType);
95+
$rate = $store->getBaseCurrency()->getRate($this->currecy);
11196

11297
foreach ($this->products as $product) {
11398
$this->setPrices($product, $this->groupedPriceType, $this->bundlePriceType);
114-
115-
if (array_key_exists((int)$product->getTaxClassId(), $this->taxClasses)) {
116-
$percent = $this->taxClasses[(int)$product->getTaxClassId()];
117-
} else {
118-
$priceInclTax = $this->processPrice($product, (float)$this->price, $store);
119-
$percent = $this->price == 0 ? 1 : round($priceInclTax / $this->price, 2);
120-
if ($percent !== 1) {
121-
$this->taxClasses[(int)$product->getTaxClassId()] = $percent;
122-
}
123-
}
99+
$percent = $this->getPercentage($product, $store);
124100

125101
$result[$product->getId()] = [
126-
'price' => $percent * $this->price,
127-
'price_ex' => $this->price,
128-
'final_price' => $this->finalPrice ? $percent * $this->finalPrice : null,
129-
'final_price_ex' => $this->finalPrice,
130-
'sales_price' => $this->salesPrice ? $percent * $this->salesPrice : null,
131-
'min_price' => $this->minPrice ? $percent * $this->minPrice : null,
132-
'max_price' => $this->maxPrice ? $percent * $this->maxPrice : null,
133-
'special_price' => $this->specialPrice ? $percent * $this->specialPrice : null,
134-
'total_price' => $this->totalPrice ? $percent * $this->totalPrice : null,
102+
'price' => $this->round($percent * $this->price),
103+
'price_ex' => $this->round($this->price * $rate),
104+
'final_price' => $this->round($this->finalPrice ? $percent * $this->finalPrice : null),
105+
'final_price_ex' => $this->round($this->finalPrice * $rate),
106+
'sales_price' => $this->round($this->salesPrice ? $percent * $this->salesPrice : null),
107+
'min_price' => $this->round($this->minPrice ? $percent * $this->minPrice : null),
108+
'max_price' => $this->round($this->maxPrice ? $percent * $this->maxPrice : null),
109+
'special_price' => $this->round($this->specialPrice ? $percent * $this->specialPrice : null),
110+
'total_price' => $this->round($this->totalPrice ? $percent * $this->totalPrice : null),
135111
'sales_date_range' => $this->getSpecialPriceDateRang($product),
136112
'discount_perc' => $this->getDiscountPercentage(),
137-
'tax' => abs(1 - $percent) * 100
113+
'tax' => abs(1 - ($percent/$rate)) * 100,
114+
'currency' => $this->currecy
138115
];
139116
}
140117

141118
return $result ?? [];
142119
}
143120

121+
/**
122+
* Calculate price multiplier including tax adjustments and currency rate differences.
123+
*
124+
* Returns a float multiplier based on the processed price (incl. tax) and original price,
125+
* potentially adjusted for base-to-store currency conversion.
126+
*
127+
* @param Product $product The product for which to calculate the price multiplier.
128+
* @param StoreInterface|null $store The store context used to resolve tax and currency.
129+
* @return float The price multiplier relative to base price.
130+
*/
131+
private function getPercentage(Product $product, ?StoreInterface $store): float
132+
{
133+
$taxClassId = (int)$product->getTaxClassId();
134+
135+
if (isset($this->taxClasses[$taxClassId])) {
136+
return $this->taxClasses[$taxClassId];
137+
}
138+
139+
if ($this->price == 0.0) {
140+
$percent = 1.0;
141+
} else {
142+
$processed = $this->processPrice($product, (float)$this->price, $store);
143+
$percent = round($processed / $this->price, 2);
144+
}
145+
146+
// Adjust for currency difference
147+
if ($store->getBaseCurrencyCode() !== $this->currecy) {
148+
$rate = $store->getBaseCurrency()->getRate($this->currecy);
149+
if ($rate > 0) {
150+
$percent *= $rate;
151+
}
152+
}
153+
154+
$this->taxClasses[$taxClassId] = $percent;
155+
return $percent;
156+
}
157+
144158
/**
145159
* @param int $storeId
146160
* @return StoreInterface|null
@@ -178,14 +192,18 @@ public function setData($type, $data)
178192

179193
/**
180194
* @param array $productIds
195+
* @param int $storeId
181196
* @return Collection|AbstractDb
182197
*/
183-
private function getProductData(array $productIds = [])
198+
private function getProductData(array $productIds = [], int $storeId = 0)
184199
{
185200
$products = $this->collectionFactory->create()
186201
->addFieldToSelect(['price', 'special_price', 'tax_class_id', 'special_from_date', 'special_to_date'])
187-
->addFieldToFilter('entity_id', ['in' => $productIds]);
202+
->addFieldToFilter('entity_id', ['in' => $productIds])
203+
->addStoreFilter($storeId)
204+
->setStoreId($storeId);
188205

206+
// Join the price attributes
189207
$products->getSelect()->joinLeft(
190208
['price_index' => $products->getTable('catalog_product_index_price')],
191209
join(
@@ -256,6 +274,11 @@ private function setPrices(Product $product, ?string $groupedPriceType, ?string
256274
}
257275
}
258276

277+
private function round($price)
278+
{
279+
return round((float)$price, 2);
280+
}
281+
259282
/**
260283
* @param Product $product
261284
*/
@@ -412,7 +435,6 @@ private function getRulePrice(Product $product): float
412435
*/
413436
private function processPrice(Product $product, float $price, ?StoreInterface $store): float
414437
{
415-
416438
return (float)$this->catalogHelper->getTaxPrice(
417439
$product,
418440
$price,

0 commit comments

Comments
 (0)