Add Orders and Order Status repositories with pagination and management features

- Implemented OrdersRepository for handling order data with pagination, filtering, and sorting capabilities.
- Added methods for retrieving order status options, quick stats, and detailed order information.
- Created OrderStatusRepository for managing order status groups and statuses, including CRUD operations and sorting.
- Introduced a bootstrap file for test environment setup and autoloading.
This commit is contained in:
2026-03-03 01:32:28 +01:00
parent d1576bc4ab
commit c489891d15
106 changed files with 11669 additions and 5091 deletions

View File

@@ -0,0 +1,156 @@
<?php
$schedulesList = is_array($schedules ?? null) ? $schedules : [];
$futureList = is_array($futureJobs ?? null) ? $futureJobs : [];
$pastList = is_array($pastJobs ?? null) ? $pastJobs : [];
$runOnWeb = ($runOnWebEnabled ?? false) === true;
$webLimit = max(1, (int) ($webCronLimit ?? 5));
?>
<section class="card">
<h1><?= $e($t('settings.title')) ?></h1>
<p class="muted"><?= $e($t('settings.description')) ?></p>
<nav class="settings-nav mt-16" aria-label="<?= $e($t('settings.submenu_label')) ?>">
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'database' ? ' is-active' : '' ?>" href="/settings/database"><?= $e($t('settings.database.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'integrations' ? ' is-active' : '' ?>" href="/settings/integrations/shoppro"><?= $e($t('settings.integrations.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'order_statuses' ? ' is-active' : '' ?>" href="/settings/order-statuses"><?= $e($t('settings.order_statuses.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'cron' ? ' is-active' : '' ?>" href="/settings/cron"><?= $e($t('settings.cron.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'gs1' ? ' is-active' : '' ?>" href="/settings/gs1"><?= $e($t('settings.gs1.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'products' ? ' is-active' : '' ?>" href="/settings/products"><?= $e($t('settings.products.title')) ?></a>
</nav>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.cron.run_on_web_title')) ?></h2>
<p class="muted mt-12"><?= $e($t('settings.cron.run_on_web_description')) ?></p>
<?php if (!empty($errorMessage)): ?>
<div class="alert alert--danger mt-12" role="alert"><?= $e((string) $errorMessage) ?></div>
<?php endif; ?>
<?php if (!empty($successMessage)): ?>
<div class="alert alert--success mt-12" role="status"><?= $e((string) $successMessage) ?></div>
<?php endif; ?>
<form action="/settings/cron/save" method="post" class="mt-16">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<label class="form-field">
<span class="field-label">
<input type="checkbox" name="cron_run_on_web" value="1"<?= $runOnWeb ? ' checked' : '' ?>>
<?= $e($t('settings.cron.run_on_web_label')) ?>
</span>
</label>
<label class="form-field mt-12">
<span class="field-label"><?= $e($t('settings.cron.web_limit')) ?></span>
<input class="form-control" type="number" min="1" max="100" name="cron_web_limit" value="<?= $e((string) $webLimit) ?>">
</label>
<div class="form-actions mt-16">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.cron.actions.save')) ?></button>
</div>
</form>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.cron.schedules_title')) ?></h2>
<div class="table-wrap mt-12">
<table class="table">
<thead>
<tr>
<th><?= $e($t('settings.cron.fields.job_type')) ?></th>
<th><?= $e($t('settings.cron.fields.enabled')) ?></th>
<th><?= $e($t('settings.cron.fields.interval')) ?></th>
<th><?= $e($t('settings.cron.fields.priority')) ?></th>
<th><?= $e($t('settings.cron.fields.next_run_at')) ?></th>
<th><?= $e($t('settings.cron.fields.last_run_at')) ?></th>
</tr>
</thead>
<tbody>
<?php if ($schedulesList === []): ?>
<tr><td colspan="6" class="muted"><?= $e($t('settings.cron.empty_schedules')) ?></td></tr>
<?php else: ?>
<?php foreach ($schedulesList as $row): ?>
<tr>
<td><?= $e((string) ($row['job_type'] ?? '')) ?></td>
<td><?= $e(((bool) ($row['enabled'] ?? false)) ? $t('settings.cron.enabled.yes') : $t('settings.cron.enabled.no')) ?></td>
<td><?= $e((string) ((int) ($row['interval_seconds'] ?? 0))) ?></td>
<td><?= $e((string) ((int) ($row['priority'] ?? 0))) ?></td>
<td><?= $e((string) (($row['next_run_at'] ?? null) ?? '-')) ?></td>
<td><?= $e((string) (($row['last_run_at'] ?? null) ?? '-')) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.cron.future_jobs_title')) ?></h2>
<div class="table-wrap mt-12">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th><?= $e($t('settings.cron.fields.job_type')) ?></th>
<th><?= $e($t('settings.cron.fields.status')) ?></th>
<th><?= $e($t('settings.cron.fields.priority')) ?></th>
<th><?= $e($t('settings.cron.fields.scheduled_at')) ?></th>
<th><?= $e($t('settings.cron.fields.attempts')) ?></th>
</tr>
</thead>
<tbody>
<?php if ($futureList === []): ?>
<tr><td colspan="6" class="muted"><?= $e($t('settings.cron.empty_future_jobs')) ?></td></tr>
<?php else: ?>
<?php foreach ($futureList as $row): ?>
<tr>
<td><?= $e((string) ((int) ($row['id'] ?? 0))) ?></td>
<td><?= $e((string) ($row['job_type'] ?? '')) ?></td>
<td><?= $e((string) ($row['status'] ?? '')) ?></td>
<td><?= $e((string) ((int) ($row['priority'] ?? 0))) ?></td>
<td><?= $e((string) (($row['scheduled_at'] ?? null) ?? '-')) ?></td>
<td><?= $e((string) ((int) ($row['attempts'] ?? 0)) . '/' . (string) ((int) ($row['max_attempts'] ?? 0))) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.cron.past_jobs_title')) ?></h2>
<div class="table-wrap mt-12">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th><?= $e($t('settings.cron.fields.job_type')) ?></th>
<th><?= $e($t('settings.cron.fields.status')) ?></th>
<th><?= $e($t('settings.cron.fields.scheduled_at')) ?></th>
<th><?= $e($t('settings.cron.fields.completed_at')) ?></th>
<th><?= $e($t('settings.cron.fields.last_error')) ?></th>
</tr>
</thead>
<tbody>
<?php if ($pastList === []): ?>
<tr><td colspan="6" class="muted"><?= $e($t('settings.cron.empty_past_jobs')) ?></td></tr>
<?php else: ?>
<?php foreach ($pastList as $row): ?>
<?php $error = trim((string) ($row['last_error'] ?? '')); ?>
<tr>
<td><?= $e((string) ((int) ($row['id'] ?? 0))) ?></td>
<td><?= $e((string) ($row['job_type'] ?? '')) ?></td>
<td><?= $e((string) ($row['status'] ?? '')) ?></td>
<td><?= $e((string) (($row['scheduled_at'] ?? null) ?? '-')) ?></td>
<td><?= $e((string) (($row['completed_at'] ?? null) ?? '-')) ?></td>
<td><?= $e($error === '' ? '-' : $error) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</section>

View File

@@ -0,0 +1,100 @@
<?php
$migrationStatus = is_array($status ?? null) ? $status : [];
$pending = (int) ($migrationStatus['pending'] ?? 0);
$total = (int) ($migrationStatus['total'] ?? 0);
$applied = (int) ($migrationStatus['applied'] ?? 0);
$pendingFiles = (array) ($migrationStatus['pending_files'] ?? []);
$logs = (array) ($runLogs ?? []);
?>
<section class="card">
<h1><?= $e($t('settings.title')) ?></h1>
<p class="muted"><?= $e($t('settings.description')) ?></p>
<nav class="settings-nav mt-16" aria-label="<?= $e($t('settings.submenu_label')) ?>">
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'database' ? ' is-active' : '' ?>" href="/settings/database"><?= $e($t('settings.database.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'integrations' ? ' is-active' : '' ?>" href="/settings/integrations/shoppro"><?= $e($t('settings.integrations.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'order_statuses' ? ' is-active' : '' ?>" href="/settings/order-statuses"><?= $e($t('settings.order_statuses.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'cron' ? ' is-active' : '' ?>" href="/settings/cron"><?= $e($t('settings.cron.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'gs1' ? ' is-active' : '' ?>" href="/settings/gs1"><?= $e($t('settings.gs1.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'products' ? ' is-active' : '' ?>" href="/settings/products"><?= $e($t('settings.products.title')) ?></a>
</nav>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.database.title')) ?></h2>
<?php if (!empty($errorMessage)): ?>
<div class="alert alert--danger mt-12" role="alert">
<?= $e((string) $errorMessage) ?>
</div>
<?php endif; ?>
<?php if (!empty($successMessage)): ?>
<div class="alert alert--success mt-12" role="status">
<?= $e((string) $successMessage) ?>
</div>
<?php endif; ?>
<div class="settings-grid mt-16">
<div class="settings-stat">
<span class="settings-stat__label"><?= $e($t('settings.database.stats.total')) ?></span>
<strong class="settings-stat__value"><?= $e((string) $total) ?></strong>
</div>
<div class="settings-stat">
<span class="settings-stat__label"><?= $e($t('settings.database.stats.applied')) ?></span>
<strong class="settings-stat__value"><?= $e((string) $applied) ?></strong>
</div>
<div class="settings-stat">
<span class="settings-stat__label"><?= $e($t('settings.database.stats.pending')) ?></span>
<strong class="settings-stat__value"><?= $e((string) $pending) ?></strong>
</div>
</div>
<?php if ($pending > 0): ?>
<div class="alert alert--warning mt-16" role="status">
<?= $e($t('settings.database.state.needs_update')) ?>
</div>
<form class="mt-16" action="/settings/database/migrate" method="post">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.database.actions.run_update')) ?></button>
</form>
<?php else: ?>
<div class="alert alert--success mt-16" role="status">
<?= $e($t('settings.database.state.up_to_date')) ?>
</div>
<?php endif; ?>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.database.pending_files_title')) ?></h2>
<div class="table-wrap mt-12">
<table class="table">
<thead>
<tr>
<th><?= $e($t('settings.database.fields.filename')) ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($pendingFiles)): ?>
<tr>
<td class="muted"><?= $e($t('settings.database.pending_files_empty')) ?></td>
</tr>
<?php else: ?>
<?php foreach ($pendingFiles as $filename): ?>
<tr>
<td><?= $e((string) $filename) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</section>
<?php if (!empty($logs)): ?>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.database.last_run_logs')) ?></h2>
<pre class="settings-logs mt-12"><?php foreach ($logs as $line): ?><?= $e((string) $line) . "\n" ?><?php endforeach; ?></pre>
</section>
<?php endif; ?>

View File

@@ -0,0 +1,58 @@
<section class="card">
<h1><?= $e($t('settings.title')) ?></h1>
<p class="muted"><?= $e($t('settings.description')) ?></p>
<nav class="settings-nav mt-16" aria-label="<?= $e($t('settings.submenu_label')) ?>">
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'database' ? ' is-active' : '' ?>" href="/settings/database"><?= $e($t('settings.database.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'integrations' ? ' is-active' : '' ?>" href="/settings/integrations/shoppro"><?= $e($t('settings.integrations.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'order_statuses' ? ' is-active' : '' ?>" href="/settings/order-statuses"><?= $e($t('settings.order_statuses.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'cron' ? ' is-active' : '' ?>" href="/settings/cron"><?= $e($t('settings.cron.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'gs1' ? ' is-active' : '' ?>" href="/settings/gs1"><?= $e($t('settings.gs1.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'products' ? ' is-active' : '' ?>" href="/settings/products"><?= $e($t('settings.products.title')) ?></a>
</nav>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.gs1.title')) ?></h2>
<p class="muted mt-12"><?= $e($t('settings.gs1.description')) ?></p>
<?php if (!empty($errorMessage)): ?>
<div class="alert alert--danger mt-12" role="alert"><?= $e((string) $errorMessage) ?></div>
<?php endif; ?>
<?php if (!empty($successMessage)): ?>
<div class="alert alert--success mt-12" role="status"><?= $e((string) $successMessage) ?></div>
<?php endif; ?>
<form action="/settings/gs1/save" method="post" class="mt-16">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<label class="form-field">
<span class="field-label"><?= $e($t('settings.gs1.fields.api_login')) ?></span>
<input class="form-control" type="text" name="gs1_api_login" value="<?= $e((string) ($gs1ApiLogin ?? '')) ?>" autocomplete="off">
</label>
<label class="form-field mt-12">
<span class="field-label"><?= $e($t('settings.gs1.fields.api_password')) ?></span>
<input class="form-control" type="password" name="gs1_api_password" value="<?= $e((string) ($gs1ApiPassword ?? '')) ?>" autocomplete="off">
</label>
<label class="form-field mt-12">
<span class="field-label"><?= $e($t('settings.gs1.fields.prefix')) ?></span>
<input class="form-control" type="text" name="gs1_prefix" value="<?= $e((string) ($gs1Prefix ?? '590532390')) ?>" maxlength="12">
</label>
<label class="form-field mt-12">
<span class="field-label"><?= $e($t('settings.gs1.fields.default_brand')) ?></span>
<input class="form-control" type="text" name="gs1_default_brand" value="<?= $e((string) ($gs1DefaultBrand ?? 'marianek.pl')) ?>">
</label>
<label class="form-field mt-12">
<span class="field-label"><?= $e($t('settings.gs1.fields.default_gpc_code')) ?></span>
<input class="form-control" type="text" name="gs1_default_gpc_code" value="<?= $e((string) ($gs1DefaultGpcCode ?? '10008365')) ?>">
</label>
<div class="form-actions mt-16">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.gs1.actions.save')) ?></button>
</div>
</form>
</section>

View File

@@ -0,0 +1,215 @@
<?php
$list = (array) ($integrations ?? []);
$selected = is_array($selectedIntegration ?? null) ? $selectedIntegration : null;
$formValues = is_array($form ?? null) ? $form : [];
$tests = (array) ($recentTests ?? []);
$isEdit = ((int) ($formValues['integration_id'] ?? 0)) > 0;
?>
<section class="card">
<h1><?= $e($t('settings.title')) ?></h1>
<p class="muted"><?= $e($t('settings.description')) ?></p>
<nav class="settings-nav mt-16" aria-label="<?= $e($t('settings.submenu_label')) ?>">
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'database' ? ' is-active' : '' ?>" href="/settings/database"><?= $e($t('settings.database.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'integrations' ? ' is-active' : '' ?>" href="/settings/integrations/shoppro"><?= $e($t('settings.integrations.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'order_statuses' ? ' is-active' : '' ?>" href="/settings/order-statuses"><?= $e($t('settings.order_statuses.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'cron' ? ' is-active' : '' ?>" href="/settings/cron"><?= $e($t('settings.cron.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'gs1' ? ' is-active' : '' ?>" href="/settings/gs1"><?= $e($t('settings.gs1.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'products' ? ' is-active' : '' ?>" href="/settings/products"><?= $e($t('settings.products.title')) ?></a>
</nav>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.integrations.list_title')) ?></h2>
<?php if (!empty($errorMessage)): ?>
<div class="alert alert--danger mt-12" role="alert">
<?= $e((string) $errorMessage) ?>
</div>
<?php endif; ?>
<?php if (!empty($successMessage)): ?>
<div class="alert alert--success mt-12" role="status">
<?= $e((string) $successMessage) ?>
</div>
<?php endif; ?>
<div class="table-wrap mt-12">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th><?= $e($t('settings.integrations.fields.name')) ?></th>
<th><?= $e($t('settings.integrations.fields.base_url')) ?></th>
<th><?= $e($t('settings.integrations.fields.active')) ?></th>
<th><?= $e($t('settings.integrations.fields.last_test')) ?></th>
<th><?= $e($t('settings.integrations.fields.actions')) ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($list)): ?>
<tr>
<td colspan="6" class="muted"><?= $e($t('settings.integrations.empty')) ?></td>
</tr>
<?php else: ?>
<?php foreach ($list as $item): ?>
<?php
$status = (string) ($item['last_test_status'] ?? '');
$statusLabel = $status === 'ok'
? $t('settings.integrations.test_status.ok')
: ($status === 'error' ? $t('settings.integrations.test_status.error') : $t('settings.integrations.test_status.never'));
?>
<tr>
<td><?= $e((string) ($item['id'] ?? 0)) ?></td>
<td><?= $e((string) ($item['name'] ?? '')) ?></td>
<td><?= $e((string) ($item['base_url'] ?? '')) ?></td>
<td>
<?php if ((bool) ($item['is_active'] ?? false)): ?>
<span class="status-pill is-active"><?= $e($t('settings.integrations.active.yes')) ?></span>
<?php else: ?>
<span class="status-pill"><?= $e($t('settings.integrations.active.no')) ?></span>
<?php endif; ?>
</td>
<td>
<div><?= $e($statusLabel) ?></div>
<?php if (!empty($item['last_test_at'])): ?>
<small class="muted"><?= $e((string) $item['last_test_at']) ?><?php if (($item['last_test_http_code'] ?? null) !== null): ?> | HTTP <?= $e((string) $item['last_test_http_code']) ?><?php endif; ?></small>
<?php endif; ?>
</td>
<td>
<a class="btn btn--secondary" href="/settings/integrations/shoppro?id=<?= $e((string) ($item['id'] ?? 0)) ?>"><?= $e($t('settings.integrations.actions.edit')) ?></a>
<form action="/settings/integrations/shoppro/test" method="post" style="display:inline-block; margin-left:6px;">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="integration_id" value="<?= $e((string) ($item['id'] ?? 0)) ?>">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.integrations.actions.test')) ?></button>
</form>
<form action="/settings/integrations/shoppro/import-offers-cache" method="post" style="display:inline-block; margin-left:6px;">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="integration_id" value="<?= $e((string) ($item['id'] ?? 0)) ?>">
<button type="submit" class="btn btn--secondary"><?= $e($t('settings.integrations.actions.import_offers_cache')) ?></button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</section>
<section class="card mt-16">
<h2 class="section-title">
<?= $e($isEdit ? $t('settings.integrations.edit_title') : $t('settings.integrations.create_title')) ?>
</h2>
<form class="mt-16" action="/settings/integrations/shoppro/save" method="post">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="integration_id" value="<?= $e((string) ($formValues['integration_id'] ?? '0')) ?>">
<div class="form-grid">
<label class="form-field">
<span class="field-label"><?= $e($t('settings.integrations.fields.name')) ?></span>
<input class="form-control" type="text" name="name" value="<?= $e((string) ($formValues['name'] ?? '')) ?>" required>
</label>
<label class="form-field">
<span class="field-label"><?= $e($t('settings.integrations.fields.base_url')) ?></span>
<input class="form-control" type="url" name="base_url" value="<?= $e((string) ($formValues['base_url'] ?? '')) ?>" placeholder="https://shoppro.project-dc.pl/" required>
</label>
<label class="form-field">
<span class="field-label"><?= $e($t('settings.integrations.fields.api_key')) ?></span>
<input class="form-control" type="password" name="api_key" value="" placeholder="<?= $e($isEdit ? $t('settings.integrations.api_key_placeholder_edit') : '') ?>">
<?php if ($isEdit): ?>
<small class="muted">
<?= $e(($selected['has_api_key'] ?? false) ? $t('settings.integrations.api_key_saved') : $t('settings.integrations.api_key_missing')) ?>
</small>
<?php endif; ?>
</label>
<label class="form-field">
<span class="field-label"><?= $e($t('settings.integrations.fields.timeout_seconds')) ?></span>
<input class="form-control" type="number" min="3" max="60" name="timeout_seconds" value="<?= $e((string) ($formValues['timeout_seconds'] ?? '10')) ?>">
</label>
<label class="form-field">
<span class="field-label"><?= $e($t('settings.integrations.fields.orders_fetch_start_date')) ?></span>
<input class="form-control" type="date" name="orders_fetch_start_date" value="<?= $e((string) ($formValues['orders_fetch_start_date'] ?? '')) ?>">
</label>
<label class="form-field">
<span class="field-label"><?= $e($t('settings.integrations.fields.order_status_sync_direction')) ?></span>
<select class="form-control" name="order_status_sync_direction">
<?php $syncDirection = (string) ($formValues['order_status_sync_direction'] ?? 'shoppro_to_orderpro'); ?>
<option value="shoppro_to_orderpro"<?= $syncDirection === 'shoppro_to_orderpro' ? ' selected' : '' ?>>
<?= $e($t('settings.integrations.fields.order_status_sync_direction_shoppro_to_orderpro')) ?>
</option>
<option value="orderpro_to_shoppro"<?= $syncDirection === 'orderpro_to_shoppro' ? ' selected' : '' ?>>
<?= $e($t('settings.integrations.fields.order_status_sync_direction_orderpro_to_shoppro')) ?>
</option>
</select>
</label>
</div>
<label class="form-field mt-12">
<span class="field-label">
<input type="checkbox" name="is_active" value="1"<?= ((string) ($formValues['is_active'] ?? '1')) === '1' ? ' checked' : '' ?>>
<?= $e($t('settings.integrations.fields.active_checkbox')) ?>
</span>
</label>
<label class="form-field mt-12">
<span class="field-label">
<input type="checkbox" name="orders_fetch_enabled" value="1"<?= ((string) ($formValues['orders_fetch_enabled'] ?? '0')) === '1' ? ' checked' : '' ?>>
<?= $e($t('settings.integrations.fields.orders_fetch_enabled_checkbox')) ?>
</span>
</label>
<div class="form-actions mt-16">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.integrations.actions.save')) ?></button>
<a href="/settings/integrations/shoppro" class="btn btn--secondary"><?= $e($t('settings.integrations.actions.new')) ?></a>
<?php if ($isEdit): ?>
<button
type="submit"
class="btn btn--secondary"
formaction="/settings/integrations/shoppro/test"
formmethod="post"
><?= $e($t('settings.integrations.actions.test_now')) ?></button>
<button
type="submit"
class="btn btn--secondary"
formaction="/settings/integrations/shoppro/import-offers-cache"
formmethod="post"
><?= $e($t('settings.integrations.actions.import_offers_cache')) ?></button>
<?php endif; ?>
</div>
</form>
<?php if ($selected !== null && !empty($tests)): ?>
<h3 class="section-title mt-16"><?= $e($t('settings.integrations.logs_title')) ?></h3>
<div class="table-wrap mt-12">
<table class="table">
<thead>
<tr>
<th><?= $e($t('settings.integrations.logs.fields.tested_at')) ?></th>
<th><?= $e($t('settings.integrations.logs.fields.status')) ?></th>
<th><?= $e($t('settings.integrations.logs.fields.http_code')) ?></th>
<th><?= $e($t('settings.integrations.logs.fields.message')) ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($tests as $test): ?>
<?php $httpCode = $test['http_code'] ?? null; ?>
<tr>
<td><?= $e((string) ($test['tested_at'] ?? '')) ?></td>
<td><?= $e((string) ($test['status'] ?? '')) ?></td>
<td><?= $e($httpCode === null ? '-' : (string) $httpCode) ?></td>
<td><?= $e((string) ($test['message'] ?? '')) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</section>

View File

@@ -0,0 +1,107 @@
<?php
$integrationsList = is_array($integrations ?? null) ? $integrations : [];
$selectedIntegrationId = max(0, (int) ($selectedIntegrationId ?? 0));
$shopProStatusesList = is_array($shopProStatuses ?? null) ? $shopProStatuses : [];
$orderProOptions = is_array($orderProStatusOptions ?? null) ? $orderProStatusOptions : [];
?>
<section class="card">
<h1><?= $e($t('settings.title')) ?></h1>
<p class="muted"><?= $e($t('settings.description')) ?></p>
<nav class="settings-nav mt-16" aria-label="<?= $e($t('settings.submenu_label')) ?>">
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'database' ? ' is-active' : '' ?>" href="/settings/database"><?= $e($t('settings.database.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'integrations' ? ' is-active' : '' ?>" href="/settings/integrations/shoppro"><?= $e($t('settings.integrations.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'order_statuses' ? ' is-active' : '' ?>" href="/settings/order-statuses"><?= $e($t('settings.order_statuses.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'cron' ? ' is-active' : '' ?>" href="/settings/cron"><?= $e($t('settings.cron.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'gs1' ? ' is-active' : '' ?>" href="/settings/gs1"><?= $e($t('settings.gs1.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'products' ? ' is-active' : '' ?>" href="/settings/products"><?= $e($t('settings.products.title')) ?></a>
</nav>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.order_statuses.title')) ?></h2>
<p class="muted mt-12"><?= $e($t('settings.order_statuses.description')) ?></p>
<?php if (!empty($errorMessage)): ?>
<div class="alert alert--danger mt-12" role="alert"><?= $e((string) $errorMessage) ?></div>
<?php endif; ?>
<?php if (!empty($successMessage)): ?>
<div class="alert alert--success mt-12" role="status"><?= $e((string) $successMessage) ?></div>
<?php endif; ?>
<form method="get" action="/settings/order-statuses" class="mt-16">
<label class="form-field">
<span class="field-label"><?= $e($t('settings.order_statuses.integration')) ?></span>
<select class="form-control" name="integration_id" onchange="this.form.submit()">
<?php if ($integrationsList === []): ?>
<option value="0"><?= $e($t('settings.order_statuses.no_integrations')) ?></option>
<?php else: ?>
<?php foreach ($integrationsList as $integration): ?>
<?php $id = max(0, (int) ($integration['id'] ?? 0)); ?>
<?php if ($id <= 0) continue; ?>
<option value="<?= $e((string) $id) ?>"<?= $id === $selectedIntegrationId ? ' selected' : '' ?>>
<?= $e((string) ($integration['name'] ?? ('#' . $id))) ?> (ID: <?= $e((string) $id) ?>)
</option>
<?php endforeach; ?>
<?php endif; ?>
</select>
</label>
</form>
<?php if ($selectedIntegrationId > 0): ?>
<form action="/settings/order-statuses/save" method="post" class="mt-16">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="integration_id" value="<?= $e((string) $selectedIntegrationId) ?>">
<div class="table-wrap">
<table class="table">
<thead>
<tr>
<th><?= $e($t('settings.order_statuses.fields.shoppro_code')) ?></th>
<th><?= $e($t('settings.order_statuses.fields.shoppro_name')) ?></th>
<th><?= $e($t('settings.order_statuses.fields.orderpro_status')) ?></th>
</tr>
</thead>
<tbody>
<?php if ($shopProStatusesList === []): ?>
<tr>
<td colspan="3" class="muted"><?= $e($t('settings.order_statuses.empty')) ?></td>
</tr>
<?php else: ?>
<?php foreach ($shopProStatusesList as $status): ?>
<?php
$shopCode = trim((string) ($status['code'] ?? ''));
if ($shopCode === '') continue;
$shopName = trim((string) ($status['name'] ?? $shopCode));
$selectedOrderPro = trim((string) ($status['mapped_orderpro_status'] ?? ''));
?>
<tr>
<td>
<?= $e($shopCode) ?>
<input type="hidden" name="shoppro_names[<?= $e($shopCode) ?>]" value="<?= $e($shopName) ?>">
</td>
<td><?= $e($shopName) ?></td>
<td>
<select class="form-control" name="mappings[<?= $e($shopCode) ?>]">
<option value=""><?= $e($t('settings.order_statuses.fields.no_mapping')) ?></option>
<?php foreach ($orderProOptions as $orderProCode => $orderProLabel): ?>
<option value="<?= $e((string) $orderProCode) ?>"<?= $selectedOrderPro === (string) $orderProCode ? ' selected' : '' ?>>
<?= $e((string) $orderProLabel) ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="form-actions mt-16">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.order_statuses.actions.save')) ?></button>
</div>
</form>
<?php endif; ?>
</section>

View File

@@ -0,0 +1,40 @@
<section class="card">
<h1><?= $e($t('settings.title')) ?></h1>
<p class="muted"><?= $e($t('settings.description')) ?></p>
<nav class="settings-nav mt-16" aria-label="<?= $e($t('settings.submenu_label')) ?>">
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'database' ? ' is-active' : '' ?>" href="/settings/database"><?= $e($t('settings.database.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'integrations' ? ' is-active' : '' ?>" href="/settings/integrations/shoppro"><?= $e($t('settings.integrations.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'order_statuses' ? ' is-active' : '' ?>" href="/settings/order-statuses"><?= $e($t('settings.order_statuses.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'cron' ? ' is-active' : '' ?>" href="/settings/cron"><?= $e($t('settings.cron.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'gs1' ? ' is-active' : '' ?>" href="/settings/gs1"><?= $e($t('settings.gs1.title')) ?></a>
<a class="settings-nav__link<?= ($activeSettings ?? '') === 'products' ? ' is-active' : '' ?>" href="/settings/products"><?= $e($t('settings.products.title')) ?></a>
</nav>
</section>
<section class="card mt-16">
<h2 class="section-title"><?= $e($t('settings.products.title')) ?></h2>
<p class="muted mt-12"><?= $e($t('settings.products.description')) ?></p>
<form action="/settings/products/save" method="post" class="mt-16">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<label class="form-field">
<span class="field-label"><?= $e($t('settings.products.fields.sku_format')) ?></span>
<input
class="form-control"
type="text"
name="products_sku_format"
maxlength="128"
value="<?= $e((string) ($productsSkuFormat ?? 'PP000000')) ?>"
placeholder="PP000000"
>
</label>
<p class="muted mt-12"><?= $e($t('settings.products.sku_format_hint')) ?></p>
<div class="form-actions mt-16">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.products.actions.save')) ?></button>
</div>
</form>
</section>