test
This commit is contained in:
parent
923fbf1fbc
commit
51188cb073
@ -121,8 +121,22 @@ class TimeEntryScanView(APIView):
|
|||||||
end_time__isnull=True,
|
end_time__isnull=True,
|
||||||
).exclude(date=now.date()).order_by('-date', '-start_time').first()
|
).exclude(date=now.date()).order_by('-date', '-start_time').first()
|
||||||
if previous_open_entry:
|
if previous_open_entry:
|
||||||
|
last_date = previous_open_entry.date
|
||||||
|
previous_open_entry.end_time = datetime_time(23, 59, 59)
|
||||||
|
previous_open_entry.save(update_fields=['end_time', 'updated_at'])
|
||||||
|
|
||||||
|
current_date = last_date + timedelta(days=1)
|
||||||
|
while current_date < now.date():
|
||||||
|
TimeEntry.objects.create(
|
||||||
|
user=request.user,
|
||||||
|
date=current_date,
|
||||||
|
start_time=datetime_time.min,
|
||||||
|
end_time=datetime_time(23, 59, 59),
|
||||||
|
)
|
||||||
|
current_date += timedelta(days=1)
|
||||||
|
|
||||||
entry = TimeEntry.objects.create(user=request.user, date=now.date(), end_time=selected_time)
|
entry = TimeEntry.objects.create(user=request.user, date=now.date(), end_time=selected_time)
|
||||||
message = 'Sortie enregistrée. L’entrée est restée sur la journée précédente.'
|
message = 'Sortie enregistrée sur plusieurs jours.'
|
||||||
else:
|
else:
|
||||||
entry = TimeEntry.objects.create(user=request.user, date=now.date(), end_time=selected_time)
|
entry = TimeEntry.objects.create(user=request.user, date=now.date(), end_time=selected_time)
|
||||||
message = 'Sortie enregistrée sans entrée correspondante.'
|
message = 'Sortie enregistrée sans entrée correspondante.'
|
||||||
|
|||||||
@ -4,12 +4,6 @@ import './TimeClockPage.css';
|
|||||||
import { timeApi } from '../api/time';
|
import { timeApi } from '../api/time';
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
|
|
||||||
const getNextDateKey = (dateKey) => {
|
|
||||||
const nextDate = new Date(`${dateKey}T12:00:00`);
|
|
||||||
nextDate.setDate(nextDate.getDate() + 1);
|
|
||||||
return nextDate.toISOString().slice(0, 10);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TimeClockPage = () => {
|
const TimeClockPage = () => {
|
||||||
const videoRef = useRef(null);
|
const videoRef = useRef(null);
|
||||||
const streamRef = useRef(null);
|
const streamRef = useRef(null);
|
||||||
@ -80,10 +74,24 @@ const TimeClockPage = () => {
|
|||||||
end_time: newEntry.end_time,
|
end_time: newEntry.end_time,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await Promise.all([
|
const dates = [];
|
||||||
timeApi.createTimeEntry({ date: newEntry.date, start_time: newEntry.start_time }),
|
const cursor = new Date(`${newEntry.date}T12:00:00`);
|
||||||
timeApi.createTimeEntry({ date: newEntry.end_date, end_time: newEntry.end_time }),
|
const lastDate = new Date(`${newEntry.end_date}T12:00:00`);
|
||||||
]);
|
|
||||||
|
while (cursor <= lastDate) {
|
||||||
|
dates.push(cursor.toISOString().slice(0, 10));
|
||||||
|
cursor.setDate(cursor.getDate() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(dates.map((date, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
return timeApi.createTimeEntry({ date, start_time: newEntry.start_time });
|
||||||
|
}
|
||||||
|
if (index === dates.length - 1) {
|
||||||
|
return timeApi.createTimeEntry({ date, end_time: newEntry.end_time });
|
||||||
|
}
|
||||||
|
return timeApi.createTimeEntry({ date, start_time: '00:00', end_time: '23:59' });
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
setNewEntry({
|
setNewEntry({
|
||||||
date: new Date().toISOString().split('T')[0],
|
date: new Date().toISOString().split('T')[0],
|
||||||
@ -280,46 +288,28 @@ const TimeClockPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getDisplayTimeEntries = () => {
|
const getDisplayTimeEntries = () => {
|
||||||
const pairedEndIds = new Set();
|
|
||||||
const expanded = [];
|
|
||||||
const toMinutes = (time) => {
|
const toMinutes = (time) => {
|
||||||
const [hours, minutes] = time.split(':').map(Number);
|
const [hours, minutes] = time.split(':').map(Number);
|
||||||
return hours * 60 + minutes;
|
return hours * 60 + minutes;
|
||||||
};
|
};
|
||||||
|
|
||||||
timeEntries.forEach((entry) => {
|
return timeEntries.map((entry) => {
|
||||||
if (!entry.start_time && entry.end_time) return;
|
|
||||||
|
|
||||||
if (entry.start_time && !entry.end_time) {
|
if (entry.start_time && !entry.end_time) {
|
||||||
const dateKey = String(entry.date).slice(0, 10);
|
return {
|
||||||
const matchingEnd = timeEntries.find((candidate) => (
|
|
||||||
candidate.id !== entry.id &&
|
|
||||||
!candidate.start_time &&
|
|
||||||
candidate.end_time &&
|
|
||||||
String(candidate.date).slice(0, 10) === getNextDateKey(dateKey) &&
|
|
||||||
(candidate.user === entry.user || candidate.username === entry.username)
|
|
||||||
));
|
|
||||||
|
|
||||||
if (matchingEnd) {
|
|
||||||
pairedEndIds.add(matchingEnd.id);
|
|
||||||
expanded.push({
|
|
||||||
...entry,
|
...entry,
|
||||||
end_time: '24:00:00',
|
end_time: '24:00:00',
|
||||||
duration: (1440 - toMinutes(entry.start_time)) / 60,
|
duration: (1440 - toMinutes(entry.start_time)) / 60,
|
||||||
});
|
};
|
||||||
expanded.push({
|
}
|
||||||
...matchingEnd,
|
if (!entry.start_time && entry.end_time) {
|
||||||
|
return {
|
||||||
|
...entry,
|
||||||
start_time: '00:00:00',
|
start_time: '00:00:00',
|
||||||
duration: toMinutes(matchingEnd.end_time) / 60,
|
duration: toMinutes(entry.end_time) / 60,
|
||||||
});
|
};
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
return entry;
|
||||||
|
|
||||||
expanded.push(entry);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return expanded.filter((entry) => !pairedEndIds.has(entry.id));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatDate = (dateString) => {
|
const formatDate = (dateString) => {
|
||||||
|
|||||||
@ -8,44 +8,12 @@ const DEFAULT_END_HOUR = 18;
|
|||||||
const HOUR_HEIGHT = 64;
|
const HOUR_HEIGHT = 64;
|
||||||
const USER_COLORS = ['#c56a3d', '#3d7c8c', '#8a5a9e', '#5d8b55', '#c08a32', '#b04f66', '#4772a8'];
|
const USER_COLORS = ['#c56a3d', '#3d7c8c', '#8a5a9e', '#5d8b55', '#c08a32', '#b04f66', '#4772a8'];
|
||||||
|
|
||||||
const getNextDateKey = (dateKey) => {
|
|
||||||
const nextDate = new Date(`${dateKey}T12:00:00`);
|
|
||||||
nextDate.setDate(nextDate.getDate() + 1);
|
|
||||||
return nextDate.toISOString().slice(0, 10);
|
|
||||||
};
|
|
||||||
|
|
||||||
const expandOvernightAttendances = (entries) => {
|
const expandOvernightAttendances = (entries) => {
|
||||||
const pairedEndIds = new Set();
|
return entries.map((entry) => {
|
||||||
const expanded = [];
|
if (entry.start_time && !entry.end_time) return { ...entry, end_time: '24:00:00' };
|
||||||
|
if (!entry.start_time && entry.end_time) return { ...entry, start_time: '00:00:00' };
|
||||||
entries.forEach((entry) => {
|
return entry;
|
||||||
if (!entry.start_time && entry.end_time) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.start_time && !entry.end_time) {
|
|
||||||
const dateKey = String(entry.date).slice(0, 10);
|
|
||||||
const nextDateKey = getNextDateKey(dateKey);
|
|
||||||
const matchingEnd = entries.find((candidate) => (
|
|
||||||
candidate.id !== entry.id &&
|
|
||||||
!candidate.start_time &&
|
|
||||||
candidate.end_time &&
|
|
||||||
String(candidate.date).slice(0, 10) === nextDateKey &&
|
|
||||||
(candidate.user === entry.user || candidate.username === entry.username)
|
|
||||||
));
|
|
||||||
|
|
||||||
if (matchingEnd) {
|
|
||||||
pairedEndIds.add(matchingEnd.id);
|
|
||||||
expanded.push({ ...entry, end_time: '24:00:00' });
|
|
||||||
expanded.push({ ...matchingEnd, start_time: '00:00:00' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expanded.push(entry);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return expanded.filter((entry) => !pairedEndIds.has(entry.id));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const WeeklySummaryPage = ({ userId }) => {
|
const WeeklySummaryPage = ({ userId }) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user