406 lines
20 KiB
HTML
406 lines
20 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if object %}Edit Delivery Log{% else %}New Delivery Log{% endif %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div>
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'communications:dashboard' %}">Communications</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'communications:delivery_log_list' %}">Delivery Logs</a></li>
|
|
<li class="breadcrumb-item active">{% if object %}Edit{% else %}New{% endif %}</li>
|
|
</ol>
|
|
<h1 class="page-header mb-0">
|
|
{% if object %}Edit Delivery Log{% else %}Create Delivery Log{% endif %}
|
|
</h1>
|
|
</div>
|
|
<div class="ms-auto">
|
|
<a href="{% url 'communications:delivery_log_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-arrow-left me-2"></i>Back to List
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-xl-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">
|
|
<i class="fas fa-shipping-fast me-2"></i>
|
|
Delivery Log Details
|
|
</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if messages %}
|
|
{% for message in messages %}
|
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.message.id_for_label }}" class="form-label">Message *</label>
|
|
<select class="form-select {% if form.message.errors %}is-invalid{% endif %}"
|
|
id="{{ form.message.id_for_label }}"
|
|
name="{{ form.message.name }}"
|
|
required>
|
|
<option value="">Select Message</option>
|
|
{% for choice in form.message.field.choices %}
|
|
{% if choice.0 %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.message.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.message.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.message.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.recipient.id_for_label }}" class="form-label">Recipient *</label>
|
|
<input type="text"
|
|
class="form-control {% if form.recipient.errors %}is-invalid{% endif %}"
|
|
id="{{ form.recipient.id_for_label }}"
|
|
name="{{ form.recipient.name }}"
|
|
value="{{ form.recipient.value|default:'' }}"
|
|
placeholder="Enter recipient email or phone"
|
|
required>
|
|
{% if form.recipient.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.recipient.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.delivery_method.id_for_label }}" class="form-label">Delivery Method *</label>
|
|
<select class="form-select {% if form.delivery_method.errors %}is-invalid{% endif %}"
|
|
id="{{ form.delivery_method.id_for_label }}"
|
|
name="{{ form.delivery_method.name }}"
|
|
required>
|
|
{% for choice in form.delivery_method.field.choices %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.delivery_method.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.delivery_method.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.delivery_method.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.status.id_for_label }}" class="form-label">Status *</label>
|
|
<select class="form-select {% if form.status.errors %}is-invalid{% endif %}"
|
|
id="{{ form.status.id_for_label }}"
|
|
name="{{ form.status.name }}"
|
|
required>
|
|
{% for choice in form.status.field.choices %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.status.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.status.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.status.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.sent_at.id_for_label }}" class="form-label">Sent At</label>
|
|
<input type="datetime-local"
|
|
class="form-control {% if form.sent_at.errors %}is-invalid{% endif %}"
|
|
id="{{ form.sent_at.id_for_label }}"
|
|
name="{{ form.sent_at.name }}"
|
|
value="{{ form.sent_at.value|default:'' }}">
|
|
{% if form.sent_at.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.sent_at.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.delivered_at.id_for_label }}" class="form-label">Delivered At</label>
|
|
<input type="datetime-local"
|
|
class="form-control {% if form.delivered_at.errors %}is-invalid{% endif %}"
|
|
id="{{ form.delivered_at.id_for_label }}"
|
|
name="{{ form.delivered_at.name }}"
|
|
value="{{ form.delivered_at.value|default:'' }}">
|
|
{% if form.delivered_at.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.delivered_at.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.error_message.id_for_label }}" class="form-label">Error Message</label>
|
|
<textarea class="form-control {% if form.error_message.errors %}is-invalid{% endif %}"
|
|
id="{{ form.error_message.id_for_label }}"
|
|
name="{{ form.error_message.name }}"
|
|
rows="3"
|
|
placeholder="Enter any error messages or delivery issues...">{{ form.error_message.value|default:'' }}</textarea>
|
|
{% if form.error_message.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.error_message.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.retry_count.id_for_label }}" class="form-label">Retry Count</label>
|
|
<input type="number"
|
|
class="form-control {% if form.retry_count.errors %}is-invalid{% endif %}"
|
|
id="{{ form.retry_count.id_for_label }}"
|
|
name="{{ form.retry_count.name }}"
|
|
value="{{ form.retry_count.value|default:'0' }}"
|
|
min="0"
|
|
max="10">
|
|
{% if form.retry_count.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.retry_count.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.next_retry_at.id_for_label }}" class="form-label">Next Retry At</label>
|
|
<input type="datetime-local"
|
|
class="form-control {% if form.next_retry_at.errors %}is-invalid{% endif %}"
|
|
id="{{ form.next_retry_at.id_for_label }}"
|
|
name="{{ form.next_retry_at.name }}"
|
|
value="{{ form.next_retry_at.value|default:'' }}">
|
|
{% if form.next_retry_at.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.next_retry_at.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.delivery_details.id_for_label }}" class="form-label">Delivery Details</label>
|
|
<textarea class="form-control {% if form.delivery_details.errors %}is-invalid{% endif %}"
|
|
id="{{ form.delivery_details.id_for_label }}"
|
|
name="{{ form.delivery_details.name }}"
|
|
rows="4"
|
|
placeholder="Additional delivery details, tracking information, etc...">{{ form.delivery_details.value|default:'' }}</textarea>
|
|
{% if form.delivery_details.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.delivery_details.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
{% if object %}
|
|
<a href="{% url 'communications:delivery_log_detail' object.pk %}" class="btn btn-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
{% else %}
|
|
<a href="{% url 'communications:delivery_log_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-2"></i>
|
|
{% if object %}Update Log{% else %}Create Log{% endif %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-4">
|
|
<!-- Delivery Status Guide -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
Delivery Status Guide
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<span class="badge bg-warning me-2">Pending</span>
|
|
<small>Message queued for delivery</small>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="badge bg-info me-2">Sending</span>
|
|
<small>Currently being sent</small>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="badge bg-success me-2">Delivered</span>
|
|
<small>Successfully delivered</small>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="badge bg-danger me-2">Failed</span>
|
|
<small>Delivery failed</small>
|
|
</div>
|
|
<div>
|
|
<span class="badge bg-secondary me-2">Cancelled</span>
|
|
<small>Delivery cancelled</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delivery Methods -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-paper-plane me-2"></i>
|
|
Delivery Methods
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<i class="fas fa-envelope text-primary me-2"></i>
|
|
<strong>Email</strong>
|
|
<div class="small text-muted">Standard email delivery</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<i class="fas fa-sms text-success me-2"></i>
|
|
<strong>SMS</strong>
|
|
<div class="small text-muted">Text message delivery</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<i class="fas fa-bell text-warning me-2"></i>
|
|
<strong>Push</strong>
|
|
<div class="small text-muted">Push notification</div>
|
|
</div>
|
|
<div>
|
|
<i class="fas fa-globe text-info me-2"></i>
|
|
<strong>Web</strong>
|
|
<div class="small text-muted">In-app notification</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-bolt me-2"></i>
|
|
Quick Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="setCurrentTime('sent_at')">
|
|
<i class="fas fa-clock me-2"></i>Set Current Time (Sent)
|
|
</button>
|
|
<button type="button" class="btn btn-outline-success btn-sm" onclick="setCurrentTime('delivered_at')">
|
|
<i class="fas fa-check me-2"></i>Mark as Delivered Now
|
|
</button>
|
|
<button type="button" class="btn btn-outline-warning btn-sm" onclick="scheduleRetry()">
|
|
<i class="fas fa-redo me-2"></i>Schedule Retry
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const statusSelect = document.getElementById('{{ form.status.id_for_label }}');
|
|
const errorMessageField = document.getElementById('{{ form.error_message.id_for_label }}');
|
|
const retryFields = ['{{ form.retry_count.id_for_label }}', '{{ form.next_retry_at.id_for_label }}'];
|
|
|
|
// Show/hide fields based on status
|
|
function toggleFieldsBasedOnStatus() {
|
|
const status = statusSelect.value;
|
|
|
|
if (status === 'failed') {
|
|
errorMessageField.parentElement.style.display = 'block';
|
|
retryFields.forEach(fieldId => {
|
|
document.getElementById(fieldId).parentElement.parentElement.style.display = 'block';
|
|
});
|
|
} else if (status === 'delivered') {
|
|
errorMessageField.parentElement.style.display = 'none';
|
|
errorMessageField.value = '';
|
|
}
|
|
}
|
|
|
|
statusSelect.addEventListener('change', toggleFieldsBasedOnStatus);
|
|
toggleFieldsBasedOnStatus(); // Initial call
|
|
|
|
// Auto-set delivered time when status changes to delivered
|
|
statusSelect.addEventListener('change', function() {
|
|
if (this.value === 'delivered') {
|
|
const deliveredAtField = document.getElementById('{{ form.delivered_at.id_for_label }}');
|
|
if (!deliveredAtField.value) {
|
|
setCurrentTime('delivered_at');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
function setCurrentTime(fieldSuffix) {
|
|
const now = new Date();
|
|
const isoString = now.toISOString().slice(0, 16); // Format for datetime-local
|
|
const field = document.getElementById(`{{ form.${fieldSuffix}.id_for_label }}`.replace('${fieldSuffix}', fieldSuffix));
|
|
if (field) {
|
|
field.value = isoString;
|
|
}
|
|
}
|
|
|
|
function scheduleRetry() {
|
|
const retryCountField = document.getElementById('{{ form.retry_count.id_for_label }}');
|
|
const nextRetryField = document.getElementById('{{ form.next_retry_at.id_for_label }}');
|
|
|
|
// Increment retry count
|
|
const currentCount = parseInt(retryCountField.value) || 0;
|
|
retryCountField.value = currentCount + 1;
|
|
|
|
// Set next retry time (15 minutes from now)
|
|
const nextRetry = new Date();
|
|
nextRetry.setMinutes(nextRetry.getMinutes() + 15);
|
|
nextRetryField.value = nextRetry.toISOString().slice(0, 16);
|
|
|
|
// Set status to pending
|
|
document.getElementById('{{ form.status.id_for_label }}').value = 'pending';
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|