--- /dev/null
+<?php
+
+use yii\helpers\Html;
+use yii\widgets\ActiveForm;
+
+/* @var $this yii\web\View */
+/* @var $uploadedData array */
+/* @var $mismatchedChecks array */
+/* @var $availableDates array */
+/* @var $storeGuidNames array */
+
+$this->title = 'Проверка несовпадения дат чеков';
+?>
+
+<div class="check-mismatch-container" style="max-width: 1400px; margin: 0 auto; padding: 20px;">
+ <h1><?= Html::encode($this->title) ?></h1>
+
+ <!-- Форма загрузки файла -->
+ <div class="upload-section" style="background-color: #f9f9f9; padding: 20px; border-radius: 5px; margin-bottom: 20px;">
+ <h2>Загрузить JSON файл</h2>
+ <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data', 'method' => 'post']]); ?>
+ <div class="form-group">
+ <label for="jsonFile">Выберите JSON файл:</label>
+ <input type="file" id="jsonFile" name="jsonFile" accept=".json" class="form-control" required>
+ </div>
+ <div class="form-group">
+ <?= Html::submitButton('Загрузить и анализировать', ['class' => 'btn btn-primary']) ?>
+ </div>
+ <?php ActiveForm::end(); ?>
+ </div>
+
+ <!-- Фильтры (отображаются только если файл был загружен) -->
+ <?php if ($uploadedData && count($availableDates) > 0): ?>
+ <div class="filters-section" style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin-bottom: 20px;">
+ <h3>Фильтры</h3>
+ <form method="get" id="filters-form" style="display: flex; gap: 15px; flex-wrap: wrap; align-items: center;">
+ <!-- Фильтр по дате -->
+ <div style="flex: 1; min-width: 200px;">
+ <label for="dateFilter" style="display: block; margin-bottom: 5px;">Дата:</label>
+ <select id="dateFilter" name="date" class="form-control" onchange="applyFilters()">
+ <option value="">Все даты</option>
+ <?php foreach ($availableDates as $date): ?>
+ <option value="<?= Html::encode($date) ?>">
+ <?= Html::encode($date) ?>
+ </option>
+ <?php endforeach; ?>
+ </select>
+ </div>
+
+ <!-- Фильтр по магазину (динамически заполняется из данных) -->
+ <div style="flex: 1; min-width: 200px;">
+ <label for="storeFilter" style="display: block; margin-bottom: 5px;">Магазин:</label>
+ <select id="storeFilter" name="store" class="form-control" onchange="applyFilters()">
+ <option value="">Все магазины</option>
+ <?php
+ $stores = [];
+ foreach ($mismatchedChecks as $check) {
+ if (!empty($check['store_id']) && !isset($stores[$check['store_id']])) {
+ $stores[$check['store_id']] = $check['store_id'];
+ }
+ }
+ foreach ($stores as $storeId): ?>
+ <option value="<?= Html::encode($storeId) ?>">
+ <?= Html::encode($storeGuidNames[$storeId] ?? $storeId) ?>
+ </option>
+ <?php endforeach; ?>
+ </select>
+ </div>
+
+ <!-- Кнопка очистки фильтров -->
+ <div style="padding-top: 20px;">
+ <button type="button" class="btn btn-secondary" onclick="clearFilters()">Очистить фильтры</button>
+ </div>
+ </form>
+ </div>
+
+ <!-- Информация о результатах -->
+ <div class="results-info" style="background-color: #e8f4f8; padding: 15px; border-radius: 5px; margin-bottom: 20px; border-left: 4px solid #0275d8;">
+ <strong>Всего несовпадений:</strong> <?= count($mismatchedChecks) ?><br>
+ <strong>Всего чеков в файле:</strong> <?= count($uploadedData['checks']) ?><br>
+ <strong>Чеков с order_id:</strong> <?= count(array_filter($uploadedData['checks'], function($c) { return !empty($c['order_id']); })) ?>
+ </div>
+
+ <!-- Таблица результатов -->
+ <?php if (count($mismatchedChecks) > 0): ?>
+ <div class="results-table" style="overflow-x: auto;">
+ <h3>Несовпадающие чеки</h3>
+ <table class="table table-striped table-hover" style="background-color: white;">
+ <thead style="background-color: #f8f9fa;">
+ <tr>
+ <th>Магазин</th>
+ <th>ID чека</th>
+ <th>Order ID</th>
+ <th>Дата чека (JSON)</th>
+ <th>Дата чека (Create Checks)</th>
+ <th>Дата продажи (Sales)</th>
+ <th>Тип</th>
+ <th>Статус</th>
+ <th>Номер чека</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($mismatchedChecks as $check): ?>
+ <tr style="border-left: 3px solid #dc3545;">
+ <td>
+ <strong><?= Html::encode($storeGuidNames[$check['store_id']] ?? $check['store_id']) ?></strong><br>
+ <code style="font-size: 10px;"><?= Html::encode($check['store_id']) ?></code>
+ </td>
+ <td><code style="font-size: 11px;"><?= Html::encode(substr($check['check_id'], 0, 20) . '...') ?></code></td>
+ <td><strong><?= Html::encode($check['order_id']) ?></strong></td>
+ <td>
+ <span style="background-color: #fff3cd; padding: 2px 6px; border-radius: 3px;">
+ <?= Html::encode($check['check_date']) ?>
+ </span>
+ </td>
+ <td>
+ <span style="background-color: #f8d7da; padding: 2px 6px; border-radius: 3px;">
+ <?= Html::encode($check['create_check_date']) ?>
+ </span>
+ </td>
+ <td>
+ <span style="background-color: #d4edda; padding: 2px 6px; border-radius: 3px;">
+ <?= Html::encode($check['sales_date']) ?>
+ </span>
+ </td>
+ <td><?= Html::encode($check['check_type']) ?></td>
+ <td><?= Html::encode($check['check_status']) ?></td>
+ <td><?= Html::encode($check['check_number']) ?></td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+ </div>
+ <?php else: ?>
+ <div class="alert alert-success" role="alert">
+ ✓ Несовпадающих чеков не найдено. Все даты корректны!
+ </div>
+ <?php endif; ?>
+
+ <?php elseif ($uploadedData): ?>
+ <div class="alert alert-info" role="alert">
+ ℹ️ Файл загружен, но чеков с order_id не найдено или на нет несовпадений.
+ </div>
+ <?php endif; ?>
+</div>
+
+<style>
+ .check-mismatch-container {
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ }
+
+ .upload-section, .filters-section {
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ }
+
+ .table {
+ width: 100%;
+ border-collapse: collapse;
+ }
+
+ .table thead th {
+ font-weight: 600;
+ text-align: left;
+ padding: 12px;
+ border-bottom: 2px solid #dee2e6;
+ }
+
+ .table tbody td {
+ padding: 10px 12px;
+ border-bottom: 1px solid #dee2e6;
+ }
+
+ .table tbody tr:hover {
+ background-color: #f9f9f9;
+ }
+
+ .btn {
+ padding: 8px 16px;
+ border-radius: 4px;
+ border: none;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ }
+
+ .btn-primary {
+ background-color: #0275d8;
+ color: white;
+ }
+
+ .btn-primary:hover {
+ background-color: #025aa5;
+ }
+
+ .btn-secondary {
+ background-color: #6c757d;
+ color: white;
+ }
+
+ .btn-secondary:hover {
+ background-color: #5a6268;
+ }
+
+ .form-control {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid #ced4da;
+ border-radius: 4px;
+ font-size: 14px;
+ }
+
+ .form-control:focus {
+ outline: none;
+ border-color: #0275d8;
+ box-shadow: 0 0 0 3px rgba(2, 117, 216, 0.25);
+ }
+
+ .form-group {
+ margin-bottom: 15px;
+ }
+
+ code {
+ background-color: #f5f5f5;
+ padding: 2px 6px;
+ border-radius: 3px;
+ font-family: 'Courier New', monospace;
+ }
+
+ .alert {
+ padding: 15px;
+ border-radius: 4px;
+ margin-bottom: 20px;
+ }
+
+ .alert-success {
+ background-color: #d4edda;
+ color: #155724;
+ border: 1px solid #c3e6cb;
+ }
+
+ .alert-info {
+ background-color: #d1ecf1;
+ color: #0c5460;
+ border: 1px solid #bee5eb;
+ }
+</style>
+
+<script>
+// Сохранение оригинальных данных чеков в памяти
+const allMismatchedChecks = <?= json_encode($mismatchedChecks, JSON_UNESCAPED_UNICODE) ?>;
+const storeGuidNames = <?= json_encode($storeGuidNames, JSON_UNESCAPED_UNICODE) ?>;
+
+function applyFilters() {
+ const dateFilter = document.getElementById('dateFilter').value;
+ const storeFilter = document.getElementById('storeFilter').value;
+
+ // Фильтруем данные
+ let filteredChecks = allMismatchedChecks;
+
+ if (dateFilter) {
+ filteredChecks = filteredChecks.filter(check => check.sales_date.startsWith(dateFilter));
+ }
+
+ if (storeFilter) {
+ filteredChecks = filteredChecks.filter(check => check.store_id === storeFilter);
+ }
+
+ // Обновляем таблицу
+ updateTable(filteredChecks);
+
+ // Обновляем информацию о результатах
+ document.querySelector('.results-info').innerHTML = `
+ <strong>Всего несовпадений:</strong> ${filteredChecks.length}<br>
+ <strong>Всего чеков в файле:</strong> ${allMismatchedChecks.length}<br>
+ <strong>Чеков с order_id:</strong> ${allMismatchedChecks.length}
+ `;
+}
+
+function updateTable(checks) {
+ const tbody = document.querySelector('.table tbody');
+
+ if (!tbody) return;
+
+ if (checks.length === 0) {
+ tbody.innerHTML = `
+ <tr>
+ <td colspan="9" style="text-align: center; padding: 30px; color: #999;">
+ По выбранным фильтрам результатов не найдено
+ </td>
+ </tr>
+ `;
+ return;
+ }
+
+ tbody.innerHTML = checks.map(check => `
+ <tr style="border-left: 3px solid #dc3545;">
+ <td>
+ <strong>${escapeHtml(storeGuidNames[check.store_id] || check.store_id)}</strong><br>
+ <code style="font-size: 10px;">${escapeHtml(check.store_id)}</code>
+ </td>
+ <td><code style="font-size: 11px;">${escapeHtml(check.check_id.substring(0, 20) + '...')}</code></td>
+ <td><strong>${escapeHtml(check.order_id)}</strong></td>
+ <td>
+ <span style="background-color: #fff3cd; padding: 2px 6px; border-radius: 3px;">
+ ${escapeHtml(check.check_date)}
+ </span>
+ </td>
+ <td>
+ <span style="background-color: #f8d7da; padding: 2px 6px; border-radius: 3px;">
+ ${escapeHtml(check.create_check_date)}
+ </span>
+ </td>
+ <td>
+ <span style="background-color: #d4edda; padding: 2px 6px; border-radius: 3px;">
+ ${escapeHtml(check.sales_date)}
+ </span>
+ </td>
+ <td>${escapeHtml(check.check_type)}</td>
+ <td>${escapeHtml(check.check_status)}</td>
+ <td>${escapeHtml(check.check_number)}</td>
+ </tr>
+ `).join('');
+}
+
+function clearFilters() {
+ document.getElementById('dateFilter').value = '';
+ document.getElementById('storeFilter').value = '';
+ updateTable(allMismatchedChecks);
+
+ // Обновляем информацию о результатах
+ document.querySelector('.results-info').innerHTML = `
+ <strong>Всего несовпадений:</strong> ${allMismatchedChecks.length}<br>
+ <strong>Всего чеков в файле:</strong> ${allMismatchedChecks.length}<br>
+ <strong>Чеков с order_id:</strong> ${allMismatchedChecks.length}
+ `;
+}
+
+function escapeHtml(text) {
+ const div = document.createElement('div');
+ div.textContent = text;
+ return div.innerHTML;
+}
+</script>