def formatted_date(self) -> str: return Date(self.date).format_date
def display_edit_delete(self) -> str: return "disabled" if current_user.role == Config.HOTEL and self.date < Date.previous_lock_in() else str()
def link_goto(self) -> str: return url_for("usage_manage", hotel_id=self.hotel.id, date=Date(self.goto_date.data).db_date, timing=self.goto_timing.data)
def display_next(self) -> str: if not self.usages: return "disabled" end_date = min(self.hotel.contract[1], Date.next_lock_in()) return "disabled" if (self.date == end_date and self.timing == Config.EVENING) or self.date > end_date \ else str()
def validate_filename(self, filename: FileField): if self.form_type.data != self.UPLOAD: return file: FileStorage = filename.data if not secure_filename(file.filename): raise ValidationError("No file selected for upload") file_path = File(current_user.id, "csv").local_path file.save(file_path) with open(file_path) as csv_file: csv_reader = csv.DictReader(csv_file) columns = set(csv_reader.fieldnames) csv_reader = [row for row in csv_reader] if columns != {HDR.DATE, HDR.TIMING, HDR.NO_EVENT, HDR.CLIENT, HDR.MEAL, HDR.TYPE, HDR.BALLROOM, HDR.EVENT}: raise ValidationError("Invalid column names in the csv file") for row in csv_reader: usage = Usage() usage.hotel = self.hotel.name usage.city = self.hotel.city date = Date.from_dd_mmm_yyyy(row[HDR.DATE]).date if not date: self.add_errors(row, HDR.DATE) continue usage.set_date(date) if row[HDR.TIMING] not in Config.TIMINGS: self.add_errors(row, HDR.TIMING) continue usage.timing = row[HDR.TIMING] if row[HDR.NO_EVENT] == HDR.NO_EVENT: usage.no_event = True self.upload_data.append(usage) continue if not row[HDR.CLIENT]: self.add_errors(row, HDR.CLIENT) continue usage.client = row[HDR.CLIENT] if usage.timing == Config.MORNING: if row[HDR.MEAL] not in Config.MORNING_MEALS: self.add_errors(row, HDR.MEAL) continue usage.meals = [Config.BREAKFAST, Config.LUNCH] if row[HDR.MEAL] == Config.BREAKFAST_LUNCH \ else [row[HDR.MEAL]] else: if row[HDR.MEAL] not in Config.EVENING_MEALS: self.add_errors(row, HDR.MEAL) continue usage.meals = [Config.HI_TEA, Config.DINNER] if row[HDR.MEAL] == Config.HI_TEA_DINNER \ else [row[HDR.MEAL]] if row[HDR.TYPE] not in Config.EVENTS: self.add_errors(row, HDR.TYPE) continue usage.event_type = row[HDR.TYPE] ballrooms = [room.strip() for room in row[HDR.BALLROOM].split(",")] if any(room not in self.hotel.ballrooms for room in ballrooms): self.add_errors(row, HDR.BALLROOM) continue usage.ballrooms = ballrooms self.hotel.set_ballroom_used(ballrooms) usage.event_description = row[HDR.EVENT] self.upload_data.append(usage) if self.upload_errors: raise ValidationError("Field specific errors. Fields with red highlight have errors.") if not self.upload_data: raise ValidationError("There are no events in the csv file") self.upload_data.sort(key=lambda usage_item: usage_item.timing, reverse=True) self.upload_data.sort(key=lambda usage_item: usage_item.date) if current_user.role != Config.ADMIN: self._check_start_period_of_uploaded_file() last_date, lock_in, end_date = Date(self.upload_data[-1].date).date, Date.next_lock_in(), self.hotel.contract[1] if last_date > lock_in: raise ValidationError(f"End period ({Date(last_date).format_date}) cannot be greater than the " f"next lock in period ({Date(lock_in).format_date})") if last_date > end_date: raise ValidationError(f"End period ({Date(last_date).format_date}) cannot be greater than the " f"contract end date ({Date(end_date).format_date})") previous_date = None for date, date_usages in itertools.groupby(self.upload_data, key=lambda usage_item: usage_item.date): date = Date(date).date date_usages = list(date_usages) if not any(usage.timing == Config.MORNING for usage in date_usages): raise ValidationError(f"Date {Date(date).format_date} does not have {Config.MORNING} events") if not any(usage.timing == Config.EVENING for usage in date_usages): raise ValidationError(f"Date {Date(date).format_date} does not have {Config.EVENING} events") for timing, timing_usages in itertools.groupby(date_usages, key=lambda usage_item: usage_item.timing): seen = set() for usage in timing_usages: if usage.client in seen: raise ValidationError(f"Duplicate client name {usage.client} for the period " f"{Date(date).format_date} - {timing}") seen.add(usage.client) if previous_date and (date - previous_date).days != 1: raise ValidationError(f"There are missing events between {Date(previous_date).format_date} and " f"{Date(date).format_date}") previous_date = date return
def _check_start_period_of_uploaded_file(self): first_date, first_timing = Date(self.upload_data[0].date).date, self.upload_data[0].timing next_date, next_timing = Usage.get_data_entry_date(self.hotel) if (first_date, first_timing) != (next_date, next_timing): raise ValidationError(f"Start period ({Date(first_date).format_date} - {first_timing}) does not match with " f"the next data entry period ({Date(next_date).format_date} - {next_timing})")