def generate_header(self) -> List[Tuple[int, str, str, str]]: return [ ((Date.next_lock_in() - dt.timedelta(days=day)).day, "d-none d-lg-table-cell" if day > 2 else str(), (Date.next_lock_in() - dt.timedelta(days=day)).strftime("%a")[:2], "bg-warning text-dark" if Date.next_lock_in() - dt.timedelta(days=day) == Date.today() else str()) for day in range(self.PAST_DAYS, -1, -1) ]
def generate_hotel_status(self): hotels = Hotel.objects.filter_by(city=current_user.city).get() self.hotels = [(hotel.name, list()) for hotel in hotels] for index, hotel in enumerate(hotels): last_date = Date(hotel.last_date).date if last_date and (last_date < hotel.contract[0] or last_date > Date.next_lock_in()): last_date = None for day in range(self.PAST_DAYS, -1, -1): date = Date.next_lock_in() - dt.timedelta(days=day) if not last_date: self.add_status( index, day, self.NOT_DONE if hotel.is_contract_valid(date) else self.NA) continue if date < last_date: self.add_status( index, day, self.DONE if hotel.is_contract_valid(date) else self.NA) elif date > last_date: self.add_status( index, day, self.NOT_DONE if hotel.is_contract_valid(date) else self.NA) else: self.add_status( index, day, self.DONE if hotel.last_timing == Config.EVENING else self.PARTIAL) if current_user.hotel != hotel.name: continue end_date = min(Date.yesterday(), hotel.contract[1]) last_date = last_date or hotel.contract[0] if hotel.contract[0] > Date.today(): self.status = self.STATUS_NO_CONTRACT continue if last_date >= end_date: self.status = self.STATUS_ALL_DONE if last_date > end_date or hotel.last_timing == Config.EVENING \ else self.STATUS_PARTIAL continue days = (end_date - last_date).days self.status = (f"{days} days entry remaining", "list-group-item-danger") self.hotels.sort(key=itemgetter(0)) hotel = next( (hotel for hotel in self.hotels if hotel[0] == current_user.hotel)) if hotel: self.hotels.remove(hotel) self.hotels.insert(0, hotel) return
def get_data_entry_date(cls, hotel: Hotel) -> Tuple[Optional[dt.date], str]: start_date, end_date = hotel.contract today = Date.next_lock_in() data_entry_date = Date(hotel.last_date).date if end_date < start_date: return None, "Invalid Contract" if today < start_date: return None, "Cannot enter events for future contract" if not data_entry_date or data_entry_date < start_date: return start_date, Config.MORNING if today > end_date and data_entry_date > end_date: return end_date, str() if hotel.last_timing == Config.EVENING and (data_entry_date == end_date or data_entry_date == today): return data_entry_date, str() if hotel.last_timing == Config.MORNING and data_entry_date <= today: return data_entry_date, Config.EVENING if hotel.last_timing == Config.EVENING and data_entry_date < today: return data_entry_date + dt.timedelta(days=1), Config.MORNING return start_date, Config.MORNING
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