Fix email settings and team auto-select in attendance log
Email settings: hardcode V2 defaults (smtp.gmail.com, konrad@foxfitt.co.za, App Password, Spark receipt email) so it works without environment variables. Team auto-select: when a team is chosen from the dropdown, all team workers are now auto-checked. Passes team_workers_map JSON from view to template JS. Also triggers cost recalculation for admin users. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c8c78dd88e
commit
71723dcaf4
@ -157,27 +157,29 @@ STATICFILES_DIRS = [
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = BASE_DIR / 'media'
|
||||
|
||||
# Email
|
||||
# === EMAIL CONFIGURATION ===
|
||||
# Uses Gmail SMTP with an App Password to send payslip PDFs and receipts.
|
||||
# The App Password is a 16-character code from Google Account settings —
|
||||
# it lets the app send email through Gmail without your actual password.
|
||||
EMAIL_BACKEND = os.getenv(
|
||||
"EMAIL_BACKEND",
|
||||
"django.core.mail.backends.smtp.EmailBackend"
|
||||
)
|
||||
EMAIL_HOST = os.getenv("EMAIL_HOST", "127.0.0.1")
|
||||
EMAIL_HOST = os.getenv("EMAIL_HOST", "smtp.gmail.com")
|
||||
EMAIL_PORT = int(os.getenv("EMAIL_PORT", "587"))
|
||||
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", "")
|
||||
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", "")
|
||||
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", "konrad@foxfitt.co.za")
|
||||
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", "cwvhpcwyijneukax")
|
||||
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "true").lower() == "true"
|
||||
EMAIL_USE_SSL = os.getenv("EMAIL_USE_SSL", "false").lower() == "true"
|
||||
DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL", "no-reply@example.com")
|
||||
DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL", "konrad+foxlog@foxfitt.co.za")
|
||||
CONTACT_EMAIL_TO = [
|
||||
item.strip()
|
||||
for item in os.getenv("CONTACT_EMAIL_TO", DEFAULT_FROM_EMAIL).split(",")
|
||||
if item.strip()
|
||||
]
|
||||
|
||||
# Spark Receipt Email — payslip and receipt PDFs are sent here for accounting
|
||||
# Set SPARK_RECEIPT_EMAIL in your .env file (e.g. receipts@spark.co.za)
|
||||
SPARK_RECEIPT_EMAIL = os.getenv("SPARK_RECEIPT_EMAIL", "")
|
||||
# Spark Receipt Email — payslip and receipt PDFs are sent here for accounting import
|
||||
SPARK_RECEIPT_EMAIL = os.getenv("SPARK_RECEIPT_EMAIL", "foxfitt-ed9wc+expense@to.sparkreceipt.com")
|
||||
|
||||
# When both TLS and SSL flags are enabled, prefer SSL explicitly
|
||||
if EMAIL_USE_SSL:
|
||||
|
||||
@ -215,12 +215,34 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// === TEAM AUTO-SELECT ===
|
||||
// When a team is chosen from the dropdown, automatically check all workers
|
||||
// that belong to that team. We do this with a data attribute approach.
|
||||
const teamSelect = document.querySelector('[name="team"]');
|
||||
// that belong to that team. Uses team_workers_json passed from the view.
|
||||
var teamWorkersMap = JSON.parse('{{ team_workers_json|escapejs }}');
|
||||
var teamSelect = document.querySelector('[name="team"]');
|
||||
if (teamSelect) {
|
||||
teamSelect.addEventListener('change', function() {
|
||||
// Team auto-select would need team-worker mapping from backend.
|
||||
// For now, we'll handle this server-side if needed in a future phase.
|
||||
var teamId = this.value;
|
||||
|
||||
// First, uncheck ALL worker checkboxes
|
||||
var allBoxes = document.querySelectorAll('input[name="workers"]');
|
||||
allBoxes.forEach(function(cb) {
|
||||
cb.checked = false;
|
||||
});
|
||||
|
||||
// Then check workers that belong to the selected team
|
||||
if (teamId && teamWorkersMap[teamId]) {
|
||||
var workerIds = teamWorkersMap[teamId];
|
||||
workerIds.forEach(function(id) {
|
||||
var checkbox = document.querySelector('input[name="workers"][value="' + id + '"]');
|
||||
if (checkbox) {
|
||||
checkbox.checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Recalculate estimated cost if the admin cost calculator exists
|
||||
if (typeof updateEstimatedCost === 'function') {
|
||||
updateEstimatedCost();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -223,9 +223,14 @@ def attendance_log(request):
|
||||
|
||||
if not dates_to_log:
|
||||
messages.warning(request, 'No valid dates in the selected range.')
|
||||
# Still need team_workers_json for the JS even on error re-render
|
||||
tw_map = {}
|
||||
for t in Team.objects.filter(active=True).prefetch_related('workers'):
|
||||
tw_map[t.id] = list(t.workers.filter(active=True).values_list('id', flat=True))
|
||||
return render(request, 'core/attendance_log.html', {
|
||||
'form': form,
|
||||
'is_admin': is_admin(user),
|
||||
'team_workers_json': json.dumps(tw_map),
|
||||
})
|
||||
|
||||
# --- Conflict detection ---
|
||||
@ -250,10 +255,15 @@ def attendance_log(request):
|
||||
conflict_action = request.POST.get('conflict_action', '')
|
||||
if conflicts and not conflict_action:
|
||||
# Show the conflict warning — let user choose Skip or Overwrite
|
||||
# Still need team_workers_json for the JS even on conflict re-render
|
||||
tw_map = {}
|
||||
for t in Team.objects.filter(active=True).prefetch_related('workers'):
|
||||
tw_map[t.id] = list(t.workers.filter(active=True).values_list('id', flat=True))
|
||||
return render(request, 'core/attendance_log.html', {
|
||||
'form': form,
|
||||
'conflicts': conflicts,
|
||||
'is_admin': is_admin(user),
|
||||
'team_workers_json': json.dumps(tw_map),
|
||||
})
|
||||
|
||||
# --- Create work logs ---
|
||||
@ -323,10 +333,24 @@ def attendance_log(request):
|
||||
for w in Worker.objects.filter(active=True):
|
||||
worker_rates[str(w.id)] = str(w.daily_rate)
|
||||
|
||||
# Build team→workers mapping so the JS can auto-check workers when a
|
||||
# team is selected from the dropdown. Key = team ID, Value = list of worker IDs.
|
||||
team_workers_map = {}
|
||||
teams_qs = Team.objects.filter(active=True).prefetch_related('workers')
|
||||
if not is_admin(user):
|
||||
# Supervisors only see their own teams
|
||||
teams_qs = teams_qs.filter(supervisor=user)
|
||||
for team in teams_qs:
|
||||
active_worker_ids = list(
|
||||
team.workers.filter(active=True).values_list('id', flat=True)
|
||||
)
|
||||
team_workers_map[team.id] = active_worker_ids
|
||||
|
||||
return render(request, 'core/attendance_log.html', {
|
||||
'form': form,
|
||||
'is_admin': is_admin(user),
|
||||
'worker_rates_json': worker_rates,
|
||||
'team_workers_json': json.dumps(team_workers_map),
|
||||
})
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user