11class RoomException < ApplicationRecord
2- # Room 모델과 다대일 관계를 가집니다.
32 belongs_to :room
43
5- # Callbacks
64 after_save :cancel_conflicting_reservations
75
86 # 기본 유효성 검사
@@ -15,7 +13,7 @@ class RoomException < ApplicationRecord
1513 validate :validate_time_order
1614 validate :validate_duplicate_date
1715
18- # 소프트 삭제 ( Soft Delete)
16+ # Soft Delete
1917 default_scope { where ( deleted_at : nil ) }
2018
2119 def soft_delete
@@ -32,68 +30,75 @@ def self.with_deleted
3230 # 1) 전체 휴일 vs 부분 휴일 규칙
3331 # ----------------------------------------
3432 def validate_time_rule
35- # 전체 휴일 (both nil) → OK
3633 return if opening_time . nil? && closing_time . nil?
3734
38- # 부분 휴일 → 둘 다 있어야 함
3935 if opening_time . present? ^ closing_time . present?
4036 errors . add ( :base , "Both opening_time and closing_time must be present for partial holiday" )
4137 end
4238 end
4339
4440 # ----------------------------------------
45- # 2) 시간 순서 검증
41+ # 2) 시간 순서 검증 (Time.parse 적용)
4642 # ----------------------------------------
4743 def validate_time_order
4844 return if opening_time . blank? || closing_time . blank?
4945
50- if opening_time >= closing_time
51- errors . add ( :opening_time , "must be earlier than closing_time" )
46+ begin
47+ ot = Time . parse ( opening_time )
48+ ct = Time . parse ( closing_time )
49+
50+ errors . add ( :opening_time , "must be earlier than closing_time" ) if ot >= ct
51+ rescue ArgumentError
52+ errors . add ( :base , "Invalid time format (expected HH:MM)" )
5253 end
5354 end
5455
5556 # ----------------------------------------
56- # 3) 동일 날짜 중복 방지 (soft-delete 제외)
57+ # 3) 동일 날짜 중복 방지
5758 # ----------------------------------------
5859 def validate_duplicate_date
5960 return if room_id . blank? || holiday_date . blank?
6061
61- duplicate = RoomException . with_deleted
62- . where ( room_id : room_id , holiday_date : holiday_date , deleted_at : nil )
63- . where . not ( id : id )
64- . exists?
62+ duplicate = RoomException
63+ . where ( room_id : room_id , holiday_date : holiday_date , deleted_at : nil )
64+ . where . not ( id : id )
65+ . exists?
6566
6667 if duplicate
6768 errors . add ( :holiday_date , "exception already exists for this date" )
6869 end
6970 end
7071
7172 # ----------------------------------------
72- # 기존 예약 자동 취소 로직 (그대로 유지 )
73+ # 기존 예약 자동 취소 로직 (시간 비교 개선 )
7374 # ----------------------------------------
7475 def cancel_conflicting_reservations
7576 reservations_on_date = Reservation . where (
7677 room_id : room_id ,
7778 start_time : holiday_date . all_day
7879 )
7980
80- # Case 1: 완전 휴무일
81+ # Case 1: 완전 휴무일 → 모두 삭제
8182 if opening_time . nil? && closing_time . nil?
8283 reservations_on_date . find_each { |reservation | reservation . soft_delete ( deleted_by : 0 ) }
8384 return
8485 end
8586
86- # Case 2: 부분 휴무
87+ # Case 2: 부분 휴무일
8788 if opening_time . present? && closing_time . present?
88- exception_opening_time_str = opening_time . strftime ( '%H:%M' )
89- exception_closing_time_str = closing_time . strftime ( '%H:%M' )
89+ begin
90+ ex_start = Time . parse ( opening_time )
91+ ex_end = Time . parse ( closing_time )
92+ rescue ArgumentError
93+ return
94+ end
9095
9196 reservations_on_date . find_each do |reservation |
92- start_time_str = reservation . start_time . strftime ( '%H:%M' )
93- end_time_str = reservation . end_time . strftime ( '%H:%M' )
97+ r_start = reservation . start_time
98+ r_end = reservation . end_time
9499
95- unless start_time_str >= exception_opening_time_str &&
96- end_time_str <= exception_closing_time_str
100+ # 예외 시간 외에 걸치면 삭제
101+ unless ( r_start >= ex_start && r_end <= ex_end )
97102 reservation . soft_delete ( deleted_by : 0 )
98103 end
99104 end
0 commit comments