23 private const OPTION_NAME =
'cost_price_calculation_method';
25 private static string $method;
26 private static bool $isUsedInventoryManagement;
38 $this->batchManager = $batchManager;
40 $this->isCurrencyModuleIncluded = Loader::includeModule(
'currency');
50 self::$method ??= Option::get(
'catalog', self::OPTION_NAME);
62 public static function setMethod(
string $method): void
64 self::$method = ($method === self::METHOD_FIFO) ? self::METHOD_FIFO : self::METHOD_AVERAGE;
66 Option::set(
'catalog', self::OPTION_NAME, self::$method);
62 public static function setMethod(
string $method): void {
…}
69 private static function isUsedInventoryManagement(): bool
71 static::$isUsedInventoryManagement ??= State::isUsedInventoryManagement();
73 return static::$isUsedInventoryManagement;
76 private function getCatalogPurchasingFields(): ?
array
78 if ($this->productFields ===
null)
81 'filter' => [
'=ID' => $this->batchManager->getProductId()],
82 'select' => [
'PURCHASING_PRICE',
'PURCHASING_CURRENCY'],
83 'cache' => [
'ttl' => 3600]
91 private function getCatalogPurchasingPrice(): float
93 return (
float)($this->getCatalogPurchasingFields()[
'PURCHASING_PRICE'] ?? 0);
96 private function getCatalogPurchasingCurrency(): string
98 return (
string)($this->getCatalogPurchasingFields()[
'PURCHASING_CURRENCY'] ??
'');
112 if ($quantity <= 0 || !self::isUsedInventoryManagement())
114 $catalogPrice = $this->getCatalogPurchasingPrice();
118 || !$this->isCurrencyModuleIncluded
119 ||
$currency === $this->getCatalogPurchasingCurrency()
122 return $catalogPrice;
125 return \CCurrencyRates::convertCurrency($catalogPrice, $this->getCatalogPurchasingCurrency(),
$currency);
128 if (self::getMethod() === self::METHOD_FIFO)
130 return $this->calculateFifo($quantity, $storeId,
$currency);
133 return $this->calculateAverage($storeId,
$currency);
136 private function calculateFifo(
float $quantity,
int $storeId,
string $currency =
null): float
140 foreach ($this->batchManager->getAvailableStoreCollection($storeId) as $item)
142 $itemAvailableAmount = $item->getAvailableAmount();
143 $itemPurchasingPrice = $item->getPurchasingPrice();
144 if ($this->isCurrencyModuleIncluded &&
$currency && $item->getPurchasingCurrency() !==
$currency)
146 $itemPurchasingPrice = \CCurrencyRates::convertCurrency(
147 $itemPurchasingPrice,
148 $item->getPurchasingCurrency(),
153 if ($itemAvailableAmount >= $quantity)
155 $commonAmount += $quantity;
156 $commonSum += ($itemPurchasingPrice * $quantity);
161 $quantity -= $itemAvailableAmount;
162 $commonAmount += $itemAvailableAmount;
163 $commonSum += ($itemPurchasingPrice * $itemAvailableAmount);
166 if ($commonAmount === 0)
168 return $this->getCatalogPurchasingPrice();
171 return $this->roundCalculation($commonSum / $commonAmount);
174 private function calculateAverage(
int $storeId,
string $currency =
null): float
176 $batchCollection = $this->batchManager->getAvailableStoreCollection($storeId);
177 $batch = $batchCollection->current();
181 $itemPurchasingPrice = $this->getCatalogPurchasingPrice();
182 $itemPurchasingCurrency = $this->getCatalogPurchasingCurrency();
186 $itemPurchasingPrice = $batch->getPurchasingPrice();
187 $itemPurchasingCurrency = $batch->getPurchasingCurrency();
191 $itemPurchasingPrice > 0
192 && $this->isCurrencyModuleIncluded
197 $itemPurchasingPrice = \CCurrencyRates::convertCurrency(
198 $itemPurchasingPrice,
199 $itemPurchasingCurrency,
204 return $this->roundCalculation($itemPurchasingPrice);
207 private function roundCalculation(
float $value): float
209 return round($value, $this->getRoundPrecision());
212 private function getRoundPrecision(): int
214 return (
int)Option::get(
'sale',
'value_precision', 2);
220 self::METHOD_AVERAGE => Loc::getMessage(
'COST_PRICE_CALCULATION_MODE_AVERAGE'),
221 self::METHOD_FIFO => Loc::getMessage(
'COST_PRICE_CALCULATION_MODE_FIFO'),
static getRow(array $parameters)