@@ -4,6 +4,7 @@ import { PlanningError } from "./../../middleware/error/planningError";
44import { RoomRepository } from "../room/Repository" ;
55import { LessonRepository } from "../lesson/Repository" ;
66import { ClassRepository } from "../class/Repository" ;
7+ import { UserRepository } from "../user/Repository" ;
78import { RoomError } from "../../middleware/error/roomError" ;
89import { LessonError } from "../../middleware/error/lessonError" ;
910import { WeeklyPlanningData , ImportResult , ImportError , ImportedLesson , ImportedLessonSchema , PlanningFilterOptions } from "./validate" ;
@@ -19,6 +20,7 @@ export class PlanningInteractor implements IPlanningInteractor {
1920 private roomRepository : RoomRepository ,
2021 private lessonRepository : LessonRepository ,
2122 private classRepository : ClassRepository ,
23+ private userRepository : UserRepository ,
2224 private optimizationService : OptimizationService ,
2325 ) { }
2426
@@ -66,6 +68,7 @@ export class PlanningInteractor implements IPlanningInteractor {
6668 async importLessonsFromTemplate ( fileBuffer : Buffer ) : Promise < ImportResult > {
6769 const errors : ImportError [ ] = [ ] ;
6870 let importedCount = 0 ;
71+ let updatedCount = 0 ;
6972 let skippedCount = 0 ;
7073 let earliestDate : Date | null = null ;
7174 let latestDate : Date | null = null ;
@@ -157,30 +160,114 @@ export class PlanningInteractor implements IPlanningInteractor {
157160 continue ;
158161 }
159162
160- const existingLesson = await this . lessonRepository . findLessonByDetails (
163+ let teacherId : string | null = null ;
164+ if ( validatedLesson . teacherName && validatedLesson . teacherName . trim ( ) ) {
165+ const nameParts = validatedLesson . teacherName . trim ( ) . split ( " " ) ;
166+ if ( nameParts . length >= 2 ) {
167+ const firstName = nameParts [ 0 ] ;
168+ const lastName = nameParts . slice ( 1 ) . join ( " " ) ;
169+ const teacher = await this . userRepository . findTeacherByName ( firstName , lastName ) ;
170+ if ( teacher ) {
171+ teacherId = teacher . id ;
172+ } else {
173+ errors . push ( {
174+ row : rowIndex + 1 ,
175+ field : "teacher_name" ,
176+ message : `Teacher "${ validatedLesson . teacherName } " not found` ,
177+ } ) ;
178+ }
179+ }
180+ }
181+
182+ const overlappingLessons = await this . lessonRepository . findOverlappingLessons (
161183 classEntity . id ,
162184 startDateTime ,
163185 endDateTime ,
164186 ) ;
165187
166- if ( existingLesson ) {
167- skippedCount ++ ;
168- } else {
169- await this . lessonRepository . createLesson ( {
188+ const lessonsToDelete = overlappingLessons . filter ( lesson => ! lesson . room_id ) ;
189+ for ( const lessonToDelete of lessonsToDelete ) {
190+ await this . lessonRepository . deleteLesson ( lessonToDelete . id ) ;
191+ }
192+
193+ const lessonsWithRoom = overlappingLessons . filter ( lesson => lesson . room_id ) ;
194+
195+ let lessonCreated = false ;
196+
197+ if ( lessonsWithRoom . length > 0 ) {
198+ if ( lessonsWithRoom . length > 1 ) {
199+ errors . push ( {
200+ row : rowIndex + 1 ,
201+ field : "time" ,
202+ message : "Multiple lessons with rooms overlap this time slot. Using the first one." ,
203+ } ) ;
204+ }
205+
206+ const lessonToUpdate = lessonsWithRoom [ 0 ] ;
207+
208+ // Check if there are actual changes
209+ const hasTimeChanged = lessonToUpdate . start_time . getTime ( ) !== startDateTime . getTime ( ) ||
210+ lessonToUpdate . end_time . getTime ( ) !== endDateTime . getTime ( ) ;
211+ const hasTitleChanged = lessonToUpdate . title !== validatedLesson . title ;
212+
213+ // Get current teacher to check if it changed
214+ const lessonWithRelations = await this . lessonRepository . getLessonWithRelations ( lessonToUpdate . id ) ;
215+ const currentTeacherId = lessonWithRelations ?. users ?. [ 0 ] ?. id ;
216+ const hasTeacherChanged = teacherId && teacherId !== currentTeacherId ;
217+
218+ if ( hasTimeChanged || hasTitleChanged || hasTeacherChanged ) {
219+ // There are changes - update the lesson
220+ const updateData : any = { } ;
221+ if ( hasTimeChanged ) {
222+ updateData . startTime = startDateTime ;
223+ updateData . endTime = endDateTime ;
224+ }
225+ if ( hasTitleChanged ) {
226+ updateData . title = validatedLesson . title ;
227+ }
228+
229+ if ( Object . keys ( updateData ) . length > 0 ) {
230+ await this . lessonRepository . updateLesson ( lessonToUpdate . id , updateData ) ;
231+ }
232+
233+ if ( hasTeacherChanged && teacherId ) {
234+ await this . lessonRepository . updateLessonTeacher ( lessonToUpdate . id , teacherId ) ;
235+ }
236+
237+ updatedCount ++ ;
238+
239+ if ( ! earliestDate || startDateTime < earliestDate ) {
240+ earliestDate = startDateTime ;
241+ }
242+ if ( ! latestDate || endDateTime > latestDate ) {
243+ latestDate = endDateTime ;
244+ }
245+ } else {
246+ skippedCount ++ ;
247+ }
248+
249+ lessonCreated = true ;
250+ }
251+
252+ if ( ! lessonCreated ) {
253+ const newLesson = await this . lessonRepository . createLesson ( {
170254 title : validatedLesson . title ,
171255 startTime : startDateTime ,
172256 endTime : endDateTime ,
173257 classId : classEntity . id ,
174258 roomId : null ,
175259 } ) ;
260+ if ( teacherId ) {
261+ await this . lessonRepository . updateLessonTeacher ( newLesson . id , teacherId ) ;
262+ }
176263 importedCount ++ ;
264+ }
177265
178- if ( ! earliestDate || startDateTime < earliestDate ) {
179- earliestDate = startDateTime ;
180- }
181- if ( ! latestDate || endDateTime > latestDate ) {
182- latestDate = endDateTime ;
183- }
266+ if ( ! earliestDate || startDateTime < earliestDate ) {
267+ earliestDate = startDateTime ;
268+ }
269+ if ( ! latestDate || endDateTime > latestDate ) {
270+ latestDate = endDateTime ;
184271 }
185272 } catch ( error ) {
186273 if ( error instanceof Error ) {
@@ -194,7 +281,7 @@ export class PlanningInteractor implements IPlanningInteractor {
194281
195282 let optimizationStatus = undefined ;
196283
197- if ( importedCount > 0 && earliestDate && latestDate ) {
284+ if ( ( importedCount > 0 || updatedCount > 0 ) && earliestDate && latestDate ) {
198285 try {
199286 await this . optimizationService . optimizeDateRange ( earliestDate , latestDate ) ;
200287 optimizationStatus = { status : "success" as const } ;
@@ -209,6 +296,7 @@ export class PlanningInteractor implements IPlanningInteractor {
209296
210297 return {
211298 importedCount,
299+ updatedCount,
212300 skippedCount,
213301 errors,
214302 optimization : optimizationStatus ,
0 commit comments