Scheduler v1
All checks were successful
Test Build / test-build (push) Successful in 23s

This commit is contained in:
2025-07-30 18:28:55 +03:00
parent 8e757afe39
commit 0f1c749b33
7 changed files with 457 additions and 159 deletions

View File

@@ -147,7 +147,7 @@
<select name="sheet_{{ sheet.id }}">
<option value="">-- {{ _('Not set') }} --</option>
{% for preset in presets %}
<option value="{{ preset['id'] }}" {% if mappings.get(sheet.title) == preset['id'] %}selected{% endif %}>
<option value="{{ preset['id'] }}" {% if mappings.get(sheet.title, {}).get('report_id') == preset['id'] %}selected{% endif %}>
{{ preset['name'] }} ({{ preset['id'] }})
</option>
{% endfor %}
@@ -197,24 +197,25 @@
</thead>
<tbody>
{% for sheet in sheets %}
{% set report_id = mappings.get(sheet.title) %}
{% if report_id %}
{% set matching_presets = presets | selectattr('id', 'equalto', report_id) | list %}
{% set preset_name = _('ID: ') + report_id %}
{% if matching_presets %}
{% set preset = matching_presets[0] %}
{% set preset_name = preset.get('name', _('Unnamed Preset')) %}
{% endif %}
{% set mappings = mappings.get(sheet.title) %}
{% if mapping_info and mapping_info.get('report_id') %}
{% set report_id = mapping_info.get('report_id') %}
{% set matching_presets = presets | selectattr('id', 'equalto', report_id) | list %}
{% set preset_name = _('ID: ') + report_id %}
{% if matching_presets %}
{% set preset = matching_presets[0] %}
{% set preset_name = preset.get('name', _('Unnamed Preset')) %}
{% endif %}
<tr>
<td>{{ sheet.title }}</td>
<td>{{ preset_name }}</td>
<td>
<button type="submit" name="render_{{ sheet.title }}">
{{ _('Render to sheet') }}
</button>
</td>
</tr>
<tr>
<td>{{ sheet.title }}</td>
<td>{{ preset_name }}</td>
<td>
<button type="submit" name="render_{{ sheet.title }}">
{{ _('Render to sheet') }}
</button>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
@@ -226,6 +227,70 @@
{% endif %}
</div>
<button type="button" class="collapsible" {% if not mappings or mappings|length == 0 %}disabled title="{{ _('Configure Mappings first') }}"{% endif %}>
5. {{ _('Scheduling Automatic Reports') }}
</button>
<div class="content">
<h3>{{ _('Schedule Settings') }}</h3>
<p>
{% trans %}Here you can set up a CRON schedule for automatic report generation.
The report will be generated for the specified period relative to the execution time.{% endtrans %}
</p>
<div class="cron-constructor">
<h4>{{ _('Cron Schedule Builder') }}</h4>
<p><small>{% trans %}Use this tool to build a cron string, then copy it to the desired field below.{% endtrans %}</small></p>
<div class="cron-row">
<select id="cron-minute"><option value="*">*</option>{% for i in range(60) %}<option value="{{i}}">{{'%02d'|format(i)}}</option>{% endfor %}</select>
<select id="cron-hour"><option value="*">*</option>{% for i in range(24) %}<option value="{{i}}">{{'%02d'|format(i)}}</option>{% endfor %}</select>
<select id="cron-day"><option value="*">*</option>{% for i in range(1, 32) %}<option value="{{i}}">{{i}}</option>{% endfor %}</select>
<select id="cron-month"><option value="*">*</option>{% for i in range(1, 13) %}<option value="{{i}}">{{i}}</option>{% endfor %}</select>
<select id="cron-day-of-week"><option value="*">*</option><option value="1">{{_('Mon')}}</option><option value="2">{{_('Tue')}}</option><option value="3">{{_('Wed')}}</option><option value="4">{{_('Thu')}}</option><option value="5">{{_('Fri')}}</option><option value="6">{{_('Sat')}}</option><option value="0">{{_('Sun')}}</option></select>
</div>
<label for="cron-output">{{ _('Generated Cron String:') }}</label>
<input type="text" id="cron-output" readonly>
<p id="cron-human-readable"></p>
</div>
<hr>
<form action="{{ url_for('.save_schedule') }}" method="post">
<table>
<thead>
<tr>
<th>{{ _('Worksheet') }}</th>
<th>{{ _('Schedule (Cron)') }}</th>
<th>{{ _('Report Period') }}</th>
</tr>
</thead>
<tbody>
{% for sheet_title, params in mappings.items() %}
<tr>
<td>{{ sheet_title }}</td>
<td>
<input type="text" name="cron-{{ sheet_title }}" value="{{ params.get('schedule_cron', '') }}" placeholder="e.g., 0 2 * * 1">
</td>
<td>
{% set current_period = params.get('schedule_period', '') %}
<select name="period-{{ sheet_title }}" class="period-select" data-target="custom-days-{{ sheet_title }}">
<option value="">-- {{ _('Not Scheduled') }} --</option>
<option value="previous_week" {% if current_period == 'previous_week' %}selected{% endif %}>{{ _('Previous Week') }}</option>
<option value="last_7_days" {% if current_period == 'last_7_days' %}selected{% endif %}>{{ _('Last 7 Days') }}</option>
<option value="previous_month" {% if current_period == 'previous_month' %}selected{% endif %}>{{ _('Previous Month') }}</option>
<option value="current_month" {% if current_period == 'current_month' %}selected{% endif %}>{{ _('Current Month (to yesterday)') }}</option>
<option value="last_N_days" {% if current_period and current_period.startswith('last_') and current_period.endswith('_days') %}selected{% endif %}>{{ _('Last N Days') }}</option>
</select>
<div id="custom-days-{{ sheet_title }}" class="custom-days-input" style="display: none; margin-top: 5px;">
<input type="number" name="custom_days-{{ sheet_title }}" min="1" placeholder="N" style="width: 60px;" value="{% if current_period and current_period.startswith('last_') %}{{ current_period.split('_')[1] }}{% endif %}">
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit">{{ _('Save Schedule') }}</button>
</form>
</div>
</div> <!-- End Container -->
<script>
@@ -251,6 +316,41 @@
}
});
}
document.addEventListener('DOMContentLoaded', function() {
// Cron конструктор
const cronInputs = ['cron-minute', 'cron-hour', 'cron-day', 'cron-month', 'cron-day-of-week'];
const cronOutput = document.getElementById('cron-output');
function updateCronString() {
if (!cronOutput) return;
const values = cronInputs.map(id => document.getElementById(id).value);
cronOutput.value = values.join(' ');
}
cronInputs.forEach(id => {
const el = document.getElementById(id);
if(el) el.addEventListener('change', updateCronString);
});
updateCronString(); // Initial call
// Управление видимостью поля "N дней"
document.querySelectorAll('.period-select').forEach(select => {
const targetId = select.dataset.target;
const targetDiv = document.getElementById(targetId);
function toggleCustomInput() {
if (select.value === 'last_N_days') {
targetDiv.style.display = 'block';
} else {
targetDiv.style.display = 'none';
}
}
select.addEventListener('change', toggleCustomInput);
toggleCustomInput(); // Initial call on page load
});
});
</script>
{% else %}
<p style="text-align: center; margin-top: 50px;">{{ _('Please,') }} <a href="{{ url_for('.login') }}">{{ _('login') }}</a> {{ _('or') }} <a href="{{ url_for('.register') }}">{{ _('register') }}</a></p>