snapshot: preserve request status retry and i18n labels
This commit is contained in:
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.1.5 on 2026-03-25 19:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('workflows', '0032_adminauditlog'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='offboardingrequest',
|
||||
name='last_error',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='offboardingrequest',
|
||||
name='processing_status',
|
||||
field=models.CharField(choices=[('submitted', 'Eingereicht'), ('processing', 'In Bearbeitung'), ('completed', 'Abgeschlossen'), ('failed', 'Fehlgeschlagen')], default='submitted', max_length=20),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='onboardingrequest',
|
||||
name='last_error',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='onboardingrequest',
|
||||
name='processing_status',
|
||||
field=models.CharField(choices=[('submitted', 'Eingereicht'), ('processing', 'In Bearbeitung'), ('completed', 'Abgeschlossen'), ('failed', 'Fehlgeschlagen')], default='submitted', max_length=20),
|
||||
),
|
||||
]
|
||||
@@ -1,6 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.translation import get_language
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
def _normalized_language_code(value: str | None) -> str:
|
||||
@@ -50,6 +51,13 @@ class AdminAuditLog(models.Model):
|
||||
|
||||
|
||||
class OnboardingRequest(models.Model):
|
||||
STATUS_CHOICES = [
|
||||
('submitted', _('Eingereicht')),
|
||||
('processing', _('In Bearbeitung')),
|
||||
('completed', _('Abgeschlossen')),
|
||||
('failed', _('Fehlgeschlagen')),
|
||||
]
|
||||
|
||||
full_name = models.CharField(max_length=255, verbose_name='Vorname und Nachname')
|
||||
gender = models.CharField(
|
||||
max_length=20,
|
||||
@@ -112,6 +120,8 @@ class OnboardingRequest(models.Model):
|
||||
|
||||
generated_pdf_path = models.CharField(max_length=500, blank=True)
|
||||
intro_pdf_path = models.CharField(max_length=500, blank=True)
|
||||
processing_status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='submitted')
|
||||
last_error = models.TextField(blank=True)
|
||||
preferred_language = models.CharField(max_length=10, blank=True, default='de', db_default='de')
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
@@ -447,6 +457,8 @@ class SystemEmailConfig(models.Model):
|
||||
|
||||
|
||||
class OffboardingRequest(models.Model):
|
||||
STATUS_CHOICES = OnboardingRequest.STATUS_CHOICES
|
||||
|
||||
employee_profile = models.ForeignKey(EmployeeProfile, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
full_name = models.CharField(max_length=255, verbose_name='Vorname und Nachname')
|
||||
work_email = models.EmailField(verbose_name='Dienstliche E-Mail-Adresse')
|
||||
@@ -460,6 +472,8 @@ class OffboardingRequest(models.Model):
|
||||
requested_by_name = models.CharField(max_length=255, blank=True, verbose_name='Name der anfordernden Person')
|
||||
preferred_language = models.CharField(max_length=10, blank=True, default='de', db_default='de')
|
||||
generated_pdf_path = models.CharField(max_length=500, blank=True)
|
||||
processing_status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='submitted')
|
||||
last_error = models.TextField(blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
||||
@@ -1195,159 +1195,183 @@ def _generate_offboarding_pdf(request_obj: OffboardingRequest) -> Path:
|
||||
@shared_task
|
||||
def process_onboarding_request(onboarding_request_id: int) -> None:
|
||||
request_obj = OnboardingRequest.objects.get(id=onboarding_request_id)
|
||||
it_email, general_info_email, business_card_email, hr_works_email, key_email = _resolve_workflow_emails()
|
||||
salutation = (request_obj.get_gender_display() or '').strip()
|
||||
display_name = f"{salutation} {request_obj.full_name}".strip()
|
||||
request_obj.processing_status = 'processing'
|
||||
request_obj.last_error = ''
|
||||
request_obj.save(update_fields=['processing_status', 'last_error'])
|
||||
try:
|
||||
it_email, general_info_email, business_card_email, hr_works_email, key_email = _resolve_workflow_emails()
|
||||
salutation = (request_obj.get_gender_display() or '').strip()
|
||||
display_name = f"{salutation} {request_obj.full_name}".strip()
|
||||
|
||||
first_name, last_name = _split_name(request_obj.full_name)
|
||||
EmployeeProfile.objects.update_or_create(
|
||||
work_email=request_obj.work_email,
|
||||
defaults={
|
||||
'full_name': request_obj.full_name,
|
||||
'first_name': first_name,
|
||||
'last_name': last_name,
|
||||
'department': request_obj.department,
|
||||
'job_title': request_obj.job_title,
|
||||
},
|
||||
)
|
||||
|
||||
pdf_path = _generate_onboarding_pdf(request_obj)
|
||||
request_obj.generated_pdf_path = str(pdf_path)
|
||||
request_obj.save(update_fields=['generated_pdf_path'])
|
||||
|
||||
email_context = {
|
||||
'FULL_NAME': display_name,
|
||||
'VORNAME': first_name,
|
||||
'NACHNAME': last_name,
|
||||
'DEPARTMENT': request_obj.department or '-',
|
||||
'CONTRACT_START': request_obj.contract_start,
|
||||
'EMAIL': request_obj.work_email,
|
||||
'REQUESTED_BY': request_obj.onboarded_by_email or '-',
|
||||
'BUSINESS_CARD_NAME': request_obj.business_card_name or display_name,
|
||||
'BUSINESS_CARD_TITLE': request_obj.business_card_title or '-',
|
||||
'BUSINESS_CARD_EMAIL': request_obj.business_card_email or request_obj.work_email,
|
||||
'BUSINESS_CARD_PHONE': request_obj.business_card_phone or '-',
|
||||
'PDF_LINK': settings.ONBOARDING_SHARED_PDF_LINK,
|
||||
}
|
||||
|
||||
_send_templated_email(
|
||||
template_key='onboarding_it',
|
||||
context=email_context,
|
||||
to=[it_email],
|
||||
attachments=[pdf_path],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
_send_templated_email(
|
||||
template_key='onboarding_general_info',
|
||||
context=email_context,
|
||||
to=[general_info_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
if request_obj.order_business_cards:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_business_card',
|
||||
context=email_context,
|
||||
to=[business_card_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
first_name, last_name = _split_name(request_obj.full_name)
|
||||
EmployeeProfile.objects.update_or_create(
|
||||
work_email=request_obj.work_email,
|
||||
defaults={
|
||||
'full_name': request_obj.full_name,
|
||||
'first_name': first_name,
|
||||
'last_name': last_name,
|
||||
'department': request_obj.department,
|
||||
'job_title': request_obj.job_title,
|
||||
},
|
||||
)
|
||||
|
||||
if 'HR Works' in request_obj.needed_accesses:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_hr_works',
|
||||
context=email_context,
|
||||
to=[hr_works_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
pdf_path = _generate_onboarding_pdf(request_obj)
|
||||
request_obj.generated_pdf_path = str(pdf_path)
|
||||
request_obj.save(update_fields=['generated_pdf_path'])
|
||||
|
||||
if 'Schlüssel' in request_obj.needed_devices:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_key',
|
||||
context=email_context,
|
||||
to=[key_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
email_context = {
|
||||
'FULL_NAME': display_name,
|
||||
'VORNAME': first_name,
|
||||
'NACHNAME': last_name,
|
||||
'DEPARTMENT': request_obj.department or '-',
|
||||
'CONTRACT_START': request_obj.contract_start,
|
||||
'EMAIL': request_obj.work_email,
|
||||
'REQUESTED_BY': request_obj.onboarded_by_email or '-',
|
||||
'BUSINESS_CARD_NAME': request_obj.business_card_name or display_name,
|
||||
'BUSINESS_CARD_TITLE': request_obj.business_card_title or '-',
|
||||
'BUSINESS_CARD_EMAIL': request_obj.business_card_email or request_obj.work_email,
|
||||
'BUSINESS_CARD_PHONE': request_obj.business_card_phone or '-',
|
||||
'PDF_LINK': settings.ONBOARDING_SHARED_PDF_LINK,
|
||||
}
|
||||
|
||||
if request_obj.onboarded_by_email:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_reference',
|
||||
template_key='onboarding_it',
|
||||
context=email_context,
|
||||
to=[request_obj.onboarded_by_email],
|
||||
to=[it_email],
|
||||
attachments=[pdf_path],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
_send_templated_email(
|
||||
template_key='onboarding_general_info',
|
||||
context=email_context,
|
||||
to=[general_info_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
_apply_notification_rules(
|
||||
event_type='onboarding',
|
||||
request_obj=request_obj,
|
||||
context=email_context,
|
||||
pdf_path=pdf_path,
|
||||
)
|
||||
if request_obj.order_business_cards:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_business_card',
|
||||
context=email_context,
|
||||
to=[business_card_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
_schedule_welcome_email(request_obj)
|
||||
if 'HR Works' in request_obj.needed_accesses:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_hr_works',
|
||||
context=email_context,
|
||||
to=[hr_works_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
upload_to_nextcloud(pdf_path, Path(pdf_path).name)
|
||||
if 'Schlüssel' in request_obj.needed_devices:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_key',
|
||||
context=email_context,
|
||||
to=[key_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
if request_obj.onboarded_by_email:
|
||||
_send_templated_email(
|
||||
template_key='onboarding_reference',
|
||||
context=email_context,
|
||||
to=[request_obj.onboarded_by_email],
|
||||
attachments=[pdf_path],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
_apply_notification_rules(
|
||||
event_type='onboarding',
|
||||
request_obj=request_obj,
|
||||
context=email_context,
|
||||
pdf_path=pdf_path,
|
||||
)
|
||||
|
||||
_schedule_welcome_email(request_obj)
|
||||
|
||||
upload_to_nextcloud(pdf_path, Path(pdf_path).name)
|
||||
request_obj.processing_status = 'completed'
|
||||
request_obj.last_error = ''
|
||||
request_obj.save(update_fields=['processing_status', 'last_error'])
|
||||
except Exception as exc:
|
||||
request_obj.processing_status = 'failed'
|
||||
request_obj.last_error = str(exc)
|
||||
request_obj.save(update_fields=['processing_status', 'last_error'])
|
||||
raise
|
||||
|
||||
|
||||
@shared_task
|
||||
def process_offboarding_request(offboarding_request_id: int) -> None:
|
||||
request_obj = OffboardingRequest.objects.get(id=offboarding_request_id)
|
||||
it_email, general_info_email, _, hr_works_email, _ = _resolve_workflow_emails()
|
||||
request_obj.processing_status = 'processing'
|
||||
request_obj.last_error = ''
|
||||
request_obj.save(update_fields=['processing_status', 'last_error'])
|
||||
try:
|
||||
it_email, general_info_email, _, hr_works_email, _ = _resolve_workflow_emails()
|
||||
|
||||
pdf_path = _generate_offboarding_pdf(request_obj)
|
||||
request_obj.generated_pdf_path = str(pdf_path)
|
||||
request_obj.save(update_fields=['generated_pdf_path'])
|
||||
pdf_path = _generate_offboarding_pdf(request_obj)
|
||||
request_obj.generated_pdf_path = str(pdf_path)
|
||||
request_obj.save(update_fields=['generated_pdf_path'])
|
||||
|
||||
email_context = {
|
||||
'FULL_NAME': request_obj.full_name,
|
||||
'DEPARTMENT': request_obj.department or '-',
|
||||
'LAST_WORKING_DAY': request_obj.last_working_day,
|
||||
'REQUESTED_BY': request_obj.requested_by_email,
|
||||
'EMAIL': request_obj.work_email,
|
||||
}
|
||||
email_context = {
|
||||
'FULL_NAME': request_obj.full_name,
|
||||
'DEPARTMENT': request_obj.department or '-',
|
||||
'LAST_WORKING_DAY': request_obj.last_working_day,
|
||||
'REQUESTED_BY': request_obj.requested_by_email,
|
||||
'EMAIL': request_obj.work_email,
|
||||
}
|
||||
|
||||
_send_templated_email(
|
||||
template_key='offboarding_it',
|
||||
context=email_context,
|
||||
to=[it_email],
|
||||
attachments=[pdf_path],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
_send_templated_email(
|
||||
template_key='offboarding_general_info',
|
||||
context=email_context,
|
||||
to=[general_info_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
had_hr_works = OnboardingRequest.objects.filter(
|
||||
work_email=request_obj.work_email,
|
||||
needed_accesses__icontains='HR Works',
|
||||
).exists()
|
||||
if had_hr_works:
|
||||
_send_templated_email(
|
||||
template_key='offboarding_hr_works_disable',
|
||||
template_key='offboarding_it',
|
||||
context=email_context,
|
||||
to=[hr_works_email],
|
||||
to=[it_email],
|
||||
attachments=[pdf_path],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
_send_templated_email(
|
||||
template_key='offboarding_general_info',
|
||||
context=email_context,
|
||||
to=[general_info_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
_send_templated_email(
|
||||
template_key='offboarding_reference',
|
||||
context=email_context,
|
||||
to=[request_obj.requested_by_email],
|
||||
attachments=[pdf_path],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
had_hr_works = OnboardingRequest.objects.filter(
|
||||
work_email=request_obj.work_email,
|
||||
needed_accesses__icontains='HR Works',
|
||||
).exists()
|
||||
if had_hr_works:
|
||||
_send_templated_email(
|
||||
template_key='offboarding_hr_works_disable',
|
||||
context=email_context,
|
||||
to=[hr_works_email],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
_apply_notification_rules(
|
||||
event_type='offboarding',
|
||||
request_obj=request_obj,
|
||||
context=email_context,
|
||||
pdf_path=pdf_path,
|
||||
)
|
||||
_send_templated_email(
|
||||
template_key='offboarding_reference',
|
||||
context=email_context,
|
||||
to=[request_obj.requested_by_email],
|
||||
attachments=[pdf_path],
|
||||
language_code=request_obj.preferred_language,
|
||||
)
|
||||
|
||||
upload_to_nextcloud(pdf_path, Path(pdf_path).name)
|
||||
_apply_notification_rules(
|
||||
event_type='offboarding',
|
||||
request_obj=request_obj,
|
||||
context=email_context,
|
||||
pdf_path=pdf_path,
|
||||
)
|
||||
|
||||
upload_to_nextcloud(pdf_path, Path(pdf_path).name)
|
||||
request_obj.processing_status = 'completed'
|
||||
request_obj.last_error = ''
|
||||
request_obj.save(update_fields=['processing_status', 'last_error'])
|
||||
except Exception as exc:
|
||||
request_obj.processing_status = 'failed'
|
||||
request_obj.last_error = str(exc)
|
||||
request_obj.save(update_fields=['processing_status', 'last_error'])
|
||||
raise
|
||||
|
||||
|
||||
@shared_task
|
||||
|
||||
@@ -189,6 +189,8 @@ docker compose exec -T web python manage.py run_staging_e2e_check</code></pre>
|
||||
<li>Use real PDF generation tests when changing PDF templates or intro/offboarding document logic.</li>
|
||||
<li>Use the dedicated Release Checklist page as the final go/no-go runbook before shipping changes.</li>
|
||||
<li>The automated bilingual smoke tests now cover DE/EN request language capture and English email-template rendering.</li>
|
||||
<li>Onboarding and offboarding request objects now expose explicit processing state and last-error fields. Async tasks are responsible for transitioning <code>submitted → processing → completed/failed</code>.</li>
|
||||
<li>The Requests Dashboard includes a retry action for failed requests. Retries reset the error text, set the request back to <code>submitted</code>, and enqueue the appropriate Celery task again.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="deploy">12) Deployment and Release Checklist</h2>
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
<li><strong>Welcome Emails:</strong> scheduled jobs, pause/resume/cancel/trigger now.</li>
|
||||
<li><strong>Audit Log:</strong> staff-only trace of important admin changes such as builder edits, settings updates, PDF generation, welcome-email operations, and request deletions. Supports filtering by action, user, and date range.</li>
|
||||
<li><strong>Requests Dashboard:</strong> search records, open PDFs, delete records (single/bulk for staff).</li>
|
||||
<li><strong>Request Status & Retry:</strong> onboarding and offboarding requests now carry explicit processing state (<code>submitted</code>, <code>processing</code>, <code>completed</code>, <code>failed</code>). Failed requests expose the last error and can be retried from the dashboard.</li>
|
||||
<li><strong>Einweisungs- und Übergabeprotokoll:</strong> staff-only <code>PDF erzeugen</code>, <code>Neu erzeugen</code>, and <code>PDF öffnen</code> actions directly on onboarding rows in the Requests Dashboard.</li>
|
||||
<li><strong>Einweisung durchführen:</strong> staff-only live checklist page opened from onboarding rows, with draft/completed status, notes, progress tracking, and a separate live-status PDF export.</li>
|
||||
<li><strong>Project Wiki:</strong> this documentation page.</li>
|
||||
|
||||
@@ -189,6 +189,10 @@
|
||||
{% else %}
|
||||
<span class="person-meta">{% trans "Noch nicht verfügbar" %}</span>
|
||||
{% endif %}
|
||||
<div class="person-meta" style="margin-top:8px;">{{ row.status }}</div>
|
||||
{% if row.status_key == 'failed' and row.last_error %}
|
||||
<div class="person-meta" style="margin-top:6px; color:#8e1e1e;">{{ row.last_error|truncatechars:140 }}</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if request.user.is_staff %}
|
||||
<td class="actions-cell intro-panel">
|
||||
@@ -232,6 +236,12 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="actions-cell">
|
||||
{% if row.status_key == 'failed' %}
|
||||
<form method="post" action="/requests/retry/{{ row.kind_slug }}/{{ row.id }}/" class="inline-delete" onsubmit="return confirm('Eintrag erneut verarbeiten?');">
|
||||
{% csrf_token %}
|
||||
<button class="btn btn-secondary" type="submit">{% trans "Erneut versuchen" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<form method="post" action="/requests/" class="inline-delete" onsubmit="return confirm('Eintrag wirklich löschen?');">
|
||||
{% csrf_token %}
|
||||
<button class="btn btn-secondary" type="submit" name="single_delete" value="{{ row.kind_slug }}:{{ row.id }}">{% trans "Löschen" %}</button>
|
||||
|
||||
@@ -39,4 +39,5 @@ urlpatterns = [
|
||||
path('requests/onboarding/<int:request_id>/intro-session/pdf/', views.generate_onboarding_intro_session_pdf, name='generate_onboarding_intro_session_pdf'),
|
||||
path('requests/onboarding/<int:request_id>/intro-pdf/generate/', views.generate_onboarding_intro_pdf, name='generate_onboarding_intro_pdf'),
|
||||
path('requests/delete/<str:kind>/<int:request_id>/', views.delete_request_from_dashboard, name='delete_request_from_dashboard'),
|
||||
path('requests/retry/<str:kind>/<int:request_id>/', views.retry_request_from_dashboard, name='retry_request_from_dashboard'),
|
||||
]
|
||||
|
||||
@@ -147,6 +147,16 @@ def _form_field_labels(form_type: str) -> dict[str, str]:
|
||||
return {}
|
||||
|
||||
|
||||
def _request_status_label(status_key: str) -> str:
|
||||
labels = {
|
||||
'submitted': _('Eingereicht'),
|
||||
'processing': _('In Bearbeitung'),
|
||||
'completed': _('Abgeschlossen'),
|
||||
'failed': _('Fehlgeschlagen'),
|
||||
}
|
||||
return labels.get(status_key, status_key)
|
||||
|
||||
|
||||
def _translate_choice_list(choices):
|
||||
return [(value, str(label)) for value, label in choices]
|
||||
|
||||
@@ -383,7 +393,9 @@ def requests_dashboard(request):
|
||||
'pdf_url': f"/media/pdfs/{Path(obj.generated_pdf_path).name}" if obj.generated_pdf_path else None,
|
||||
'intro_pdf_url': f"/media/pdfs/{Path(obj.intro_pdf_path).name}" if obj.intro_pdf_path else None,
|
||||
'intro_session': intro_session,
|
||||
'status': 'PDF erstellt' if obj.generated_pdf_path else 'In Bearbeitung',
|
||||
'status': _request_status_label(obj.processing_status),
|
||||
'status_key': obj.processing_status,
|
||||
'last_error': obj.last_error,
|
||||
}
|
||||
)
|
||||
for obj in offboarding_items:
|
||||
@@ -398,7 +410,9 @@ def requests_dashboard(request):
|
||||
'pdf_url': f"/media/pdfs/{Path(obj.generated_pdf_path).name}" if obj.generated_pdf_path else None,
|
||||
'intro_pdf_url': None,
|
||||
'intro_session': None,
|
||||
'status': 'PDF erstellt' if obj.generated_pdf_path else 'In Bearbeitung',
|
||||
'status': _request_status_label(obj.processing_status),
|
||||
'status_key': obj.processing_status,
|
||||
'last_error': obj.last_error,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1682,3 +1696,29 @@ def delete_request_from_dashboard(request, kind: str, request_id: int):
|
||||
_audit(request, 'request_deleted', target_type=kind, target_id=request_id, target_label=str(obj))
|
||||
messages.success(request, f'{kind.capitalize()}-Anfrage #{request_id} wurde gelöscht.')
|
||||
return redirect('requests_dashboard')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
@require_POST
|
||||
def retry_request_from_dashboard(request, kind: str, request_id: int):
|
||||
if kind == 'onboarding':
|
||||
obj = get_object_or_404(OnboardingRequest, id=request_id)
|
||||
obj.processing_status = 'submitted'
|
||||
obj.last_error = ''
|
||||
obj.save(update_fields=['processing_status', 'last_error'])
|
||||
process_onboarding_request.delay(obj.id)
|
||||
_audit(request, 'request_retried', target_type='onboarding', target_id=obj.id, target_label=obj.full_name)
|
||||
elif kind == 'offboarding':
|
||||
obj = get_object_or_404(OffboardingRequest, id=request_id)
|
||||
obj.processing_status = 'submitted'
|
||||
obj.last_error = ''
|
||||
obj.save(update_fields=['processing_status', 'last_error'])
|
||||
process_offboarding_request.delay(obj.id)
|
||||
_audit(request, 'request_retried', target_type='offboarding', target_id=obj.id, target_label=obj.full_name)
|
||||
else:
|
||||
messages.error(request, f'Unbekannter Typ: {kind}')
|
||||
return redirect('requests_dashboard')
|
||||
|
||||
messages.success(request, f'{kind.capitalize()}-Anfrage #{request_id} wurde erneut angestoßen.')
|
||||
return redirect('requests_dashboard')
|
||||
|
||||
Reference in New Issue
Block a user