Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
Doctor.php
1<?php
2
4
10
35final class Doctor
36{
44 private function getSql(): string
45 {
47 $helper = $conn->getSqlHelper();
48 return '
49 SELECT
50 cp.ID AS ' . $helper->quote('PRODUCT_ID') . ',
51 cp.QUANTITY AS ' . $helper->quote('PRODUCT_QUANTITY_AVAILABLE') . ',
52 csp.QUANTITY_AVAILABLE AS ' . $helper->quote('STORE_QUANTITY_AVAILABLE') . ',
53 cp.QUANTITY_RESERVED AS ' . $helper->quote('PRODUCT_QUANTITY_RESERVED') . ',
54 csp.QUANTITY_RESERVED AS ' . $helper->quote('STORE_QUANTITY_RESERVED') . ',
55 sbr.QUANTITY_RESERVED AS ' . $helper->quote('SALE_QUANTITY_RESERVED') . '
56 FROM
57 b_catalog_product AS cp
58 LEFT JOIN (
59 SELECT
60 PRODUCT_ID,
61 SUM(AMOUNT) as QUANTITY,
62 SUM(QUANTITY_RESERVED) as QUANTITY_RESERVED,
63 SUM(AMOUNT - QUANTITY_RESERVED) as QUANTITY_AVAILABLE
64 FROM
65 b_catalog_store_product
66 INNER JOIN b_catalog_store ON b_catalog_store.ID = b_catalog_store_product.STORE_ID AND b_catalog_store.ACTIVE = \'Y\'
67 GROUP BY PRODUCT_ID
68 ) as csp ON cp.ID = csp.PRODUCT_ID
69 LEFT JOIN (
70 SELECT
71 sb.PRODUCT_ID,
72 SUM(sbr.QUANTITY) AS QUANTITY_RESERVED
73 FROM
74 b_sale_basket AS sb
75 LEFT JOIN b_sale_basket_reservation AS sbr ON sbr.BASKET_ID = sb.ID AND sbr.QUANTITY != 0
76 WHERE
77 sb.PRODUCT_ID > 0
78 AND sbr.QUANTITY != 0
79 GROUP BY sb.PRODUCT_ID
80 ) as sbr ON cp.ID = sbr.PRODUCT_ID
81 WHERE
82 (
83 cp.QUANTITY != 0
84 OR cp.QUANTITY_RESERVED != 0
85 OR csp.QUANTITY != 0
86 OR csp.QUANTITY_RESERVED != 0
87 OR csp.QUANTITY_AVAILABLE != 0
88 OR sbr.QUANTITY_RESERVED != 0
89 )
90 ';
91 }
92
98 public function printProblems(): void
99 {
100 $sql = $this->getSql() . ' AND (
101 cp.QUANTITY != csp.QUANTITY_AVAILABLE OR csp.QUANTITY_AVAILABLE IS NULL
102 OR cp.QUANTITY_RESERVED != csp.QUANTITY_RESERVED OR csp.QUANTITY_RESERVED IS NULL
103 OR sbr.QUANTITY_RESERVED > cp.QUANTITY_RESERVED
104 OR cp.QUANTITY_RESERVED < 0
105 OR csp.QUANTITY_RESERVED < 0
106 )';
107
108 $result = [];
109
110 $rows = Application::getConnection()->query($sql);
111 foreach ($rows as $row)
112 {
113 $problems = [];
114
115 $storeReserveQuantity = (float)$row['STORE_QUANTITY_RESERVED'];
116 $productReserveQuantity = (float)$row['PRODUCT_QUANTITY_RESERVED'];
117
118 if ((float)$row['PRODUCT_QUANTITY_AVAILABLE'] !== (float)$row['STORE_QUANTITY_AVAILABLE'])
119 {
120 $problems[] = 'Available quantity not match';
121 }
122
123 if ($productReserveQuantity !== $storeReserveQuantity)
124 {
125 $problems[] = 'Reserve quantity not match';
126 }
127
128 if ($productReserveQuantity < 0.0)
129 {
130 $problems[] = 'Product reserve quantity less than 0';
131 }
132
133 if ($storeReserveQuantity < 0.0)
134 {
135 $problems[] = 'Store reserve quantity less than 0';
136 }
137
138 if ((float)$row['SALE_QUANTITY_RESERVED'] > $productReserveQuantity)
139 {
140 $problems[] = 'More is reserved in \'sale\' than in \'catalog\'';
141 }
142
143 if (empty($problems))
144 {
145 $problems[] = 'Unknown, check SQL';
146 }
147
148 $result[] = ['PROBLEMS' => join('; ', $problems)] + $row;
149 }
150
151 $this->printTable($result);
152 }
153
159 public function printInfo(): void
160 {
161 $this->printTable(
162 Application::getConnection()->query($this->getSql())->fetchAll()
163 );
164 }
165
171 private function printTable(array $rows): void
172 {
173 if (empty($rows))
174 {
175 echo '-- empty --';
176 return;
177 }
178
179 $headers = array_keys(
180 current($rows)
181 );
182
183 echo '<table border="1" cellspacing="0" cellpadding="2"><tr>';
184 foreach ($headers as $header)
185 {
186 echo '<th>' . HtmlFilter::encode($header) . '</th>';
187 }
188
189 foreach ($rows as $row)
190 {
191 echo '<tr>';
192
193 foreach ($headers as $header)
194 {
195 $value = isset($row[$header]) && $row[$header] !== '' ? $row[$header] : '-';
196 echo '<td>' . HtmlFilter::encode($value) . '</td>';
197 }
198
199 echo '</td>';
200 }
201
202 echo '</table>';
203 }
204
212 public function fixQuantitiesFromStores(int ...$productIds): void
213 {
214 if (empty($productIds))
215 {
216 throw new ArgumentNullException('productIds');
217 }
218
219 $result = [];
220
221 $productIdsSql = join(',', $productIds);
222 $sql = "
223 SELECT
224 PRODUCT_ID,
225 SUM(AMOUNT) as QUANTITY
226 FROM
227 b_catalog_store_product
228 INNER JOIN b_catalog_store ON b_catalog_store.ID = b_catalog_store_product.STORE_ID AND b_catalog_store.ACTIVE = 'Y'
229 WHERE
230 PRODUCT_ID IN ({$productIdsSql})
231 GROUP BY
232 PRODUCT_ID
233 ";
234 $rows = Application::getConnection()->query($sql);
235 foreach ($rows as $row)
236 {
237 $productId = (int)$row['PRODUCT_ID'];
238
239 $result[$productId] = [
240 'PRODUCT_ID' => $productId,
241 'NEW_QUANTITY' => (float)$row['QUANTITY'],
242 ];
243 }
244
245 // fill products without store quantities
246 foreach ($productIds as $productId)
247 {
248 $result[$productId] ??= [
249 'PRODUCT_ID' => $productId,
250 'NEW_QUANTITY' => 0.0,
251 ];
252 }
253
254 // update products
255 foreach ($result as $productId => &$item)
256 {
257 // or \Bitrix\Catalog\Model\Product::update ?
258 $saveResult = ProductTable::update($productId, [
259 'QUANTITY' => $item['NEW_QUANTITY'],
260 ]);
261 $item['SAVE_RESULT'] =
262 $saveResult->isSuccess()
263 ? 'ok'
264 : join(', ', $saveResult->getErrorMessages())
265 ;
266 }
267
268 $this->printTable($result);
269 }
270
278 public function fixReservesFromStores(int ...$productIds): void
279 {
280 if (empty($productIds))
281 {
282 throw new ArgumentNullException('productIds');
283 }
284
285 $result = [];
286
287 $productIdsSql = join(',', $productIds);
288 $sql = "
289 SELECT
290 PRODUCT_ID,
291 SUM(QUANTITY_RESERVED) as QUANTITY_RESERVED
292 FROM
293 b_catalog_store_product
294 INNER JOIN b_catalog_store ON b_catalog_store.ID = b_catalog_store_product.STORE_ID AND b_catalog_store.ACTIVE = 'Y'
295 WHERE
296 PRODUCT_ID IN ({$productIdsSql})
297 GROUP BY
298 PRODUCT_ID
299 ";
300 $rows = Application::getConnection()->query($sql);
301 foreach ($rows as $row)
302 {
303 $productId = (int)$row['PRODUCT_ID'];
304
305 $result[$productId] = [
306 'PRODUCT_ID' => $productId,
307 'NEW_QUANTITY_RESERVED' => (float)$row['QUANTITY_RESERVED'],
308 ];
309 }
310
311 // fill products without store quantities
312 foreach ($productIds as $productId)
313 {
314 $result[$productId] ??= [
315 'PRODUCT_ID' => $productId,
316 'NEW_QUANTITY_RESERVED' => 0.0,
317 ];
318 }
319
320 // update products
321 foreach ($result as $productId => &$item)
322 {
323 // or \Bitrix\Catalog\Model\Product::update ?
324 $saveResult = ProductTable::update($productId, [
325 'QUANTITY_RESERVED' => $item['NEW_QUANTITY_RESERVED'],
326 ]);
327 $item['SAVE_RESULT'] =
328 $saveResult->isSuccess()
329 ? 'ok'
330 : join(', ', $saveResult->getErrorMessages())
331 ;
332 }
333
334 $this->printTable($result);
335 }
336
343 public function fixReservesLessZero(): void
344 {
346
347 // products
348 $db->queryExecute(
349 'UPDATE b_catalog_product SET QUANTITY_RESERVED = 0 WHERE QUANTITY_RESERVED < 0'
350 );
351 if ($db->getAffectedRowsCount() > 0)
352 {
354 }
355
356 // stores
357 $db->queryExecute(
358 'UPDATE b_catalog_store_product SET QUANTITY_RESERVED = 0 WHERE QUANTITY_RESERVED < 0'
359 );
360 if ($db->getAffectedRowsCount() > 0)
361 {
363 }
364 }
365}
static getConnection($name="")
static update($primary, array $data)
static encode($string, $flags=ENT_COMPAT, $doubleEncode=true)