Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
costpricecalculator.php
1<?php
3
9use phpDocumentor\Reflection\Types\Boolean;
10
19{
20 public const METHOD_FIFO = 'fifo';
21 public const METHOD_AVERAGE = 'average';
22 private const OPTION_NAME = 'cost_price_calculation_method';
23
24 private static string $method;
25 private static bool $isUsedInventoryManagement;
26
27 protected ?array $productFields = null;
29
30 private BatchManager $batchManager;
31
35 public function __construct(BatchManager $batchManager)
36 {
37 $this->batchManager = $batchManager;
38
39 $this->isCurrencyModuleIncluded = Loader::includeModule('currency');
40 }
41
47 public static function getMethod(): string
48 {
49 self::$method ??= Option::get('catalog', self::OPTION_NAME);
50
51 return self::$method;
52 }
53
61 public static function setMethod(string $method): void
62 {
63 self::$method = ($method === self::METHOD_FIFO) ? self::METHOD_FIFO : self::METHOD_AVERAGE;
64
65 Option::set('catalog', self::OPTION_NAME, self::$method);
66 }
67
68 private static function isUsedInventoryManagement(): bool
69 {
70 static::$isUsedInventoryManagement ??= State::isUsedInventoryManagement();
71
72 return static::$isUsedInventoryManagement;
73 }
74
75 private function getCatalogPurchasingFields(): ?array
76 {
77 if ($this->productFields === null)
78 {
79 $this->productFields = ProductTable::getRow([
80 'filter' => ['=ID' => $this->batchManager->getProductId()],
81 'select' => ['PURCHASING_PRICE', 'PURCHASING_CURRENCY'],
82 'cache' => ['ttl' => 3600]
83 ]);
84
85 }
86
88 }
89
90 private function getCatalogPurchasingPrice(): float
91 {
92 return (float)($this->getCatalogPurchasingFields()['PURCHASING_PRICE'] ?? 0);
93 }
94
95 private function getCatalogPurchasingCurrency(): string
96 {
97 return (string)($this->getCatalogPurchasingFields()['PURCHASING_CURRENCY'] ?? '');
98 }
99
109 public function calculate(float $quantity, int $storeId, string $currency = null): float
110 {
111 if ($quantity <= 0 || !self::isUsedInventoryManagement())
112 {
113 $catalogPrice = $this->getCatalogPurchasingPrice();
114
115 if (
116 empty($currency)
117 || !$this->isCurrencyModuleIncluded
118 || $currency === $this->getCatalogPurchasingCurrency()
119 )
120 {
121 return $catalogPrice;
122 }
123
124 return \CCurrencyRates::convertCurrency($catalogPrice, $this->getCatalogPurchasingCurrency(), $currency);
125 }
126
127 if (self::getMethod() === self::METHOD_FIFO)
128 {
129 return $this->calculateFifo($quantity, $storeId, $currency);
130 }
131
132 return $this->calculateAverage($storeId, $currency);
133 }
134
135 private function calculateFifo(float $quantity, int $storeId, string $currency = null): float
136 {
137 $commonAmount = 0;
138 $commonSum = 0;
139 foreach ($this->batchManager->getAvailableStoreCollection($storeId) as $item)
140 {
141 $itemAvailableAmount = $item->getAvailableAmount();
142 $itemPurchasingPrice = $item->getPurchasingPrice();
143 if ($this->isCurrencyModuleIncluded && $currency && $item->getPurchasingCurrency() !== $currency)
144 {
145 $itemPurchasingPrice = \CCurrencyRates::convertCurrency(
146 $itemPurchasingPrice,
147 $item->getPurchasingCurrency(),
148 $currency
149 );
150 }
151
152 if ($itemAvailableAmount >= $quantity)
153 {
154 $commonAmount += $quantity;
155 $commonSum += ($itemPurchasingPrice * $quantity);
156
157 break;
158 }
159
160 $quantity -= $itemAvailableAmount;
161 $commonAmount += $itemAvailableAmount;
162 $commonSum += ($itemPurchasingPrice * $itemAvailableAmount);
163 }
164
165 if ($commonAmount === 0)
166 {
167 return $this->getCatalogPurchasingPrice();
168 }
169
170 return $this->roundCalculation($commonSum / $commonAmount);
171 }
172
173 private function calculateAverage(int $storeId, string $currency = null): float
174 {
175 $batchCollection = $this->batchManager->getAvailableStoreCollection($storeId);
176 $batch = $batchCollection->current();
177
178 if (!$batch)
179 {
180 $itemPurchasingPrice = $this->getCatalogPurchasingPrice();
181 $itemPurchasingCurrency = $this->getCatalogPurchasingCurrency();
182 }
183 else
184 {
185 $itemPurchasingPrice = $batch->getPurchasingPrice();
186 $itemPurchasingCurrency = $batch->getPurchasingCurrency();
187 }
188
189 if (
190 $itemPurchasingPrice > 0
191 && $this->isCurrencyModuleIncluded
192 && $currency
193 && $itemPurchasingCurrency !== $currency
194 )
195 {
196 $itemPurchasingPrice = \CCurrencyRates::convertCurrency(
197 $itemPurchasingPrice,
198 $itemPurchasingCurrency,
199 $currency
200 );
201 }
202
203 return $this->roundCalculation($itemPurchasingPrice);
204 }
205
206 private function roundCalculation(float $value): float
207 {
208 return round($value, $this->getRoundPrecision());
209 }
210
211 private function getRoundPrecision(): int
212 {
213 return (int)Option::get('sale', 'value_precision', 2);
214 }
215}
calculate(float $quantity, int $storeId, string $currency=null)
static getRow(array $parameters)