Esempio n. 1
0
def check_periods_input(periods):
    """Checks the validity of periods input"""
    errors = []

    for period in periods:

        period_id = period['travellerData']['filename'] \
                    if 'travellerData' in period and period['travellerData'] else 'New Period'
        error_prefix = '{0}:'.format(period_id)
        from_date = None
        to_date = None

        if 'from' not in period or not period['from']:
            errors.append('{0} From date is required'.format(error_prefix))
        else:
            from_date = val.check_date(errors, period['from'],
                                       '{0} From date'.format(error_prefix))

        if 'to' not in period or not period['to']:
            errors.append('{0} To date is required'.format(error_prefix))
        else:
            to_date = val.check_date(errors, period['to'],
                                     '{0} To date'.format(error_prefix))

        if from_date and to_date:
            if to_date < from_date:
                errors.append(
                    '{0} To date must be after From date'.format(error_prefix))

        if 'travellerData' not in period or not period['travellerData']:
            errors.append(
                '{0} please upload the traveller data'.format(error_prefix))

    if errors:
        raise InvalidUsage(errors)
Esempio n. 2
0
def check_user_input(data, adding):
    """Check the validity of input data"""
    errors = []

    if adding:
        if 'customerId' not in data or not data['customerId']:
            errors.append('Customer is required')

    if 'firstName' not in data or not data['firstName']:
        errors.append('First name is required')
    elif len(data['firstName']) > 50:
        errors.append(
            'First name should have less than or exactly 50 characters')

    if 'secondName' in data and len(data['secondName']) > 50:
        errors.append(
            'Second name should have less than or exactly 50 characters')

    if 'companyName' in data and len(data['companyName']) > 50:
        errors.append(
            'Company name should have less than or exactly 50 characters')

    if 'companyAddress' in data and len(data['companyAddress']) > 4000:
        errors.append(
            'Company address should have less than or exactly 4000 characters')

    if 'contractEndDate' in data and data['contractEndDate']:
        val.check_date(errors, data['contractEndDate'], 'Contract end date')

    if 'workEmail' not in data or not data['workEmail']:
        errors.append('Work e-mail is required')
    elif len(data['workEmail']) > 500:
        errors.append(
            'Work e-mail should have less than or exactly 50 characters')
    else:
        val.check_email(errors, data['workEmail'], 'Work e-mail')

    check_password(errors, data, adding)

    if 'active' not in data:
        errors.append('Active: missing attribute')

    if 'admin' not in data:
        errors.append('Admin: missing attribute')

    if errors:
        raise InvalidUsage(errors)
Esempio n. 3
0
    def edit_payment(self, _event=None):
        self.response['foreground'] = 'red'

        payment_type = self.payment_type.get()
        method = self.method.get().title()
        if not method:
            self.response['text'] = "Payment method is empty."
            return

        amount = self.amount.get()
        if not amount:
            self.response['text'] = "Amount paid is empty."
            return

        if not validation.is_float(amount):
            self.response['text'] = "Amount paid must be a monetary amount."
            return
        amount = f"{float(amount):.2f}"

        date = self.date.get()
        if not date:
            self.response['text'] = "Date is empty."
            return

        if not validation.check_date(date):
            self.response[
                'text'] = "Date input is invalid.\nMust be of form YYYY-MM-DD"
            return
        date = datetime.datetime.strptime(date,
                                          "%Y-%m-%d").strftime("%Y-%m-%d")

        time = self.time.get()
        if not time:
            self.response['text'] = "Time is empty."
            return

        if not validation.check_time(time):
            self.response[
                'text'] = "Time input is invalid.\nMust be of form HH:MM"
            return
        time = datetime.datetime.strptime(time, "%H:%M").strftime("%H:%M")

        description = self.description.get('1.0', tk.END)

        payee_id = self.payee[0].get().split(' ', 1)[0]
        record = (method, amount, date, time, description)
        SQL.payments.edit_payment(self.payment_id, payment_type, record,
                                  payee_id)

        self.response['text'] = ""
        self.master.show_details_frame()
        messagebox.showinfo(
            title="Successfully updated payment!",
            message="Payment record has been successfully updated!")
Esempio n. 4
0
def check_input(data):
    """Checks if the queries are valid"""
    errors = []

    if not 'categories' in data or len(data['categories']) > 1:
        return

    if 'fromDate' in data:
        if not data['fromDate']:
            errors.append('From date is required')
        else:
            data['fromDate'] = val.check_date(errors, data['fromDate'], 'From')
    if 'toDate' in data:
        if not data['toDate']:
            errors.append('To date is required')
        else:
            data['toDate'] = val.check_date(errors, data['toDate'], 'To')

    if errors:
        raise InvalidUsage(errors)
Esempio n. 5
0
def check_customer_input(data):
    """Check the validity of input data"""
    errors = []

    if 'name' not in data or not data['name']:
        errors.append('Name is required')
    elif len(data['name']) > 50:
        errors.append('Name should have less than or exactly 50 characters')

    if 'address' in data and len(data['address']) > 4000:
        errors.append(
            'Company address should have less than or exactly 4000 characters')

    if 'contractEndDate' in data and data['contractEndDate']:
        val.check_date(errors, data['contractEndDate'], 'Contract end date')

    if 'active' not in data:
        errors.append('Active: missing attribute')

    if errors:
        raise InvalidUsage(errors)
Esempio n. 6
0
def check_employee_arrangements(errors, employee_error_prefix, employee):
    """Checks all the employee arrangements"""
    if 'arrangements' in employee and isinstance(employee['arrangements'],
                                                 list):
        last_eff_date = None
        for idx, arrangement in enumerate(employee['arrangements']):
            error_prefix = "{0} - Arrangement #{1}".format(
                employee_error_prefix, idx + 1)
            empty_category = 'category' not in arrangement or not arrangement[
                'category']
            if empty_category:
                errors.append('{0}: Category is required'.format(error_prefix))
            eff_from = None
            empty_eff_from = 'effectiveFrom' not in arrangement or not arrangement[
                'effectiveFrom']
            if not empty_eff_from:
                eff_from = val.check_date(
                    errors, arrangement['effectiveFrom'],
                    '{0}: Effective From'.format(error_prefix))
            eff_to = None
            empty_eff_to = 'effectiveTo' not in arrangement or not arrangement[
                'effectiveTo']
            if not empty_eff_to:
                eff_to = val.check_date(
                    errors, arrangement['effectiveTo'],
                    '{0}: Effective To'.format(error_prefix))
            if eff_from and eff_to and eff_to < eff_from:
                errors.append(
                    '{0}: Effective To must be after Effective From'.format(
                        error_prefix))
            if last_eff_date:
                if eff_from and last_eff_date > eff_from:
                    errors.append(
                        '{0}: Effective From must be after previous arrangements'
                        .format(error_prefix))
                elif eff_to and last_eff_date > eff_to:
                    errors.append(
                        '{0}: Effective To must be after previous arrangements'
                        .format(error_prefix))
            last_eff_date = eff_to if eff_to else eff_from if eff_from else last_eff_date
Esempio n. 7
0
def check_home_country_clarifications(errors, employee_error_prefix, employee):
    """Checks all the employee home country clarifications"""
    if 'clarifications' in employee and isinstance(employee['clarifications'],
                                                   list):
        last_eff_date = None
        for idx, clar in enumerate(employee['clarifications']):
            empty_clarification = not clar['homeCountry'] and \
                                  not clar['fromDate'] and not clar['toDate']
            if empty_clarification:
                continue
            error_prefix = "{0} - Clarification #{1}".format(
                employee_error_prefix, idx + 1)
            empty_country = 'homeCountry' not in clar or not clar['homeCountry']
            if empty_country:
                errors.append(
                    '{0}: Home country is required'.format(error_prefix))
            eff_from = None
            empty_eff_from = 'fromDate' not in clar or not clar['fromDate']
            if not empty_eff_from:
                eff_from = val.check_date(
                    errors, clar['fromDate'],
                    '{0}: From Date'.format(error_prefix))
            eff_to = None
            empty_eff_to = 'toDate' not in clar or not clar['toDate']
            if not empty_eff_to:
                eff_to = val.check_date(errors, clar['toDate'],
                                        '{0}: To Date'.format(error_prefix))
            if eff_from and eff_to and eff_to < eff_from:
                errors.append('{0}: To Date must be after From Date'.format(
                    error_prefix))
            if last_eff_date:
                if eff_from and last_eff_date >= eff_from:
                    errors.append(
                        '{0}: From Date must be after previous clarifications'.
                        format(error_prefix))
                elif eff_to and last_eff_date >= eff_to:
                    errors.append(
                        '{0}: To Date must be after previous clarifications'.
                        format(error_prefix))
            last_eff_date = eff_to if eff_to else eff_from if eff_from else last_eff_date
Esempio n. 8
0
    def register_payment(self, _event=None):
        self.response['foreground'] = 'red'

        payment_type = self.payment_type
        if payment_type == "Select Payment Type":
            self.response['text'] = "Payment Type must be selected."
            return

        payee = self.payee[0].get().split(' ', 1)
        if payee[0] == "Select":
            self.response['text'] = "Payee must be selected."
            return

        method = self.method.get().title()
        if not method:
            self.response['text'] = "Payment method is empty."
            return

        amount = self.amount.get()
        if not amount:
            self.response['text'] = "Amount paid is empty."
            return

        if not validation.is_float(amount):
            self.response['text'] = "Amount paid must be a monetary amount."
            return
        amount = f"{float(amount):.2f}"

        date = self.date.get()
        if not date:
            self.response['text'] = "Date is empty."
            return

        if not validation.check_date(date):
            self.response[
                'text'] = "Date input is invalid.\nMust be of form YYYY-MM-DD"
            return
        date = datetime.datetime.strptime(date,
                                          "%Y-%m-%d").strftime("%Y-%m-%d")

        time = self.time.get()
        if not time:
            self.response['text'] = "Time is empty."
            return

        if not validation.check_time(time):
            self.response[
                'text'] = "Time input is invalid.\nMust be of form HH:MM"
            return
        time = datetime.datetime.strptime(time, "%H:%M").strftime("%H:%M")

        description = self.description.get('1.0', tk.END)
        record = (payment_type, method, amount, date, time, description)
        SQL.payments.add_payment(record, payee[0])

        # Clear entry fields after account creation
        self.clear_fields()

        self.response['text'] = ""
        self.master.show_details_frame()
        messagebox.showinfo(
            title="Successfully added payment!",
            message="Payment has been successfully added to the database.")
Esempio n. 9
0
def check_input(data):
    """Check the validity of input data"""
    errors = []

    if 'unclearHomeCountry' in data and isinstance(data['unclearHomeCountry'],
                                                   list):
        for idx, employee in enumerate(data['unclearHomeCountry']):
            traveller_name = employee['travellerName'] if employee[
                'travellerName'] else 'Unnamed'
            employee_id = employee['employeeId'] if employee[
                'employeeId'] else 'No ID'
            error_prefix = '{0} ({1})'.format(traveller_name, employee_id)
            check_home_country_clarifications(errors, error_prefix, employee)

    if 'incompleteTrips' in data and isinstance(data['incompleteTrips'], list):
        for idx, trip in enumerate(data['incompleteTrips']):
            error_prefix = 'Line #{0}: '.format(idx + 1)
            if trip['departureDate']:
                trip['departureDate'] = val.check_date(
                    errors, trip['departureDate'],
                    '{0}Departure date'.format(error_prefix))
            if trip['departureTime']:
                trip['departureTime'] = val.check_time(
                    errors, trip['departureTime'],
                    '{0}Departure time'.format(error_prefix))
            if trip['arrivalDate']:
                trip['arrivalDate'] = val.check_date(
                    errors, trip['arrivalDate'],
                    '{0}Arrival date'.format(error_prefix))
            if trip['arrivalTime']:
                trip['arrivalTime'] = val.check_time(
                    errors, trip['arrivalTime'],
                    '{0}Arrival time'.format(error_prefix))

    if 'inboundAssumptions' in data and isinstance(data['inboundAssumptions'],
                                                   list):
        for idx, trip in enumerate(data['inboundAssumptions']):
            error_prefix = 'Line #{0}: '.format(idx + 1)
            trip['toDate'] = val.check_date(errors, trip['toDate'],
                                            '{0}To date'.format(error_prefix))
            if trip['inboundAssumptionConfirmed'] and trip[
                    'inboundAssumptionConfirmed'] == 'N':
                if 'correctFromDate' not in trip or not trip['correctFromDate']:
                    errors.append('{0}Correct date is required for a "No" answer' \
                                  .format(error_prefix))
                else:
                    trip['correctFromDate'] = val.check_date(errors, trip['correctFromDate'],
                                                             '{0}Correct date' \
                                                             .format(error_prefix))
                    if trip['correctFromDate'] and trip['toDate'] \
                       and trip['correctFromDate'] > trip['toDate']:
                        errors.append('{0}Correct date must be equal or less than To date' \
                                      .format(error_prefix))

    if 'outboundAssumptions' in data and isinstance(
            data['outboundAssumptions'], list):
        for idx, trip in enumerate(data['outboundAssumptions']):
            error_prefix = 'Line #{0}: '.format(idx + 1)
            trip['fromDate'] = val.check_date(
                errors, trip['fromDate'], '{0}From date'.format(error_prefix))
            if trip['outboundAssumptionConfirmed'] and trip[
                    'outboundAssumptionConfirmed'] == 'N':
                if 'correctToDate' not in trip or not trip['correctToDate']:
                    errors.append('{0}Correct date is required for a "No" answer' \
                                  .format(error_prefix))
                else:
                    trip['correctToDate'] = val.check_date(errors, trip['correctToDate'],
                                                           '{0}Correct date' \
                                                           .format(error_prefix))
                    if trip['correctToDate'] and trip['fromDate'] \
                       and trip['correctToDate'] < trip['fromDate']:
                        errors.append('{0}Correct date must be equal or after From date' \
                                      .format(error_prefix))

    if 'unclearBorderCrossTime' in data and isinstance(
            data['unclearBorderCrossTime'], list):
        for trip in data['unclearBorderCrossTime']:
            employee_name = trip['travellerName'] if trip[
                'travellerName'] else 'Unnamed'
            employee_id = trip['employeeId'] if trip['employeeId'] else 'N/A'
            border_cross = val.check_date(errors, trip['borderCross'],
                                          'Border Cross Date')
            border_cross_fmtd = border_cross.strftime(
                "%d/%m/%y %H:%M") if border_cross else '?'
            error_prefix = '{0} ({1}) - {2} - {3}/{4}: '.format(
                employee_name, employee_id, border_cross_fmtd,
                trip['originCountry'], trip['destinationCountry'])
            if 'correctTime' in trip:
                trip['correctTime'] = val.check_time(
                    errors, trip['correctTime'],
                    '{0}Correct Time'.format(error_prefix))

    if errors:
        raise InvalidUsage(errors)
Esempio n. 10
0
def upload():
    """Receives a upload for processing"""
    user = security.authorize(request)

    if 'file' not in request.files:
        raise InvalidUsage('Missing file data')

    if 'id' not in request.form:
        raise InvalidUsage('Missing request id')
    upload_id = UUID(request.form['id'])
    sse_channel = 'upload-progress-{0}'.format(upload_id)

    from_date = None
    if 'from' in request.form:
        from_date = val.check_date([], request.form['from'], '')
        from_date = from_date.date() if from_date else None

    to_date = None
    if 'to' in request.form:
        to_date = val.check_date([], request.form['to'], '')
        to_date = to_date.date() if to_date else None

    uploaded_file = request.files['file']
    data = uploaded_file.read()

    sse.publish({'status': 'Storing a copy on our servers...'},
                channel=sse_channel)

    with BytesIO(data) as stream:
        upload_key = aws.s3upload(stream)

    sse.publish({
        'status': 'Processing traveller data...',
        'progress': 0
    },
                channel=sse_channel)

    countries = Country.query.all()
    country_aliases = CountryAlias.query.all()

    try:

        book = xlrd.open_workbook(file_contents=data)

        def generate_rows():
            """Process the spreadsheet generating rows"""
            if 'Traveller Data' not in book.sheet_names():
                raise InvalidUsage(
                    'No "Traveller Data" worksheet found in this workbook')
            sheet = book.sheet_by_name('Traveller Data')
            if sheet.ncols < 20:
                raise InvalidUsage('Invalid number of columns ' +
                                   'in the spreadsheet (expected: 20).')
            for row in range(1, sheet.nrows):
                travel = create_travel_record(sheet, row, countries,
                                              country_aliases)
                if travel:
                    yield travel

        rows = generate_rows()
        total_rows = sum([sheet.nrows - 1 for sheet in book.sheets()])

        traveller_data_id = uuid4()
        upload_date = datetime.now()
        traveller_data = dict(id=traveller_data_id,
                              customer_id=user.customer.id,
                              upload_date=upload_date,
                              upload_key=upload_key,
                              filename=uploaded_file.filename,
                              valid=False)

        db.session.execute(TravellerData.__table__.insert(), traveller_data)

        # count trips before or after the period if applicable
        trips_before_period = 0
        trips_after_period = 0

        travel_count = 0
        row_count = 0
        invalid_trips_count = 0
        error_count = 0
        travel_rows = []
        error_rows = []
        for row in rows:
            row_count += 1
            if row['errors'] and row['ticket_type'] != 'Refund':
                invalid_trips_count += 1
                error_count += len(row['errors'])
            row['id'] = uuid4()
            row['traveller_data_id'] = traveller_data_id
            travel_rows.append(row)
            for error in row['errors']:
                error_rows.append({
                    'travel_id': row['id'],
                    'error_code': error
                })
            if row['ticket_type'] != 'Refund':
                travel_count += 1
                if from_date:
                    if row['departure_date'] and row[
                            'departure_date'] < from_date:
                        trips_before_period += 1
                    elif row['arrival_date'] and row[
                            'arrival_date'] < from_date:
                        trips_before_period += 1
                if to_date:
                    if row['departure_date'] and row[
                            'departure_date'] > to_date:
                        trips_after_period += 1
                    elif row['arrival_date'] and row['arrival_date'] > to_date:
                        trips_after_period += 1
            if len(travel_rows) >= 1000:
                progress_status = 'Processing traveller data ' + \
                                  '({0} rows processed)...'.format(row_count)
                sse.publish(
                    {
                        'status': progress_status,
                        'progress': row_count / total_rows * 100
                    },
                    channel=sse_channel)
                db.session.execute(Travel.__table__.insert(), travel_rows)
                travel_rows.clear()
                if error_rows:
                    db.session.execute(TravellerDataError.__table__.insert(),
                                       error_rows)
                    error_rows.clear()

        if travel_rows:
            db.session.execute(Travel.__table__.insert(), travel_rows)
        if error_rows:
            db.session.execute(TravellerDataError.__table__.insert(),
                               error_rows)

        if error_count > 0:
            query = TravellerData.__table__.update().where(
                TravellerData.id == traveller_data_id)
            db.session.execute(query, {'valid': False})

        sse.publish({'status': 'Done!', 'progress': 100}, channel=sse_channel)

        db.session.commit()

    except xlrd.XLRDError:
        raise InvalidUsage(
            'Unsupported spreadsheet. Please check the uploaded file.')

    return jsonify({
        "entryCount":
        travel_count,
        "id":
        traveller_data_id,
        "filename":
        uploaded_file.filename,
        "dateUploaded":
        upload_date.isoformat(),
        "errorCount":
        error_count,
        "tripsBeforePeriod":
        trips_before_period,
        "tripsAfterPeriod":
        trips_after_period,
        "invalidCount":
        invalid_trips_count,
        "outsidePeriodCount":
        trips_before_period + trips_after_period,
    })