Skip to content

Instantly share code, notes, and snippets.

@kaligrafy
Created February 13, 2024 19:49
Show Gist options
  • Save kaligrafy/fd482247bdd77897220e72d323eb5475 to your computer and use it in GitHub Desktop.
Save kaligrafy/fd482247bdd77897220e72d323eb5475 to your computer and use it in GitHub Desktop.
od_mtl_2023 Person class
import moment from 'moment-business-days';
import _cloneDeep from 'lodash/cloneDeep';
import {
BasePerson,
BasePersonAttributes,
ExtendedPersonAttributes
} from 'evolution-common/lib/services/baseObjects/BasePerson';
import { parseDate } from 'evolution-common/lib/utils/DateUtils';
import { BasePlaceAttributes } from 'evolution-common/lib/services/baseObjects/BasePlace';
import { BaseTripAttributes } from 'evolution-common/lib/services/baseObjects/BaseTrip';
import { BaseVisitedPlaceAttributes } from 'evolution-common/lib/services/baseObjects/BaseVisitedPlace';
import * as PAttr from './attributeTypes/PersonAttributes';
import * as GAttr from './attributeTypes/GeneralAttributes';
import { BasePlace, ExtendedPlaceAttributes } from 'evolution-common/lib/services/baseObjects/BasePlace';
import { BaseAddressAttributes } from 'evolution-common/lib/services/baseObjects/BaseAddress';
import { VisitedPlace, VisitedPlaceAttributes } from './VisitedPlace';
import { Trip, TripAttributes } from './Trip';
import { convertNullToUndefined, convertStringsToNumbers } from './utils/Utils';
import ParamsValidatorTools from './utils/ParamsValidatorTools';
import parser from '../parsers/person.parser';
import config from 'chaire-lib-common/lib/config/shared/project.config';
const displayName = 'Person';
type PersonAttributes = {
_completedSections?: PAttr.CompletedSection;
_sequence?: number;
_color?: string; // hex color for map
_isProxy?: boolean; // for export, use isProxy method to calculate
ageIsApproximate?: boolean; // od_mtl_2023 | Priority audit: 1 √
departurePlaceIsHome?: GAttr.YesNoDontKnow; // all | Priority audit: 1 √
departurePlaceIsHomeConfirm?: GAttr.YesNoDontKnow; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 1 √
departurePlaceOther?: PAttr.DeparturePlaceOther; // od_mtl_2023, od_mtl_ete_2023, od_qc_2023 | Priority audit: 1 √
departurePlaceType?: PAttr.DeparturePlaceType; // od_mtl_pilote_2021 | Priority audit: 1 √
didTripsOnTripsDate?: GAttr.YesNoDontKnow; // od_mtl_pilote_2021 | Priority audit: 1 √ // moved to personDidTrips in constructor
drivingLicenseOwner?: GAttr.YesNoDontKnow; // all | Priority audit: 1 √
transitPassOwner?: GAttr.YesNoDontKnow; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 1 √
// Before 2023-10-18: bixiBikesharingUsage: (choices: 'seasonal', 'monthly', 'noSubscription', 'subscriptionWithPay'):
bixiBikesharingUsage?: PAttr.BixiBikesharingUsage; // all except od_qc_2023, od_mtl_2023: only part of the sample | Priority audit: 2 √
// After 2023-10-18: bixiBikesharingUsage_NewOptions2023-10-18 (choices: 'monthlySeasonalAnnual', 'payPerTrip'):
['bixiBikesharingUsage_NewOptions2023-10-18']?: PAttr.BixiBikesharingUsageV2; // od_mtl_2023: only part of the sample | Priority audit: 2 √
bixiBikesharingUsageV2?: PAttr.BixiBikesharingUsageV2; // added by parser, not in original questionnaire | Priority audit: 2 √
bikeOwnership?: GAttr.YesNoDontKnow; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
canRemoteWork?: PAttr.CanRemoteWork; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 2 √
communautoFlexCarsharingUsage?: PAttr.CommunautoFlexCarSharingUsage; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
daysAtOfficePerWeek?: PAttr.DaysAtOfficePerWeek; // source: number, but convert into string using choice labels; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 2
disabilities?: PAttr.Disability[]; // all except od_qc_2023 | Priority audit: 3 >
disabilitiesComments?: string; // all except od_qc_2023 | Priority audit: 0 √
//doesNotStudiesFromFixedLocationReason?: PAttr.DoesNotStudyFromFixedLocationReason; // od_mtl_ete_2023, change into doesNotStudyFromFixedLocationReason in create
doesNotStudyFromFixedLocationReason?: PAttr.DoesNotStudyFromFixedLocationReason; // od_mtl_2023 | Priority audit: 3 √
educationalAttainment?: PAttr.EducationalAttainment; // override default values of basePerson | Priority audit: 2
electricBikeOwnership?: GAttr.YesNoDontKnow; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
enrolledInSchool?: PAttr.EnrolledInSchool; // all | Priority audit: 1 √
everUsedBixiBikesharingServices?: GAttr.YesNoDontKnowNonApplicable; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
everUsedCommunautoFlexCarsharingServicesAsADriver?: GAttr.YesNoDontKnow; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
freeParkingAtSchool?: PAttr.FreeParking; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 2 √
freeParkingAtWork?: PAttr.FreeParking; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 2 √
genderCustom?: string; // od_mtl_pilote_2021 | Priority audit: 3 √
genderSpecify?: string; // all except od_qc_2023 | Priority audit: 3 √
hasDisability?: GAttr.YesNoPreferNotToAnswer; // all | Priority audit: 1 √
hasOmittedActiveModesTrips?: boolean; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 1 √
hasUsualSchoolPlace?: boolean; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 1 √
hasUsualWorkPlace?: boolean; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 1 √
job?: string; // all except od_qc_2023 | Priority audit: 3 √
jobActivitySector?: PAttr.JobActivitySector; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 3 √
jobCategory?: PAttr.JobCategory; // override default values of basePerson | Priority audit: 3 √
jobCompatibleWithTelecommuting?: PAttr.JobCompatibleWithTelecommuting; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
jobHoursFlexibility?: PAttr.JobHoursFlexibility; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
jobHoursSchedulesType?: PAttr.JobHoursSchedulesType; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
jobType?: PAttr.JobType; // all except od_qc_2023 | Priority audit: 1 √
mobilityAssistiveDevices?: PAttr.MobilityAssistiveDevice[]; // all except od_qc_2023 | Priority audit: 3 √
mobilityAssistiveDevicesSpecify?: string; // all except od_qc_2023 | Priority audit: 3 √
mostUsedMobilityAssistiveDevice?: PAttr.MobilityAssistiveDevice; // all except od_qc_2023 | Priority audit: 3 √
// ignore nickname altogether
noSchoolTripReasonV1?: PAttr.NoSchoolTripReasonV1; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1) | Priority audit: 2 √
noSchoolTripReasonV2?: PAttr.NoSchoolTripReasonV2; // od_mtl_2023 (v2), od_qc_2023 (v2) | Priority audit: 2 √
noSchoolTripReasonSpecify?: string; // od_mtl_pilote_2021, od_mtl_pilote_2022, od_mtl_2023, od_qc_2023 | Priority audit: 3 √
noUsualSchoolPlaceReason?: PAttr.NoUsualSchoolPlaceReason; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
noWorkOrStudyTripReason?: PAttr.NoWorkOrStudyTripReason; // od_mtl_ete_2023 | Priority audit: 2 √
noWorkTripReasonV1?: PAttr.NoSchoolTripReasonV1; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1) | Priority audit: 2 √
noWorkTripReasonV2?: PAttr.NoSchoolTripReasonV2; // od_mtl_2023 (v2), od_qc_2023 (v2) | Priority audit: 2 √
noWorkTripReasonSpecify?: string; // od_mtl_pilote_2021, od_mtl_pilote_2022, od_mtl_2023, od_qc_2023 | Priority audit: 2 √
occupationQC?: PAttr.OccupationQC; // od_qc_2023 | Priority audit: 1
occupationV1?: PAttr.OccupationV1; // od_mtl_pilote_2021 | Priority audit: 1
occupationV2?: PAttr.OccupationV2; // od_mtl_pilote_2022 | Priority audit: 1
occupationV3?: PAttr.OccupationV3; // od_mtl_ete_2023, od_mtl_2023 | Priority audit: 1
occupationSpecify?: string; // all | Priority audit: 3 √
parentConsent?: PAttr.ParentConsent; // od_qc_2023 | Priority audit: 1 √
consentConfirm?: boolean; // od_qc_2023 (only true is posible) | Priority audit: 1 √
personDidTrips?: GAttr.YesNoDontKnow; // all | Priority audit: 1 √
personDidTripsChangeConfirm?: GAttr.YesNo; // all | Priority audit: 1 √
previousWeekDidTripsDays?: Date[] | string[]; // od_mtl_pilote_2021 | Priority audit: 2 √
previousWeekNoWorkingDaysReasons?: PAttr.PreviousWeekNoWorkingDaysReason[]; // od_mtl_pilote_2021 | Priority audit: 2 √
previousWeekWentToSchoolOutsideHomeDays?: Date[] | string[]; // od_mtl_pilote_2021 | Priority audit: 2 √
previousWeekWentToWorkOutsideHomeDays?: Date[] | string[]; // od_mtl_pilote_2021 | Priority audit: 2 √
previousWeekWorkingDays?: Date[] | string[]; // od_mtl_pilote_2021 | Priority audit: 2 √
// refuseAge?: string; // od_qc_2023 (only yes or undefined values possible): ignore, implicit if ageGroup is set
remoteStudyDays?: PAttr.WeekDaysNoPreferNotToAnswer[]; // od_qc_2023 | Priority audit: 2 √
remoteWorkDays?: PAttr.WeekDaysNoPreferNotToAnswer[]; // od_qc_2023 | Priority audit: 2 √
schoolType?: PAttr.SchoolType; // od_qc_2023 | Priority audit: 1 √
shortTripSectionDidSchoolTripsOnTripsDate?: GAttr.YesNoDontKnow; // od_mtl_pilote_2022 | Priority audit: 2 √
shortTripSectionDidTripsOnTripsDate?: GAttr.YesNoDontKnow; // od_mtl_pilote_2022 | Priority audit: 2 √
shortTripSectionDidTripsToUsualSchoolPlaceOnTripsDate?: GAttr.YesNoDontKnow; // od_mtl_pilote_2022 | Priority audit: 2 √
shortTripSectionDidTripsToUsualWorkPlaceOnTripsDate?: GAttr.YesNoDontKnow; // od_mtl_pilote_2022 | Priority audit: 2 √
shortTripSectionDidWorkTripsOnTripsDate?: GAttr.YesNoDontKnow; // od_mtl_pilote_2022 | Priority audit: 2 √
studentType?: PAttr.StudentType; // all except od_qc_2023 | Priority audit: 1 √
studiesFromFixedLocation?: GAttr.YesNoDontKnow; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 1 √
transitPassTypes?: PAttr.TransitPassType[]; // od_qc_2023 -> move from transitFares in od_qc_2023 only | Priority audit: 2 √
transitFaresUsed?: PAttr.TransitFareUsed[]; // od_mtl_2023, od_mtl_ete_2023 -> move from transitFares in od_mtl_ete_2023 | Priority audit: 2 √
transitPassesV1?: PAttr.TransitPassMtlV1[]; // od_mtl_pilote_2021 | Priority audit: 2 √
transitPassesV2?: PAttr.TransitPassMtlV2[]; // od_mtl_pilote_2022, od_mtl_ete_2023, od_mtl_2023 | Priority audit: 2 √
transitPassesQC?: PAttr.TransitPassQC[]; // od_qc_2023 | Priority audit: 2 √
transitPassSpecify?: string; // od_mtl_pilote_2022, od_mtl_2023, od_mtl_ete_2023 | Priority audit: 3 √
travelToStudyDays?: PAttr.WeekDaysNoPreferNotToAnswer[]; // od_qc_2023 | Priority audit: 2 √
travelToWorkDays?: PAttr.WeekDaysNoPreferNotToAnswer[]; // od_qc_2023 | Priority audit: 2 √
useBikeForUtilitarianTravel?: GAttr.YesNoDontKnow; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
usedBixiBikesharingServicesInLast30Days?: GAttr.YesNoDontKnow; // od_mtl_2023 | Priority audit: 2 √
usedBixiBikesharingServicesInLast6Months?: GAttr.YesNoDontKnow; // od_mtl_ete_2023 | Priority audit: 2 √
usedCommunautoCarsharingServicesAsADriverInLast6Months?: GAttr.YesNoDontKnow; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 2 √
usedTransitInLast30Days?: GAttr.YesNoDontKnow; // audited, od_mtl_2023, od_mtl_ete_2023 | Priority audit: 2 √
useParatransit?: GAttr.YesNoDontKnowPreferNotToAnswer; // od_mtl_pilote_2022: YesNoDontKnow, od_mtl_ete_2023: YesNoDontKnow but dontKnow was labeled preferNotToAnswer, od_mtl_2023: YesNoPreferNotToAnswer | Priority audit: 2 √
usualSchoolPlaceParkingType?: PAttr.UsualPlaceParkingType; // od_mtl_pilote_2021?, od_mtl_pilote_2022 | Priority audit: 2 √
usualWorkPlaceIsHome?: boolean; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 1 √
usualWorkPlaceParkingType?: PAttr.UsualPlaceParkingType; // od_mtl_pilote_2021?, od_mtl_pilote_2022 | Priority audit: 2 √
usualWorkPlaceUsageAtLeastOnceAWeek?: PAttr.UsualWorkPlaceUsageAtLeastOnceAWeek; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
usualWorkPlaceWasHomeBeforeThePandemic?: PAttr.UsualWorkPlaceWasHomeBeforeThePandemic; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
whoAnsweredForThisPerson?: string; // uuid of the person who answered. od_mtl_pilote_2021 | Priority audit: 1 √
whoWillAnswerForThisPerson?: string; // uuid of the person who will answer. all surveys | Priority audit: 1 √
workerAndStudentType?: PAttr.WorkerAndStudentType; // od_mtl_pilote_2021 | Priority audit: 2 √
workingPlace?: PAttr.WorkingPlace; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 1 √
workOnTheRoad?: boolean; // all except od_qc_2023 | Priority audit: 1 √
worksFromFixedLocation?: boolean; // od_mtl_2023, od_mtl_ete_2023 | Priority audit: 1 √
workTripsDaysCountPerWeek?: PAttr.WorkTripsDaysCountPerWeek; // od_mtl_pilote_2021, od_mtl_pilote_2022 | Priority audit: 2 √
workType?: PAttr.WorkType; // od_qc_2023 | Priority audit: 1 √
// generated from flattened attributes:
modeFrequencies?: PAttr.FrequencyByTripTypeAndModeV1AndV2; // generated from multiple input | Priority audit: 2 √
} & ExtendedPersonAttributes;
class Person {
workPlaces?: BasePlace[];
schoolPlaces?: BasePlace[];
basePerson: BasePerson;
visitedPlaces?: VisitedPlace[];
trips?: Trip[];
_completedSections?: PAttr.CompletedSection;
_sequence?: number;
_color?: string;
_isProxy?: boolean;
ageIsApproximate?: boolean;
bixiBikesharingUsage?: PAttr.BixiBikesharingUsage;
['bixiBikesharingUsage_NewOptions2023-10-18']?: PAttr.BixiBikesharingUsageV2; // deleted by parser
bixiBikesharingUsageV2?: PAttr.BixiBikesharingUsageV2;
bikeOwnership?: GAttr.YesNoDontKnow;
drivingLicenseOwner?: GAttr.YesNoDontKnow; // move to basePerson drivingLicenseOwnership
transitPassOwner?: GAttr.YesNoDontKnow; // move to basePerson transitPassOwnership
communautoFlexCarsharingUsage?: PAttr.CommunautoFlexCarSharingUsage;
canRemoteWork?: PAttr.CanRemoteWork;
daysAtOfficePerWeek?: PAttr.DaysAtOfficePerWeek;
departurePlaceIsHome?: GAttr.YesNoDontKnow;
departurePlaceIsHomeConfirm?: GAttr.YesNoDontKnow;
departurePlaceOther?: PAttr.DeparturePlaceOther;
departurePlaceType?: PAttr.DeparturePlaceType; // od_qc_2023 only
didTripsOnTripsDate?: GAttr.YesNoDontKnow; // show in validation dashboard
disabilities?: PAttr.Disability[];
disabilitiesComments?: string;
doesNotStudyFromFixedLocationReason?: PAttr.DoesNotStudyFromFixedLocationReason;
educationalAttainment?: PAttr.EducationalAttainment;
electricBikeOwnership?: GAttr.YesNoDontKnow;
enrolledInSchool?: PAttr.EnrolledInSchool; // show in validation dashboard
everUsedBixiBikesharingServices?: GAttr.YesNoDontKnowNonApplicable;
everUsedCommunautoFlexCarsharingServicesAsADriver?: GAttr.YesNoDontKnow;
freeParkingAtSchool?: PAttr.FreeParking;
freeParkingAtWork?: PAttr.FreeParking;
genderCustom?: string;
genderSpecify?: string;
hasDisability?: GAttr.YesNoPreferNotToAnswer; // show in validation dashboard
hasOmittedActiveModesTrips?: boolean; // show in validation dashboard
hasUsualSchoolPlace?: boolean; // show in validation dashboard
hasUsualWorkPlace?: boolean; // show in validation dashboard
job?: string;
jobActivitySector?: PAttr.JobActivitySector;
jobCategory?: PAttr.JobCategory; // override default values of basePerson
jobCompatibleWithTelecommuting?: PAttr.JobCompatibleWithTelecommuting;
jobHoursFlexibility?: PAttr.JobHoursFlexibility;
jobHoursSchedulesType?: PAttr.JobHoursSchedulesType;
jobType?: PAttr.JobType;
mobilityAssistiveDevices?: PAttr.MobilityAssistiveDevice[];
mobilityAssistiveDevicesSpecify?: string;
mostUsedMobilityAssistiveDevice?: PAttr.MobilityAssistiveDevice;
// ignore nickname altogether
noSchoolTripReasonV1?: PAttr.NoSchoolTripReasonV1;
noSchoolTripReasonV2?: PAttr.NoSchoolTripReasonV2;
noSchoolTripReasonSpecify?: string;
noUsualSchoolPlaceReason?: PAttr.NoUsualSchoolPlaceReason;
noWorkOrStudyTripReason?: PAttr.NoWorkOrStudyTripReason;
noWorkTripReasonV1?: PAttr.NoWorkTripReasonV1;
noWorkTripReasonV2?: PAttr.NoWorkTripReasonV2;
noWorkTripReasonSpecify?: string;
occupationQC?: PAttr.OccupationQC; // show in validation dashboard
occupationV1?: PAttr.OccupationV1; // show in validation dashboard
occupationV2?: PAttr.OccupationV2; // show in validation dashboard
occupationV3?: PAttr.OccupationV3; // show in validation dashboard
occupationSpecify?: string; // show in validation dashboard
parentConsent?: PAttr.ParentConsent; // show in validation dashboard
consentConfirm?: boolean; // show in validation dashboard
personDidTrips?: GAttr.YesNoDontKnow; // show in validation dashboard
personDidTripsChangeConfirm?: GAttr.YesNo;
previousWeekDidTripsDays?: Date[];
previousWeekNoWorkingDaysReasons?: PAttr.PreviousWeekNoWorkingDaysReason[];
previousWeekWentToSchoolOutsideHomeDays?: Date[];
previousWeekWentToWorkOutsideHomeDays?: Date[];
previousWeekWorkingDays?: Date[];
// refuseAge?: string; // ignore, implicit if ageGroup is set
remoteStudyDays?: PAttr.WeekDaysNoPreferNotToAnswer[];
remoteWorkDays?: PAttr.WeekDaysNoPreferNotToAnswer[];
schoolType?: PAttr.SchoolType; // show in validation dashboard
shortTripSectionDidSchoolTripsOnTripsDate?: GAttr.YesNoDontKnow;
shortTripSectionDidTripsOnTripsDate?: GAttr.YesNoDontKnow;
shortTripSectionDidTripsToUsualSchoolPlaceOnTripsDate?: GAttr.YesNoDontKnow;
shortTripSectionDidTripsToUsualWorkPlaceOnTripsDate?: GAttr.YesNoDontKnow;
shortTripSectionDidWorkTripsOnTripsDate?: GAttr.YesNoDontKnow;
studentType?: PAttr.StudentType; // show in validation dashboard
studiesFromFixedLocation?: GAttr.YesNoDontKnow; // show in validation dashboard
transitPassTypes?: PAttr.TransitPassType[];
transitFaresUsed?: PAttr.TransitFareUsed[];
transitPassesV1?: PAttr.TransitPassMtlV1[];
transitPassesV2?: PAttr.TransitPassMtlV2[];
transitPassesQC?: PAttr.TransitPassQC[];
transitPassSpecify?: string;
travelToStudyDays?: PAttr.WeekDaysNoPreferNotToAnswer[];
travelToWorkDays?: PAttr.WeekDaysNoPreferNotToAnswer[];
useBikeForUtilitarianTravel?: GAttr.YesNoDontKnow;
usedBixiBikesharingServicesInLast30Days?: GAttr.YesNoDontKnow;
usedBixiBikesharingServicesInLast6Months?: GAttr.YesNoDontKnow;
usedCommunautoCarsharingServicesAsADriverInLast6Months?: GAttr.YesNoDontKnow;
usedTransitInLast30Days?: GAttr.YesNoDontKnow;
useParatransit?: GAttr.YesNoDontKnowPreferNotToAnswer;
usualSchoolPlaceParkingType?: PAttr.UsualPlaceParkingType;
usualWorkPlaceIsHome?: boolean; // show in validation dashboard
usualWorkPlaceParkingType?: PAttr.UsualPlaceParkingType;
usualWorkPlaceUsageAtLeastOnceAWeek?: PAttr.UsualWorkPlaceUsageAtLeastOnceAWeek;
usualWorkPlaceWasHomeBeforeThePandemic?: PAttr.UsualWorkPlaceWasHomeBeforeThePandemic;
whoAnsweredForThisPerson?: string; // show in validation dashboard
whoWillAnswerForThisPerson?: string; // show in validation dashboard
workerAndStudentType?: PAttr.WorkerAndStudentType; // show in validation dashboard
workingPlace?: PAttr.WorkingPlace;
workOnTheRoad?: boolean; // show in validation dashboard
worksFromFixedLocation?: boolean; // show in validation dashboard
workTripsDaysCountPerWeek?: PAttr.WorkTripsDaysCountPerWeek;
workType?: PAttr.WorkType; // show in validation dashboard
// generated from flattened attributes:
modeFrequencies?: PAttr.FrequencyByTripTypeAndModeV1AndV2;
// do not export these:
static _confidentialAttributes: string[] = [
'nickname', // replace by P1, P2, P3... in interview summary (validation), but not in the questionnaire validation itself
'disabilitiesComments', // show in validation though
'genderSpecify',
'genderCustom'
];
constructor(
params: {
basePerson: BasePerson;
visitedPlaces?: VisitedPlace[];
trips?: Trip[];
workPlaces?: BasePlace[];
schoolPlaces?: BasePlace[];
} & PersonAttributes
) {
this.basePerson = params.basePerson;
this.visitedPlaces = params.visitedPlaces || [];
this.trips = params.trips || [];
this.workPlaces = params.workPlaces || [];
this.schoolPlaces = params.schoolPlaces || [];
this._completedSections = params._completedSections;
this._sequence = params._sequence;
this._color = params._color;
this.ageIsApproximate = params.ageIsApproximate;
this.bixiBikesharingUsage = params.bixiBikesharingUsage;
this['bixiBikesharingUsage_NewOptions2023-10-18'] = params['bixiBikesharingUsage_NewOptions2023-10-18'];
this.bixiBikesharingUsageV2 = params.bixiBikesharingUsageV2;
this.bikeOwnership = params.bikeOwnership;
this.drivingLicenseOwner = params.drivingLicenseOwner;
this.transitPassOwner = params.transitPassOwner;
this.communautoFlexCarsharingUsage = params.communautoFlexCarsharingUsage;
this.canRemoteWork = params.canRemoteWork;
this.daysAtOfficePerWeek = params.daysAtOfficePerWeek;
this.departurePlaceIsHome = params.departurePlaceIsHome;
this.departurePlaceIsHomeConfirm = params.departurePlaceIsHomeConfirm;
this.departurePlaceOther = params.departurePlaceOther;
this.departurePlaceType = params.departurePlaceType;
this.doesNotStudyFromFixedLocationReason = params.doesNotStudyFromFixedLocationReason;
this.didTripsOnTripsDate = params.didTripsOnTripsDate;
this.disabilities = params.disabilities;
this.disabilitiesComments = params.disabilitiesComments;
this.educationalAttainment = params.educationalAttainment;
this.electricBikeOwnership = params.electricBikeOwnership;
this.enrolledInSchool = params.enrolledInSchool;
this.everUsedBixiBikesharingServices = params.everUsedBixiBikesharingServices;
this.everUsedCommunautoFlexCarsharingServicesAsADriver =
params.everUsedCommunautoFlexCarsharingServicesAsADriver;
this.freeParkingAtSchool = params.freeParkingAtSchool;
this.freeParkingAtWork = params.freeParkingAtWork;
this.genderCustom = params.genderCustom;
this.genderSpecify = params.genderSpecify;
this.hasDisability = params.hasDisability;
this.hasOmittedActiveModesTrips = params.hasOmittedActiveModesTrips;
this.hasUsualSchoolPlace = params.hasUsualSchoolPlace;
this.hasUsualWorkPlace = params.hasUsualWorkPlace;
this.job = params.job;
this.jobActivitySector = params.jobActivitySector;
this.jobCategory = params.jobCategory;
this.jobCompatibleWithTelecommuting = params.jobCompatibleWithTelecommuting;
this.jobHoursFlexibility = params.jobHoursFlexibility;
this.jobHoursSchedulesType = params.jobHoursSchedulesType;
this.jobType = params.jobType;
this.mobilityAssistiveDevices = params.mobilityAssistiveDevices;
this.mobilityAssistiveDevicesSpecify = params.mobilityAssistiveDevicesSpecify;
this.mostUsedMobilityAssistiveDevice = params.mostUsedMobilityAssistiveDevice;
// ignore nickname altogether
this.noSchoolTripReasonV1 = params.noSchoolTripReasonV1;
this.noSchoolTripReasonV2 = params.noSchoolTripReasonV2;
this.noSchoolTripReasonSpecify = params.noSchoolTripReasonSpecify;
this.noUsualSchoolPlaceReason = params.noUsualSchoolPlaceReason;
this.noWorkOrStudyTripReason = params.noWorkOrStudyTripReason;
this.noWorkTripReasonV1 = params.noWorkTripReasonV1;
this.noWorkTripReasonV2 = params.noWorkTripReasonV2;
this.noWorkTripReasonSpecify = params.noWorkTripReasonSpecify;
this.occupationQC = params.occupationQC;
this.occupationV1 = params.occupationV1;
this.occupationV2 = params.occupationV2;
this.occupationV3 = params.occupationV3;
this.occupationSpecify = params.occupationSpecify;
this.parentConsent = params.parentConsent;
this.consentConfirm = params.consentConfirm;
this.personDidTrips = params.personDidTrips;
this.personDidTripsChangeConfirm = params.personDidTripsChangeConfirm;
this.previousWeekDidTripsDays =
params.previousWeekDidTripsDays !== undefined
? params.previousWeekDidTripsDays.map((date) => parseDate(date))
: undefined;
this.previousWeekNoWorkingDaysReasons = params.previousWeekNoWorkingDaysReasons;
this.previousWeekWentToSchoolOutsideHomeDays =
params.previousWeekWentToSchoolOutsideHomeDays !== undefined
? params.previousWeekWentToSchoolOutsideHomeDays.map((date) => parseDate(date))
: undefined;
this.previousWeekWentToWorkOutsideHomeDays =
params.previousWeekWentToWorkOutsideHomeDays !== undefined
? params.previousWeekWentToWorkOutsideHomeDays.map((date) => parseDate(date))
: undefined;
this.previousWeekWorkingDays =
params.previousWeekWorkingDays !== undefined
? params.previousWeekWorkingDays.map((date) => parseDate(date))
: undefined;
//this.refuseAge = params.refuseAge; // ignore, implicit if ageGroup is set
this.remoteStudyDays = params.remoteStudyDays;
this.remoteWorkDays = params.remoteWorkDays;
this.schoolType = params.schoolType;
this.shortTripSectionDidSchoolTripsOnTripsDate = params.shortTripSectionDidSchoolTripsOnTripsDate;
this.shortTripSectionDidTripsOnTripsDate = params.shortTripSectionDidTripOnTripsDate;
this.shortTripSectionDidTripsToUsualSchoolPlaceOnTripsDate =
params.shortTripSectionDidTripToUsualSchoolPlaceOnTripsDate;
this.shortTripSectionDidTripsToUsualWorkPlaceOnTripsDate =
params.shortTripSectionDidTripToUsualWorkPlaceOnTripsDate;
this.shortTripSectionDidWorkTripsOnTripsDate = params.shortTripSectionDidWorkTripsOnTripsDate;
this.studentType = params.studentType;
this.studiesFromFixedLocation = params.studiesFromFixedLocation;
this.transitPassTypes = params.transitPassTypes;
this.transitFaresUsed = params.transitFaresUsed;
this.transitPassesV1 = params.transitPassesV1;
this.transitPassesV2 = params.transitPassesV2;
this.transitPassesQC = params.transitPassesQC;
this.transitPassSpecify = params.transitPassSpecify;
this.travelToStudyDays = params.travelToStudyDays;
this.travelToWorkDays = params.travelToWorkDays;
this.useBikeForUtilitarianTravel = params.useBikeForUtilitarianTravel;
this.usedBixiBikesharingServicesInLast30Days = params.usedBixiBikesharingServicesInLast30Days;
this.usedBixiBikesharingServicesInLast6Months = params.usedBixiBikesharingServicesInLast6Months;
this.usedCommunautoCarsharingServicesAsADriverInLast6Months =
params.usedCommunautoCarsharingServicesAsADriverInLast6Months;
this.usedTransitInLast30Days = params.usedTransitInLast30Days;
this.useParatransit = params.useParatransit;
this.usualSchoolPlaceParkingType = params.usualSchoolPlaceParkingType;
this.usualWorkPlaceIsHome = params.usualWorkPlaceIsHome;
this.usualWorkPlaceParkingType = params.usualWorkPlaceParkingType;
this.usualWorkPlaceUsageAtLeastOnceAWeek = params.usualWorkPlaceUsageAtLeastOnceAWeek;
this.usualWorkPlaceWasHomeBeforeThePandemic = params.usualWorkPlaceWasHomeBeforeThePandemic;
this.whoAnsweredForThisPerson = params.whoAnsweredForThisPerson;
this.whoWillAnswerForThisPerson = params.whoWillAnswerForThisPerson;
this.workerAndStudentType = params.workerAndStudentType;
this.workingPlace = params.workingPlace;
this.workOnTheRoad = params.workOnTheRoad;
this.worksFromFixedLocation = params.worksFromFixedLocation;
this.workTripsDaysCountPerWeek = params.workTripsDaysCountPerWeek;
this.workType = params.workType;
this._isProxy = this.isProxy();
// generated from flattened attributes:
this.modeFrequencies = params.modeFrequencies;
}
// will not check for error, data must be sanitized before
static unserialize(
attributes: PersonAttributes & {
trips?: (TripAttributes & { baseTrip: BaseTripAttributes })[];
visitedPlaces?: (VisitedPlaceAttributes & {
baseVisitedPlace: BaseVisitedPlaceAttributes & {
basePlace: BasePlaceAttributes & { address?: BaseAddressAttributes };
};
})[];
workPlaces?: (BasePlaceAttributes & { address?: BaseAddressAttributes })[];
schoolPlaces?: (BasePlaceAttributes & { address?: BaseAddressAttributes })[];
basePerson: BasePersonAttributes;
}
): Person {
const serializedTrips = attributes.trips || [];
const trips = [];
for (let i = 0, count = serializedTrips.length; i < count; i++) {
trips.push(Trip.unserialize(serializedTrips[i]));
}
const serializedVisitedPlaces = attributes.visitedPlaces || [];
const visitedPlaces = [];
for (let i = 0, count = serializedVisitedPlaces.length; i < count; i++) {
visitedPlaces.push(VisitedPlace.unserialize(serializedVisitedPlaces[i]));
}
const serializedWorkPlaces = attributes.workPlaces || [];
const workPlaces = [];
for (let i = 0, count = serializedWorkPlaces.length; i < count; i++) {
workPlaces.push(BasePlace.unserialize(serializedWorkPlaces[i]));
}
const serializedSchoolPlaces = attributes.schoolPlaces || [];
const schoolPlaces = [];
for (let i = 0, count = serializedSchoolPlaces.length; i < count; i++) {
schoolPlaces.push(BasePlace.unserialize(serializedSchoolPlaces[i]));
}
const basePerson = BasePerson.unserialize(attributes.basePerson);
const person = new Person({ ...attributes, basePerson, trips, visitedPlaces, workPlaces, schoolPlaces });
return person;
}
// checks if minimum required information have been completed/declared
// TODO: test
isCompleteMinimum(): boolean {
return (
(this.basePerson.age !== undefined || this.basePerson.ageGroup) &&
this._sequence !== undefined &&
this._sequence > 0 &&
(this.ageCompare(16) < 0 || this.basePerson.drivingLicenseOwnership !== undefined) &&
this.basePerson.occupation !== undefined &&
this.personDidTrips !== undefined &&
this._isProxy !== undefined &&
// no need to check for age with transit pass ownership because all surveys would set to nonApplicable for too young:
this.basePerson.transitPassOwnership !== undefined
// TODO: school/work/Type if needed
// TODO: usualWork/School/Place if needed
// TODO: workOnTheRoad if needed
);
}
hasAtLeastOneTransitSegment(): boolean {
return this.getTrips().some((trip) => trip.hasAtLeastOneTransitSegment());
}
// needed to get the usual place and save it into basePerson, no matter which survey:
// od_mtl_2023 only asks for usual work/school place if none declared in travel diary
// TODO: test
setupWorkPlaces(): void {
const usualWorkVisitedPlaces = this.getUsualWorkVisitedPlaces();
if (
(this.shouldHaveAUsualWorkPlace() || usualWorkVisitedPlaces.length > 0) &&
(this.workPlaces === undefined || this.workPlaces.length === 0)
) {
if (usualWorkVisitedPlaces.length > 0) {
this.workPlaces = usualWorkVisitedPlaces.map((visitedPlace) => visitedPlace.baseVisitedPlace.basePlace);
}
}
}
// check if this person should declare a usual work place
shouldHaveAUsualWorkPlace(): boolean | undefined {
return (
this.isWorker() === true && // isWorker could be undefined if missing attributes/occupation
(this.hasUsualWorkPlace === true ||
(this.worksFromFixedLocation === true && this.isFullTimeWorker() === true) || // od_mtl_pilote_2022, od_mtl_ete_2023, od_mtl_2023 (part-time: not asked in od_mtl_2023)
(this.hasUsualWorkPlace === undefined && this.usualWorkPlaceIsHome === false) || // od_mtl_pilote_2021
(this.workType !== undefined &&
[
// od_qc_2023
'onLocation',
'hybrid',
'onTheRoadWithUsualPlace'
].includes(this.workType)))
);
}
// TODO: test
wentToUsualWorkPlace(): boolean {
return this.getUsualWorkVisitedPlaces().length > 0;
}
// TODO: test
getUsualWorkVisitedPlaces(): VisitedPlace[] {
const visitedPlaces = this.getVisitedPlaces();
const usualWorkVisitedPlaces = [];
for (let i = 0, count = visitedPlaces.length; i < count; i++) {
const visitedPlace = visitedPlaces[i];
if (visitedPlace.baseVisitedPlace.activity === 'workUsual') {
usualWorkVisitedPlaces.push(visitedPlace);
}
}
return usualWorkVisitedPlaces;
}
// TODO: test
getVisitedPlaces(): VisitedPlace[] {
return this.visitedPlaces || [];
}
// TODO: test
getTrips(): Trip[] {
return this.trips || [];
}
// TODO: test
countTrips(): number {
return this.getTrips().length || 0;
}
// TODO: test
countVisitedPlaces(): number {
return this.getVisitedPlaces().length || 0;
}
// TODO: test
getVisitedPlaceByUuid(visitedPlaceUuid: string): VisitedPlace | undefined {
return this.getVisitedPlaces().find((visitedPlace) => visitedPlace.baseVisitedPlace._uuid === visitedPlaceUuid);
}
// TODO: test
getVisitedPlaceBySequence(sequence: number): VisitedPlace | undefined {
return this.getVisitedPlaces().find((visitedPlace) => visitedPlace._sequence === sequence);
}
// TODO: test
getTripByUuid(tripUuid: string): Trip | undefined {
return this.getTrips().find((trip) => trip.baseTrip._uuid === tripUuid);
}
// TODO: test
getTripBySequence(sequence: number): Trip | undefined {
return this.getTrips().find((trip) => trip._sequence === sequence);
}
// TODO: test
sortVisitedPlaces() {
this.visitedPlaces = this.visitedPlaces?.sort((a, b) => {
return a._sequence - b._sequence;
});
}
// TODO: test
sortTrips() {
this.trips = this.trips?.sort((a, b) => {
return a._sequence - b._sequence;
});
}
getAge(): number | undefined {
return this.basePerson.age;
}
getAgeGroup(): string | undefined {
return this.basePerson.ageGroup;
}
isWorker(): boolean | undefined {
if (this.jobType !== undefined) {
// all except od_qc_2023 and od_mtl_pilote_2021
return ['yesFullTime', 'yesPartTime'].includes(this.jobType);
} else if (this.occupationQC !== undefined) {
// in od_qc_2023, cannot be both student and worker
return ['fullTimeWorker', 'partTimeWorker'].includes(this.occupationQC);
} else if (this.occupationV1 !== undefined) {
// od_mtl_pilote_2021
return ['fullTimeWorker', 'partTimeWorker', 'workerAndStudent'].includes(this.occupationV1);
}
return undefined;
}
isFullTimeWorker(): boolean | undefined {
if (this.jobType !== undefined) {
// all except od_qc_2023
return this.jobType === 'yesFullTime';
} else if (this.occupationQC !== undefined) {
// in od_qc_2023, cannot be both student and worker
return this.occupationQC === 'fullTimeWorker';
} else if (this.occupationV1 !== undefined) {
// od_mtl_pilote_2021: occupation or workerAndStudentType if both student and worker
return this.occupationV1 === 'fullTimeWorker' || this.workerAndStudentType.startsWith('fullTimeWork');
}
return undefined;
}
isPartTimeWorker(): boolean | undefined {
if (this.jobType !== undefined) {
// all except od_qc_2023
return this.jobType === 'yesPartTime';
} else if (this.occupationQC !== undefined) {
// in od_qc_2023, cannot be both student and worker
return this.occupationQC === 'partTimeWorker';
} else if (this.occupationV1 !== undefined) {
// od_mtl_pilote_2021: occupation or workerAndStudentType if both student and worker
return this.occupationV1 === 'partTimeWorker' || this.workerAndStudentType.startsWith('partTimeWork');
}
return undefined;
}
isStudent() {
if (this.studentType !== undefined) {
return ['yesFullTime', 'yesPartTime'].includes(this.studentType);
} else if (this.enrolledInSchool !== undefined) {
return [
'kindergartenFor4YearsOld',
'kindergarten',
'primarySchool',
'secondarySchool',
'collegeCegepDepAep',
'university',
'schoolAtHome',
'other' // not sure what to do with other...
].includes(this.enrolledInSchool);
} else if (this.occupationV1) {
// od_mtl_pilote_2021
return ['fullTimeStudent', 'partTimeStudent', 'workerAndStudent'].includes(this.occupationV1);
}
return undefined;
}
isFullTimeStudent() {
// only used in od_mtl_2023 and od_qc_2023
if (this.studentType !== undefined) {
return this.studentType === 'yesFullTime';
} else if (this.enrolledInSchool !== undefined) {
// not sure what to do with other, but in the helper, it returned false here
return [
'kindergartenFor4YearsOld',
'kindergarten',
'primarySchool',
'secondarySchool',
'schoolAtHome',
'other' // not sure what to do with other...
].includes(this.enrolledInSchool);
} else if (this.occupationV1) {
// od_mtl_pilote_2021
return (
['fullTimeStudent'].includes(this.occupationV1) || this.workerAndStudentType.endsWith('FullTimeStudies')
);
} else if (this.occupationQC) {
// in od_qc_2023, cannot be both student and worker
return this.occupationQC === 'fullTimeStudent';
}
}
isPartTimeStudent() {
// only used in od_mtl_2023 and od_qc_2023
if (this.studentType !== undefined) {
return this.studentType === 'yesPartTime';
} else if (this.occupationV1) {
// od_mtl_pilote_2021
return (
['partTimeStudent'].includes(this.occupationV1) || this.workerAndStudentType.endsWith('PartTimeStudies')
);
} else if (this.occupationQC) {
// in od_qc_2023, cannot be both student and worker
return this.occupationQC === 'partTimeStudent';
}
}
isSelfDeclared() {
// the person responded for themselves
const ageComparison = this.ageCompare(config.selfResponseMinimumAge || 14);
if (ageComparison !== undefined && ageComparison >= 0) {
if (this.whoWillAnswerForThisPerson !== undefined) {
return this.whoWillAnswerForThisPerson === this.basePerson._uuid;
} else if (this.whoAnsweredForThisPerson !== undefined) {
return this.whoAnsweredForThisPerson === this.basePerson._uuid;
} else {
return undefined;
}
}
if (ageComparison === undefined) {
return undefined;
} else {
// too young, auto proxy
return false;
}
}
isProxy() {
// another household member responded for this person
const isSelfDeclared = this.isSelfDeclared();
if (isSelfDeclared !== undefined) {
return !isSelfDeclared;
}
return undefined;
}
mayHaveDisability() {
if (this.hasDisability !== undefined) {
return this.hasDisability !== 'no'; // accept yes and preferNotToAnswer
}
return undefined;
}
/**
* Compare the age of a person with a requested age. This will look at the age
* field, if set, or see if the desired age is within the ageGroup
*
* @param age The age to compare to
* @return -1 if the person age or age group is lower than the value, 0 if the
* age is equal or the ageGroup includes the age, 1 if the person age or
* ageGroup is higher than requested age, or undefined if the age and ageGroup are
* unavailable
*/
ageCompare(age: number): number | undefined {
const personAge = this.basePerson.age;
if (typeof personAge === 'number') {
return personAge < age ? -1 : personAge === age ? 0 : 1;
}
const ageGroup = this.basePerson.ageGroup;
if (typeof ageGroup !== 'string') {
return undefined;
}
const separatorDashPos = ageGroup.indexOf('-');
if (separatorDashPos !== -1) {
const minAge = parseInt(ageGroup.substring(0, separatorDashPos));
const maxAge = parseInt(ageGroup.substring(separatorDashPos + 1));
if (!Number.isNaN(minAge) && !Number.isNaN(maxAge)) {
return maxAge < age ? -1 : minAge > age ? 1 : 0;
}
return undefined;
}
const separatorPlusPos = ageGroup.indexOf('+');
if (separatorPlusPos !== -1) {
const minMaxAge = parseInt(ageGroup.substring(0, separatorPlusPos));
if (!Number.isNaN(minMaxAge)) {
return minMaxAge < age ? -1 : minMaxAge === age ? 0 : 1;
}
}
return undefined;
}
/**
* Function that converts and move all versions of mode frequencies to a normalized format
* @param dirtyParams
* @returns modeFrequencies: PAttr.FrequencyByTripTypeAndModeV1AndV2
*/
static moveModeFrequencies(
dirtyParams: { [key: string]: any },
surveyShortname
): PAttr.FrequencyByTripTypeAndModeV1AndV2 {
/*
anyTripModeFrequenciesWalk?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // all except od_qc_2023 (v1), od_mtl_2023 (v2)
anyTripModeFrequenciesBicycle?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // all except od_qc_2023 (v1), od_mtl_2023 (v2)
anyTripModeFrequenciesCarDriver?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // all except od_qc_2023 (v1), od_mtl_2023 (v2)
anyTripModeFrequenciesCarPassenger?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // all except od_qc_2023 (v1), od_mtl_2023 (v2)
anyTripModeFrequenciesTransit?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1)
anyTripModeFrequenciesTransitBus?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
anyTripModeFrequenciesTransitSubway?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
anyTripModeFrequenciesTransitTrainREM?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
anyTripModeFrequenciesSchoolBus?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1)
anyTripModeFrequenciesTaxi?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1)
// can start with homeWorkTripFrequencies too:
workCommutingFrequenciesWalk?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
workCommutingFrequenciesBicycle?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
workCommutingFrequenciesCarDriver?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
workCommutingFrequenciesCarPassenger?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
workCommutingFrequenciesTransit?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1)
workCommutingFrequenciesTransitBus?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
workCommutingFrequenciesTransitSubway?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
workCommutingFrequenciesTransitTrainREM?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
workCommutingFrequenciesSchoolBus?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // unused
workCommutingFrequenciesTaxi?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // unused
// can start with homeSchoolTripFrequencies too:
schoolCommutingFrequenciesWalk?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
schoolCommutingFrequenciesBicycle?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
schoolCommutingFrequenciesCarDriver?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
schoolCommutingFrequenciesCarPassenger?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1), od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
schoolCommutingFrequenciesTransit?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2), od_mtl_ete_2023 (v1)
schoolCommutingFrequenciesTransitBus?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
schoolCommutingFrequenciesTransitSubway?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
schoolCommutingFrequenciesTransitTrainREM?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_pilote_2021 (v1), od_mtl_pilote_2022 (v1)
schoolCommutingFrequenciesSchoolBus?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // od_mtl_2023 (v2)
schoolCommutingFrequenciesTaxi?: PAttr.ModeFrequencyV1 | PAttr.ModeFrequencyV2; // unused
*/
let modeFrequencies: PAttr.FrequencyByTripTypeAndModeV1AndV2 | undefined = undefined;
if (!dirtyParams.modeFrequencies) {
modeFrequencies = {
anyTripV1: {
walk: surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesWalk : undefined,
bicycle: surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesBicycle : undefined,
carDriver:
surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesCarDriver : undefined,
carPassenger:
surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesCarPassenger : undefined,
transit: surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTransit : undefined,
transitBus:
surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTransitBus : undefined,
transitSubway:
surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTransitSubway : undefined,
transitTrainREM:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.anyTripModeFrequenciesTransitTrainREM
: undefined,
schoolBus:
surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesSchoolBus : undefined,
taxi: surveyShortname !== 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTaxi : undefined
},
anyTripV2: {
walk: surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesWalk : undefined,
bicycle: surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesBicycle : undefined,
carDriver:
surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesCarDriver : undefined,
carPassenger:
surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesCarPassenger : undefined,
transit: surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTransit : undefined,
transitBus:
surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTransitBus : undefined,
transitSubway:
surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTransitSubway : undefined,
transitTrainREM:
surveyShortname === 'od_mtl_2023'
? dirtyParams.anyTripModeFrequenciesTransitTrainREM
: undefined,
schoolBus:
surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesSchoolBus : undefined,
taxi: surveyShortname === 'od_mtl_2023' ? dirtyParams.anyTripModeFrequenciesTaxi : undefined
},
workCommutingV1: {
walk:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesWalk ||
dirtyParams.homeWorkTripModeFrequenciesWalk ||
dirtyParams.homeWorkTripModeFrequencies?.walk
: undefined,
bicycle:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesBicycle ||
dirtyParams.homeWorkTripModeFrequenciesBicycle ||
dirtyParams.homeWorkTripModeFrequencies?.bicycle
: undefined,
carDriver:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesCarDriver ||
dirtyParams.homeWorkTripModeFrequenciesCarDriver ||
dirtyParams.homeWorkTripModeFrequencies?.CarDriver
: undefined, // yes with a capital C!
carPassenger:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesCarPassenger ||
dirtyParams.homeWorkTripModeFrequenciesCarPassenger ||
dirtyParams.homeWorkTripModeFrequencies?.CarPassenger
: undefined, // yes with a capital C!
transit:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransit ||
dirtyParams.homeWorkTripModeFrequenciesTransit ||
dirtyParams.homeWorkTripModeFrequencies?.transit
: undefined,
transitBus:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransitBus ||
dirtyParams.homeWorkTripModeFrequenciesTransitBus ||
dirtyParams.homeWorkTripModeFrequencies?.transitBus
: undefined,
transitSubway:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransitSubway ||
dirtyParams.homeWorkTripModeFrequenciesTransitSubway ||
dirtyParams.homeWorkTripModeFrequencies?.transitSubway
: undefined,
transitTrainREM:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransitTrainREM ||
dirtyParams.homeWorkTripModeFrequenciesTransitTrainREM ||
dirtyParams.homeWorkTripModeFrequencies?.transitTrainREM
: undefined,
schoolBus:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesSchoolBus ||
dirtyParams.homeWorkTripModeFrequenciesSchoolBus ||
dirtyParams.homeWorkTripModeFrequencies?.schoolBus
: undefined,
taxi:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTaxi ||
dirtyParams.homeWorkTripModeFrequenciesTaxi ||
dirtyParams.homeWorkTripModeFrequencies?.taxi
: undefined
},
workCommutingV2: {
walk:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesWalk ||
dirtyParams.homeWorkTripModeFrequenciesWalk
: undefined,
bicycle:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesBicycle ||
dirtyParams.homeWorkTripModeFrequenciesBicycle
: undefined,
carDriver:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesCarDriver ||
dirtyParams.homeWorkTripModeFrequenciesCarDriver
: undefined,
carPassenger:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesCarPassenger ||
dirtyParams.homeWorkTripModeFrequenciesCarPassenger
: undefined,
transit:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransit ||
dirtyParams.homeWorkTripModeFrequenciesTransit
: undefined,
transitBus:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransitBus ||
dirtyParams.homeWorkTripModeFrequenciesTransitBus
: undefined,
transitSubway:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransitSubway ||
dirtyParams.homeWorkTripModeFrequenciesTransitSubway
: undefined,
transitTrainREM:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTransitTrainREM ||
dirtyParams.homeWorkTripModeFrequenciesTransitTrainREM
: undefined,
schoolBus:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesSchoolBus ||
dirtyParams.homeWorkTripModeFrequenciesSchoolBus
: undefined,
taxi:
surveyShortname === 'od_mtl_2023'
? dirtyParams.workCommutingModeFrequenciesTaxi ||
dirtyParams.homeWorkTripModeFrequenciesTaxi
: undefined
},
schoolCommutingV1: {
walk:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesWalk ||
dirtyParams.homeSchoolTripModeFrequenciesWalk
: undefined,
bicycle:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesBicycle ||
dirtyParams.homeSchoolTripModeFrequenciesBicycle
: undefined,
carDriver:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesCarDriver ||
dirtyParams.homeSchoolTripModeFrequenciesCarDriver
: undefined,
carPassenger:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesCarPassenger ||
dirtyParams.homeSchoolTripModeFrequenciesCarPassenger
: undefined,
transit:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransit ||
dirtyParams.homeSchoolTripModeFrequenciesTransit
: undefined,
transitBus:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransitBus ||
dirtyParams.homeSchoolTripModeFrequenciesTransitBus
: undefined,
transitSubway:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransitSubway ||
dirtyParams.homeSchoolTripModeFrequenciesTransitSubway
: undefined,
transitTrainREM:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransitTrainREM ||
dirtyParams.homeSchoolTripModeFrequenciesTransitTrainREM
: undefined,
schoolBus:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesSchoolBus ||
dirtyParams.homeSchoolTripModeFrequenciesSchoolBus
: undefined,
taxi:
surveyShortname !== 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTaxi ||
dirtyParams.homeSchoolTripModeFrequenciesTaxi
: undefined
},
schoolCommutingV2: {
walk:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesWalk ||
dirtyParams.homeSchoolTripModeFrequenciesWalk
: undefined,
bicycle:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesBicycle ||
dirtyParams.homeSchoolTripModeFrequenciesBicycle
: undefined,
carDriver:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesCarDriver ||
dirtyParams.homeSchoolTripModeFrequenciesCarDriver
: undefined,
carPassenger:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesCarPassenger ||
dirtyParams.homeSchoolTripModeFrequenciesCarPassenger
: undefined,
transit:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransit ||
dirtyParams.homeSchoolTripModeFrequenciesTransit
: undefined,
transitBus:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransitBus ||
dirtyParams.homeSchoolTripModeFrequenciesTransitBus
: undefined,
transitSubway:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransitSubway ||
dirtyParams.homeSchoolTripModeFrequenciesTransitSubway
: undefined,
transitTrainREM:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTransitTrainREM ||
dirtyParams.homeSchoolTripModeFrequenciesTransitTrainREM
: undefined,
schoolBus:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesSchoolBus ||
dirtyParams.homeSchoolTripModeFrequenciesSchoolBus
: undefined,
taxi:
surveyShortname === 'od_mtl_2023'
? dirtyParams.schoolCommutingModeFrequenciesTaxi ||
dirtyParams.homeSchoolTripModeFrequenciesTaxi
: undefined
}
};
// fill out missing aggregated transit if more precise data exists:
for (const tripsType in modeFrequencies) {
if (modeFrequencies[tripsType].transit === undefined) {
if (tripsType.endsWith('V1')) {
modeFrequencies[tripsType].transit = PAttr.highestFrequencyV1([
modeFrequencies[tripsType].transitBus,
modeFrequencies[tripsType].transitSubway,
modeFrequencies[tripsType].transitTrainREM
]);
} else if (tripsType.endsWith('V2')) {
modeFrequencies[tripsType].transit = PAttr.highestFrequencyV2([
modeFrequencies[tripsType].transitBus,
modeFrequencies[tripsType].transitSubway,
modeFrequencies[tripsType].transitTrainREM
]);
}
}
}
}
return modeFrequencies || dirtyParams.modeFrequencies;
}
/**
* Factory that validates input from an interview and makes
* sure types and required fields are valid before returning a new object
* @param dirtyParams
* @param surveyShortname required for some pre-parsing (like moving/converting mode frequencies)
* @param previousDay required to get correct dates to replace 'everyday' in previousWeekDidTripsDay and other questions with dates
* @returns Person | Error[]
*/
static async create(
dirtyParams: { [key: string]: any },
surveyShortname: string,
previousDay: Date | string
): Promise<Person | Error[]> {
// Get validated data, but use original responses for some attributes:
const _dirtyParams = _cloneDeep(dirtyParams);
dirtyParams.previousWeekDidTripsDays =
dirtyParams.previousWeekDidTripsDays !== undefined
? dirtyParams.previousWeekDidTripsDays.map((date) => parseDate(date))
: undefined;
dirtyParams.previousWeekWentToSchoolOutsideHomeDays =
dirtyParams.previousWeekWentToSchoolOutsideHomeDays !== undefined
? dirtyParams.previousWeekWentToSchoolOutsideHomeDays.map((date) => parseDate(date))
: undefined;
dirtyParams.previousWeekWentToWorkOutsideHomeDays =
dirtyParams.previousWeekWentToWorkOutsideHomeDays !== undefined
? dirtyParams.previousWeekWentToWorkOutsideHomeDays.map((date) => parseDate(date))
: undefined;
dirtyParams.previousWeekWorkingDays =
dirtyParams.previousWeekWorkingDays !== undefined
? dirtyParams.previousWeekWorkingDays.map((date) => parseDate(date))
: undefined;
if (typeof _dirtyParams.hasDisability === 'boolean') {
// some surveys have hasDisability as a boolean
_dirtyParams.hasDisability =
_dirtyParams.hasDisability === true ? 'yes' : _dirtyParams.hasDisability === false ? 'no' : undefined;
}
// convert null values to undefined:
convertNullToUndefined(_dirtyParams);
// convert strings to numbers:
const numberTypeAttributes = ['age'];
for (let i = 0, count = numberTypeAttributes.length; i < count; i++) {
const attribute = numberTypeAttributes[i];
_dirtyParams[attribute] = convertStringsToNumbers(_dirtyParams[attribute]);
}
// convert ageIsApproximate to boolean: TODO: test
if (_dirtyParams.ageIsApproximate !== undefined) {
_dirtyParams.ageIsApproximate = _dirtyParams.ageIsApproximate === 'yes';
} else {
_dirtyParams.ageIsApproximate = false;
}
// convert and move mode frequencies to normalized object, with V1 and V2 frequency choices:
const modeFrequencies = Person.moveModeFrequencies(_dirtyParams, surveyShortname);
_dirtyParams.modeFrequencies = modeFrequencies;
// fix typo in educational attainment:
if (_dirtyParams.educationalAttainment === 'diplomaBellowBachelor') {
_dirtyParams.educationalAttainment = 'diplomaBelowBachelor';
}
// convert noSchoolTripReason and noWorkTripReason to v1 or v2
if (['od_mtl_pilote_2021', 'od_mtl_pilote_2022'].includes(surveyShortname)) {
_dirtyParams.noSchoolTripReasonV1 = _dirtyParams.noSchoolTripReason;
_dirtyParams.noSchoolTripReasonV2 = undefined;
_dirtyParams.noWorkTripReasonV1 = _dirtyParams.noWorkTripReason;
_dirtyParams.noWorkTripReasonV2 = undefined;
} else if (['od_mtl_2023', 'od_qc_2023'].includes(surveyShortname)) {
_dirtyParams.noSchoolTripReasonV2 = _dirtyParams.noSchoolTripReason;
_dirtyParams.noSchoolTripReasonV1 = undefined;
_dirtyParams.noWorkTripReasonV2 = _dirtyParams.noWorkTripReason;
_dirtyParams.noWorkTripReasonV1 = undefined;
}
delete _dirtyParams.noSchoolTripReason;
delete _dirtyParams.noWorkTripReason;
// convert parentConsent to string (od_qc_2023 only):
if (_dirtyParams.parentConsent) {
if (_dirtyParams.parentConsent === -1) {
_dirtyParams.parentConsent = 'parentNotAvailable';
} else if (_dirtyParams.parentConsent === 0) {
_dirtyParams.parentConsent = 'parentAvailable';
} else if (_dirtyParams.parentConsent === 1) {
_dirtyParams.parentConsent = 'parentAlreadyThere';
} else {
_dirtyParams.parentConsent = undefined;
}
}
// fix typos in attribute names:
if (
_dirtyParams.doesNotStudiesFromFixedLocationReason !== undefined &&
_dirtyParams.doesNotStudyFromFixedLocationReason === undefined
) {
_dirtyParams.doesNotStudyFromFixedLocationReason = _dirtyParams.doesNotStudiesFromFixedLocationReason;
delete _dirtyParams.doesNotStudiesFromFixedLocationReason;
}
const previousDayMoment = previousDay !== undefined ? moment(parseDate(previousDay)) : undefined; // we assume previousDay is a valid date
// convert some arrays created from previous day to date[]:
const stringDateAttributes = [
'previousWeekDidTripsDays',
'previousWeekWentToSchoolOutsideHomeDays',
'previousWeekWentToWorkOutsideHomeDays',
'previousWeekWorkingDays'
];
for (let attributeI = 0; attributeI < stringDateAttributes.length; attributeI++) {
const attribute = stringDateAttributes[attributeI];
const value = _dirtyParams[attribute];
// TODO: add more testing or a try catch to make sure it works even with bad data
if (previousDayMoment && value !== undefined && Array.isArray(value)) {
if (value.length === 1 && value[0] === 'none') {
_dirtyParams[attribute] = [];
} else if (value.length === 1 && value[0] === 'everyday') {
_dirtyParams[attribute] = [];
for (let i = 6; i >= 0; i--) {
_dirtyParams[attribute].push(previousDayMoment.clone().subtract(i, 'days').toDate());
}
} else if (value.length > 1) {
for (let i = 0; i < value.length; i++) {
const date = new Date(value[i] + 'T00:00:00');
if (!(date instanceof Date) || isNaN(date.getDate())) {
_dirtyParams[attribute].push(new Date(value[i] + 'T00:00:00'));
}
}
}
}
}
// move transitFares to transitPassTypes (od_qc_2023) or transitFaresUsed (od_mtl_ete_2023)
if (surveyShortname === 'od_qc_2023' && _dirtyParams.transitFares !== undefined) {
_dirtyParams.transitPassTypes = _dirtyParams.transitFares;
} else if (surveyShortname === 'od_mtl_ete_2023' && _dirtyParams.transitFares !== undefined) {
_dirtyParams.transitFaresUsed = _dirtyParams.transitFares;
}
delete _dirtyParams.transitFares;
// correct useParaTransit:
if (_dirtyParams.useParatransit !== undefined) {
// there was an incorrect labelling in od_mtl_ete_2023:
if (surveyShortname === 'od_mtl_ete_2023' && _dirtyParams.useParatransit === 'dontKnow') {
_dirtyParams.useParatransit = 'preferNotToAnswer';
}
}
const errors: Error[] = [];
const workPlaces: BasePlace[] = [];
const schoolPlaces: BasePlace[] = [];
// move and homogenize usual school and work places:
const usualSchoolPlaceDirtyParams: BasePlaceAttributes = {
geography: undefined,
name: undefined,
lastAction: undefined,
geocodingQueryString: undefined,
deviceUsed: undefined,
zoom: undefined
};
let usualSchoolPlaceParamsGeography: GeoJSON.Feature<GeoJSON.Point, { [key: string]: any }> | undefined =
undefined;
if (_dirtyParams.usualSchoolPlace?.geometry) {
usualSchoolPlaceParamsGeography = _dirtyParams.usualSchoolPlace;
} else if (_dirtyParams.usualSchoolPlace?.geography) {
usualSchoolPlaceParamsGeography = _dirtyParams.usualSchoolPlace.geography;
} else if (_dirtyParams.usualStudyPlaceNameGeographie) {
usualSchoolPlaceParamsGeography = _dirtyParams.usualStudyPlaceNameGeographie;
}
if (usualSchoolPlaceParamsGeography) {
usualSchoolPlaceDirtyParams.geography = usualSchoolPlaceParamsGeography;
if (usualSchoolPlaceDirtyParams.geography?.properties === undefined) {
usualSchoolPlaceDirtyParams.geography.properties = {};
}
usualSchoolPlaceDirtyParams.name =
_dirtyParams.usualSchoolPlaceName ||
_dirtyParams.usualSchoolPlace?.name ||
_dirtyParams.usualStudyPlaceName;
usualSchoolPlaceDirtyParams.lastAction = usualSchoolPlaceParamsGeography.properties?.lastAction;
usualSchoolPlaceDirtyParams.geocodingQueryString =
usualSchoolPlaceParamsGeography.properties?.geocodingQueryString;
usualSchoolPlaceDirtyParams.deviceUsed = usualSchoolPlaceParamsGeography.properties?.platform;
usualSchoolPlaceDirtyParams.zoom = usualSchoolPlaceParamsGeography.properties?.zoom;
if (usualSchoolPlaceParamsGeography.properties?.geocodingResultsData) {
if (!usualSchoolPlaceDirtyParams.geography.properties) {
usualSchoolPlaceDirtyParams.geography.properties = {};
}
usualSchoolPlaceDirtyParams.geography.properties.googleFormattedAddress =
usualSchoolPlaceParamsGeography.properties.geocodingResultsData.formatted_address;
usualSchoolPlaceDirtyParams.geography.properties.googleTypes =
usualSchoolPlaceParamsGeography.properties.geocodingResultsData.types;
usualSchoolPlaceDirtyParams.geography.properties.googlePlaceId =
usualSchoolPlaceParamsGeography.properties.geocodingResultsData.place_id;
usualSchoolPlaceDirtyParams.geography.properties.googlePlaceName =
usualSchoolPlaceParamsGeography.properties.geocodingResultsData.name;
delete usualSchoolPlaceDirtyParams.geography.properties.geocodingResultsData;
}
if (usualSchoolPlaceDirtyParams && usualSchoolPlaceDirtyParams.geography) {
errors.push(...BasePlace.validateParams(usualSchoolPlaceDirtyParams));
if (errors.length === 0) {
schoolPlaces.push(new BasePlace(usualSchoolPlaceDirtyParams));
}
}
}
const usualWorkPlaceDirtyParams: BasePlaceAttributes = {
geography: undefined,
name: undefined,
lastAction: undefined,
geocodingQueryString: undefined,
deviceUsed: undefined,
zoom: undefined
};
let usualWorkPlaceParamsGeography: GeoJSON.Feature<GeoJSON.Point, { [key: string]: any }> | undefined =
undefined;
if (_dirtyParams.usualWorkPlace?.geometry) {
usualWorkPlaceParamsGeography = _dirtyParams.usualWorkPlace;
} else if (_dirtyParams.usualWorkPlace?.geography) {
usualWorkPlaceParamsGeography = _dirtyParams.usualWorkPlace.geography;
} else if (_dirtyParams.usualWorkPlaceNameGeographie) {
usualWorkPlaceParamsGeography = _dirtyParams.usualWorkPlaceNameGeographie;
}
if (usualWorkPlaceParamsGeography) {
usualWorkPlaceDirtyParams.geography = usualWorkPlaceParamsGeography;
if (usualWorkPlaceDirtyParams.geography?.properties === undefined) {
usualWorkPlaceDirtyParams.geography.properties = {};
}
usualWorkPlaceDirtyParams.name =
_dirtyParams.usualWorkPlaceName ||
_dirtyParams.usualWorkPlace?.name ||
_dirtyParams.usualStudyPlaceName;
usualWorkPlaceDirtyParams.lastAction = usualWorkPlaceParamsGeography.properties?.lastAction;
usualWorkPlaceDirtyParams.geocodingQueryString =
usualWorkPlaceParamsGeography.properties?.geocodingQueryString;
usualWorkPlaceDirtyParams.deviceUsed = usualWorkPlaceParamsGeography.properties?.platform;
usualWorkPlaceDirtyParams.zoom = usualWorkPlaceParamsGeography.properties?.zoom;
if (usualWorkPlaceParamsGeography.properties?.geocodingResultsData) {
if (!usualWorkPlaceDirtyParams.geography.properties) {
usualWorkPlaceDirtyParams.geography.properties = {};
}
usualWorkPlaceDirtyParams.geography.properties.googleFormattedAddress =
usualWorkPlaceParamsGeography.properties.geocodingResultsData.formatted_address;
usualWorkPlaceDirtyParams.geography.properties.googleTypes =
usualWorkPlaceParamsGeography.properties.geocodingResultsData.types;
usualWorkPlaceDirtyParams.geography.properties.googlePlaceId =
usualWorkPlaceParamsGeography.properties.geocodingResultsData.place_id;
usualWorkPlaceDirtyParams.geography.properties.googlePlaceName =
usualWorkPlaceParamsGeography.properties.geocodingResultsData.name;
delete usualWorkPlaceDirtyParams.geography.properties.geocodingResultsData;
}
if (usualWorkPlaceDirtyParams && usualWorkPlaceDirtyParams.geography) {
errors.push(...BasePlace.validateParams(usualWorkPlaceDirtyParams));
if (errors.length === 0) {
workPlaces.push(new BasePlace(usualWorkPlaceDirtyParams));
}
}
}
// generate departurePlaceIsHome from od_mtl_pilote_2021 departurePlaceType
if (
surveyShortname === 'od_mtl_pilote_2021' &&
_dirtyParams.departurePlaceType !== undefined &&
_dirtyParams.departurePlaceIsHome === undefined
) {
if (_dirtyParams.departurePlaceType === 'home') {
_dirtyParams.departurePlaceIsHome = 'yes';
delete _dirtyParams.departurePlaceType;
} else if (_dirtyParams.departurePlaceType === 'other') {
_dirtyParams.departurePlaceIsHome = 'no';
delete _dirtyParams.departurePlaceType;
}
}
// generate personDidTrips from od_mtl_pilote_2021 didTripsOnTripsDate
if (
surveyShortname === 'od_mtl_pilote_2021' &&
_dirtyParams.didTripsOnTripsDate !== undefined &&
_dirtyParams.personDidTrips === undefined
) {
if (_dirtyParams.didTripsOnTripsDate === 'yes') {
_dirtyParams.personDidTrips = 'yes';
delete _dirtyParams.didTripsOnTripsDate;
} else if (_dirtyParams.didTripsOnTripsDate === 'no') {
_dirtyParams.personDidTrips = 'no';
delete _dirtyParams.didTripsOnTripsDate;
} else if (_dirtyParams.didTripsOnTripsDate === 'dontKnow') {
_dirtyParams.personDidTrips = 'dontKnow';
delete _dirtyParams.didTripsOnTripsDate;
}
}
// convert bixi usage to new version:
if (_dirtyParams['bixiBikesharingUsage_NewOptions2023-10-18'] !== undefined) {
_dirtyParams.bixiBikesharingUsageV2 = _dirtyParams['bixiBikesharingUsage_NewOptions2023-10-18'];
}
delete _dirtyParams['bixiBikesharingUsage_NewOptions2023-10-18'];
if (_dirtyParams.bixiBikesharingUsage !== undefined) {
if (['seasonal', 'monthly', 'subscriptionWithPay'].includes(_dirtyParams.bixiBikesharingUsage)) {
_dirtyParams.bixiBikesharingUsageV2 = 'monthlySeasonalAnnual';
} else if (['noSubscription'].includes(_dirtyParams.bixiBikesharingUsage)) {
_dirtyParams.bixiBikesharingUsageV2 = 'payPerTrip';
}
}
// fix missing lowercase for supportAndClericalStaff
if (_dirtyParams.jobCategory === 'SupportAndClericalStaff') {
_dirtyParams.jobCategory = 'supportAndClericalStaff';
}
// convert daysAtOfficePerWeek fron number to string
if (_dirtyParams.daysAtOfficePerWeek !== undefined) {
if (_dirtyParams.daysAtOfficePerWeek < 0 || _dirtyParams.daysAtOfficePerWeek > 5) {
_dirtyParams.daysAtOfficePerWeek = undefined;
}
if (_dirtyParams.daysAtOfficePerWeek === 0) {
_dirtyParams.daysAtOfficePerWeek = 'lessThan1';
} else if (_dirtyParams.daysAtOfficePerWeek >= 1 && _dirtyParams.daysAtOfficePerWeek < 5) {
_dirtyParams.daysAtOfficePerWeek = _dirtyParams.daysAtOfficePerWeek.toString();
} else if (_dirtyParams.daysAtOfficePerWeek === 5) {
_dirtyParams.daysAtOfficePerWeek = '5+';
}
}
// convert occupations:
_dirtyParams.occupationV1 = undefined;
_dirtyParams.occupationV2 = undefined;
_dirtyParams.occupationV3 = undefined;
_dirtyParams.occupationQC = undefined;
if (
(surveyShortname === 'od_mtl_2023' || surveyShortname === 'od_mtl_ete_2023') &&
_dirtyParams.occupation !== undefined
) {
_dirtyParams.occupationV3 = _dirtyParams.occupation;
delete _dirtyParams.occupation;
} else if (surveyShortname === 'od_mtl_pilote_2021' && _dirtyParams.occupation !== undefined) {
_dirtyParams.occupationV1 = _dirtyParams.occupation;
delete _dirtyParams.occupation;
} else if (surveyShortname === 'od_mtl_pilote_2022' && _dirtyParams.occupation !== undefined) {
_dirtyParams.occupationV2 = _dirtyParams.occupation;
delete _dirtyParams.occupation;
} else if (surveyShortname === 'od_qc_2023' && _dirtyParams.occupation !== undefined) {
_dirtyParams.occupationQC = _dirtyParams.occupation;
delete _dirtyParams.occupation;
}
// convert transitPasses:
_dirtyParams.transitPassesV1 = undefined;
_dirtyParams.transitPassesV2 = undefined;
_dirtyParams.transitPassesQC = undefined;
if (_dirtyParams.transitPasses !== undefined && Array.isArray(_dirtyParams.transitPasses)) {
if (
surveyShortname === 'od_mtl_2023' ||
surveyShortname === 'od_mtl_ete_2023' ||
surveyShortname === 'od_mtl_pilote_2022'
) {
_dirtyParams.transitPassesV2 = _dirtyParams.transitPasses;
delete _dirtyParams.transitPasses;
} else if (surveyShortname === 'od_mtl_pilote_2021') {
_dirtyParams.transitPassesV1 = _dirtyParams.transitPasses;
delete _dirtyParams.transitPasses;
} else if (surveyShortname === 'od_qc_2023') {
_dirtyParams.transitPassesQC = _dirtyParams.transitPasses;
delete _dirtyParams.transitPasses;
}
}
// fix typos in short section did trips:
if (
_dirtyParams.shortTripSectionDidTripOnTripsDate !== undefined &&
_dirtyParams.shortTripSectionDidTripsOnTripsDate === undefined
) {
_dirtyParams.shortTripSectionDidTripsOnTripsDate = _dirtyParams.shortTripSectionDidTripOnTripsDate;
delete _dirtyParams.shortTripSectionDidTripOnTripsDate;
}
if (
_dirtyParams.shortTripSectionDidTripToUsualSchoolPlaceOnTripsDate !== undefined &&
_dirtyParams.shortTripSectionDidTripsToUsualSchoolPlaceOnTripsDate === undefined
) {
_dirtyParams.shortTripSectionDidTripsToUsualSchoolPlaceOnTripsDate =
_dirtyParams.shortTripSectionDidTripToUsualSchoolPlaceOnTripsDate;
delete _dirtyParams.shortTripSectionDidTripToUsualSchoolPlaceOnTripsDate;
}
if (
_dirtyParams.shortTripSectionDidTripToUsualWorkPlaceOnTripsDate !== undefined &&
_dirtyParams.shortTripSectionDidTripsToUsualWorkPlaceOnTripsDate === undefined
) {
_dirtyParams.shortTripSectionDidTripsToUsualWorkPlaceOnTripsDate =
_dirtyParams.shortTripSectionDidTripToUsualWorkPlaceOnTripsDate;
delete _dirtyParams.shortTripSectionDidTripToUsualWorkPlaceOnTripsDate;
}
// fix wrong label in od_mtl_2023 for useParatransit:
if (surveyShortname === 'od_mtl_2023' && _dirtyParams.useParatransit === 'dontKnow') {
_dirtyParams.useParatransit = 'preferNotToAnswer';
}
// remove usual places, trips and visited places from params (will be created separately):
delete _dirtyParams.trips;
delete _dirtyParams.visitedPlaces;
delete _dirtyParams.schoolPlaces;
delete _dirtyParams.workPlaces;
// validate params for both interview and baseInterview:
errors.push(...BasePerson.validateParams(_dirtyParams), ...Person.validateParams(_dirtyParams));
if (errors.length > 0) {
return errors;
} else {
const basePerson = BasePerson.create(_dirtyParams) as BasePerson;
const person = new Person({ basePerson, ..._dirtyParams } as { basePerson: BasePerson } & PersonAttributes);
person.workPlaces = workPlaces;
person.schoolPlaces = schoolPlaces;
await parser(person);
return person;
}
}
/**
* Validates attribute types of params:
* @param dirtyParams The parameters to validate.
* @returns Error[] TODO: specialize this error class
*/
static validateParams(dirtyParams: { [key: string]: any }): Error[] {
const errors: Error[] = [];
errors.push(
...ParamsValidatorTools.isInstanceOf('basePerson', dirtyParams.basePerson, displayName, BasePerson)
);
errors.push(
...ParamsValidatorTools.isBoolean(
'_completedSections.profile',
dirtyParams._completedSections?.profile,
displayName
)
);
errors.push(
...ParamsValidatorTools.isBoolean(
'_completedSections.segments',
dirtyParams._completedSections?.segments,
displayName
)
);
errors.push(
...ParamsValidatorTools.isBoolean(
'_completedSections.travelBehavior',
dirtyParams._completedSections?.travelBehavior,
displayName
)
);
errors.push(
...ParamsValidatorTools.isBoolean(
'_completedSections.tripsIntro',
dirtyParams._completedSections?.tripsIntro,
displayName
)
);
errors.push(
...ParamsValidatorTools.isBoolean(
'_completedSections.visitedPlaces',
dirtyParams._completedSections?.visitedPlaces,
displayName
)
);
errors.push(...ParamsValidatorTools.isRequired('_sequence', dirtyParams._sequence, displayName));
errors.push(...ParamsValidatorTools.isPositiveInteger('_sequence', dirtyParams._sequence, displayName));
errors.push(...ParamsValidatorTools.isBoolean('ageIsApproximate', dirtyParams.ageIsApproximate, displayName));
errors.push(
...ParamsValidatorTools.isString('bixiBikesharingUsage', dirtyParams.bixiBikesharingUsage, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'bixiBikesharingUsage_NewOptions2023-10-18',
dirtyParams['bixiBikesharingUsage_NewOptions2023-10-18'],
displayName
)
);
errors.push(
...ParamsValidatorTools.isString('bixiBikesharingUsageV2', dirtyParams.bixiBikesharingUsageV2, displayName)
);
errors.push(...ParamsValidatorTools.isString('bikeOwnership', dirtyParams.bikeOwnership, displayName));
errors.push(
...ParamsValidatorTools.isString('drivingLicenseOwner', dirtyParams.drivingLicenseOwner, displayName)
);
errors.push(...ParamsValidatorTools.isString('transitPassOwner', dirtyParams.transitPassOwner, displayName));
errors.push(
...ParamsValidatorTools.isString(
'communautoFlexCarsharingUsage',
dirtyParams.communautoFlexCarsharingUsage,
displayName
)
);
errors.push(...ParamsValidatorTools.isString('canRemoteWork', dirtyParams.canRemoteWork, displayName));
errors.push(
...ParamsValidatorTools.isString('daysAtOfficePerWeek', dirtyParams.daysAtOfficePerWeek, displayName)
);
errors.push(
...ParamsValidatorTools.isString('departurePlaceIsHome', dirtyParams.departurePlaceIsHome, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'departurePlaceIsHomeConfirm',
dirtyParams.departurePlaceIsHomeConfirm,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString('departurePlaceOther', dirtyParams.departurePlaceOther, displayName)
);
errors.push(
...ParamsValidatorTools.isString('departurePlaceType', dirtyParams.departurePlaceType, displayName)
);
errors.push(
...ParamsValidatorTools.isString('didTripsOnTripsDate', dirtyParams.didTripsOnTripsDate, displayName)
);
errors.push(...ParamsValidatorTools.isArrayOfStrings('disabilities', dirtyParams.disabilities, displayName));
errors.push(
...ParamsValidatorTools.isString('disabilitiesComments', dirtyParams.disabilitiesComments, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'doesNotStudiesFromFixedLocationReason',
dirtyParams.doesNotStudiesFromFixedLocationReason,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'doesNotStudyFromFixedLocationReason',
dirtyParams.doesNotStudyFromFixedLocationReason,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString('educationalAttainment', dirtyParams.educationalAttainment, displayName)
);
errors.push(
...ParamsValidatorTools.isString('electricBikeOwnership', dirtyParams.electricBikeOwnership, displayName)
);
errors.push(...ParamsValidatorTools.isString('enrolledInSchool', dirtyParams.enrolledInSchool, displayName));
errors.push(
...ParamsValidatorTools.isString(
'everUsedBixiBikesharingServices',
dirtyParams.everUsedBixiBikesharingServices,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'everUsedCommunautoFlexCarsharingServicesAsADriver',
dirtyParams.everUsedCommunautoFlexCarsharingServicesAsADriver,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString('freeParkingAtSchool', dirtyParams.freeParkingAtSchool, displayName)
);
errors.push(...ParamsValidatorTools.isString('freeParkingAtWork', dirtyParams.freeParkingAtWork, displayName));
errors.push(...ParamsValidatorTools.isString('genderCustom', dirtyParams.genderCustom, displayName));
errors.push(...ParamsValidatorTools.isString('genderSpecify', dirtyParams.genderSpecify, displayName));
errors.push(...ParamsValidatorTools.isString('hasDisability', dirtyParams.hasDisability, displayName));
errors.push(
...ParamsValidatorTools.isBoolean(
'hasOmittedActiveModesTrips',
dirtyParams.hasOmittedActiveModesTrips,
displayName
)
);
errors.push(
...ParamsValidatorTools.isBoolean('hasUsualSchoolPlace', dirtyParams.hasUsualSchoolPlace, displayName)
);
errors.push(...ParamsValidatorTools.isBoolean('hasUsualWorkPlace', dirtyParams.hasUsualWorkPlace, displayName));
errors.push(...ParamsValidatorTools.isString('job', dirtyParams.job, displayName));
errors.push(...ParamsValidatorTools.isString('jobActivitySector', dirtyParams.jobActivitySector, displayName));
errors.push(...ParamsValidatorTools.isString('jobCategory', dirtyParams.jobCategory, displayName));
errors.push(
...ParamsValidatorTools.isString(
'jobCompatibleWithTelecommuting',
dirtyParams.jobCompatibleWithTelecommuting,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString('jobHoursFlexibility', dirtyParams.jobHoursFlexibility, displayName)
);
errors.push(
...ParamsValidatorTools.isString('jobHoursSchedulesType', dirtyParams.jobHoursSchedulesType, displayName)
);
errors.push(...ParamsValidatorTools.isString('jobType', dirtyParams.jobType, displayName));
errors.push(
...ParamsValidatorTools.isArrayOfStrings(
'mobilityAssistiveDevices',
dirtyParams.mobilityAssistiveDevices,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'mobilityAssistiveDevicesSpecify',
dirtyParams.mobilityAssistiveDevicesSpecify,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'mostUsedMobilityAssistiveDevice',
dirtyParams.mostUsedMobilityAssistiveDevice,
displayName
)
);
// ignore nickname altogether
errors.push(
...ParamsValidatorTools.isString('noSchoolTripReasonV1', dirtyParams.noSchoolTripReasonV1, displayName)
);
errors.push(
...ParamsValidatorTools.isString('noSchoolTripReasonV2', dirtyParams.noSchoolTripReasonV2, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'noSchoolTripReasonSpecify',
dirtyParams.noSchoolTripReasonSpecify,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'noUsualSchoolPlaceReason',
dirtyParams.noUsualSchoolPlaceReason,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString('noUsualWorkPlaceReason', dirtyParams.noUsualWorkPlaceReason, displayName)
);
errors.push(
...ParamsValidatorTools.isString('noWorkTripReasonV1', dirtyParams.noWorkTripReasonV1, displayName)
);
errors.push(
...ParamsValidatorTools.isString('noWorkTripReasonV2', dirtyParams.noWorkTripReasonV2, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'noWorkTripReasonSpecify',
dirtyParams.noWorkTripReasonSpecify,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'noWorkOrStudyTripReason',
dirtyParams.noWorkOrStudyTripReason,
displayName
)
);
errors.push(...ParamsValidatorTools.isString('occupationV1', dirtyParams.occupationV1, displayName));
errors.push(...ParamsValidatorTools.isString('occupationV2', dirtyParams.occupationV2, displayName));
errors.push(...ParamsValidatorTools.isString('occupationV3', dirtyParams.occupationV3, displayName));
errors.push(...ParamsValidatorTools.isString('occupationQC', dirtyParams.occupationQC, displayName));
errors.push(...ParamsValidatorTools.isString('occupationSpecify', dirtyParams.occupationSpecify, displayName));
errors.push(...ParamsValidatorTools.isString('parentConsent', dirtyParams.parentConsent, displayName));
errors.push(...ParamsValidatorTools.isBoolean('consentConfirm', dirtyParams.consentConfirm, displayName));
errors.push(...ParamsValidatorTools.isString('personDidTrips', dirtyParams.personDidTrips, displayName));
errors.push(
...ParamsValidatorTools.isString(
'personDidTripsChangeConfirm',
dirtyParams.personDidTripsChangeConfirm,
displayName
)
);
errors.push(
...ParamsValidatorTools.isArrayOf(
'previousWeekDidTripsDays',
dirtyParams.previousWeekDidTripsDays,
displayName,
Date
)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings(
'previousWeekNoWorkingDaysReasons',
dirtyParams.previousWeekNoWorkingDaysReasons,
displayName
)
);
errors.push(
...ParamsValidatorTools.isArrayOf(
'previousWeekWentToSchoolOutsideHomeDays',
dirtyParams.previousWeekWentToSchoolOutsideHomeDays,
displayName,
Date
)
);
errors.push(
...ParamsValidatorTools.isArrayOf(
'previousWeekWentToWorkOutsideHomeDays',
dirtyParams.previousWeekWentToWorkOutsideHomeDays,
displayName,
Date
)
);
errors.push(
...ParamsValidatorTools.isArrayOf(
'previousWeekWorkingDays',
dirtyParams.previousWeekWorkingDays,
displayName,
Date
)
);
//errors.push(...ParamsValidatorTools.isString('refuseAge', dirtyParams.refuseAge, displayName)); // ignore, implicit if ageGroup is set
errors.push(
...ParamsValidatorTools.isArrayOfStrings('remoteStudyDays', dirtyParams.remoteStudyDays, displayName)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('remoteWorkDays', dirtyParams.remoteWorkDays, displayName)
);
errors.push(...ParamsValidatorTools.isString('schoolType', dirtyParams.schoolType, displayName));
errors.push(
...ParamsValidatorTools.isString(
'shortTripSectionDidSchoolTripsOnTripsDate',
dirtyParams.shortTripSectionDidSchoolTripsOnTripsDate,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'shortTripSectionDidTripsOnTripsDate',
dirtyParams.shortTripSectionDidTripsOnTripsDate,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'shortTripSectionDidTripsToUsualSchoolPlaceOnTripsDate',
dirtyParams.shortTripSectionDidTripsToUsualSchoolPlaceOnTripsDate,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'shortTripSectionDidTripsToUsualWorkPlaceOnTripsDate',
dirtyParams.shortTripSectionDidTripsToUsualWorkPlaceOnTripsDate,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'shortTripSectionDidWorkTripsOnTripsDate',
dirtyParams.shortTripSectionDidWorkTripsOnTripsDate,
displayName
)
);
errors.push(...ParamsValidatorTools.isString('studentType', dirtyParams.studentType, displayName));
errors.push(
...ParamsValidatorTools.isString(
'studiesFromFixedLocation',
dirtyParams.studiesFromFixedLocation,
displayName
)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('transitPassTypes', dirtyParams.transitPassTypes, displayName)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('transitFaresUsed', dirtyParams.transitFaresUsed, displayName)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('transitPassesV1', dirtyParams.transitPassesV1, displayName)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('transitPassesV2', dirtyParams.transitPassesV2, displayName)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('transitPassesQC', dirtyParams.transitPassesQC, displayName)
);
errors.push(
...ParamsValidatorTools.isString('transitPassSpecify', dirtyParams.transitPassSpecify, displayName)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('travelToStudyDays', dirtyParams.travelToStudyDays, displayName)
);
errors.push(
...ParamsValidatorTools.isArrayOfStrings('travelToWorkDays', dirtyParams.travelToWorkDays, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'useBikeForUtilitarianTravel',
dirtyParams.useBikeForUtilitarianTravel,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'usedBixiBikesharingServicesInLast30Days',
dirtyParams.usedBixiBikesharingServicesInLast30Days,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'usedBixiBikesharingServicesInLast6Months',
dirtyParams.usedBixiBikesharingServicesInLast6Months,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'usedCommunautoCarsharingServicesAsADriverInLast6Months',
dirtyParams.usedCommunautoCarsharingServicesAsADriverInLast6Months,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'usedTransitInLast30Days',
dirtyParams.usedTransitInLast30Days,
displayName
)
);
errors.push(...ParamsValidatorTools.isString('useParatransit', dirtyParams.useParatransit, displayName));
errors.push(
...ParamsValidatorTools.isString(
'usualSchoolPlaceParkingType',
dirtyParams.usualSchoolPlaceParkingType,
displayName
)
);
errors.push(
...ParamsValidatorTools.isBoolean('usualWorkPlaceIsHome', dirtyParams.usualWorkPlaceIsHome, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'usualWorkPlaceParkingType',
dirtyParams.usualWorkPlaceParkingType,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'usualWorkPlaceUsageAtLeastOnceAWeek',
dirtyParams.usualWorkPlaceUsageAtLeastOnceAWeek,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString(
'usualWorkPlaceWasHomeBeforeThePandemic',
dirtyParams.usualWorkPlaceWasHomeBeforeThePandemic,
displayName
)
);
errors.push(
...ParamsValidatorTools.isUuid(
'whoAnsweredForThisPerson',
dirtyParams.whoAnsweredForThisPerson,
displayName
)
);
errors.push(
...ParamsValidatorTools.isUuid(
'whoWillAnswerForThisPerson',
dirtyParams.whoWillAnswerForThisPerson,
displayName
)
);
errors.push(
...ParamsValidatorTools.isString('workerAndStudentType', dirtyParams.workerAndStudentType, displayName)
);
errors.push(...ParamsValidatorTools.isString('workingPlace', dirtyParams.workingPlace, displayName));
errors.push(...ParamsValidatorTools.isBoolean('workOnTheRoad', dirtyParams.workOnTheRoad, displayName));
errors.push(
...ParamsValidatorTools.isBoolean('worksFromFixedLocation', dirtyParams.worksFromFixedLocation, displayName)
);
errors.push(
...ParamsValidatorTools.isString(
'workTripsDaysCountPerWeek',
dirtyParams.workTripsDaysCountPerWeek,
displayName
)
);
errors.push(...ParamsValidatorTools.isString('workType', dirtyParams.workType, displayName));
for (const tripsType in dirtyParams.modeFrequencies) {
for (const mode in dirtyParams.modeFrequencies[tripsType]) {
errors.push(
...ParamsValidatorTools.isString(
'modeFrequencies.' + tripsType + '.' + mode,
dirtyParams.modeFrequencies[tripsType][mode],
displayName
)
);
}
}
return errors;
}
}
export { Person, PersonAttributes };
/*
_uuid: validated in BasePerson
age: validated in BasePerson
ageGroup: validated in BasePerson
gender: validated in BasePerson
drivingLicenseOwnership: validated in BasePerson
transitPassOwnership: validated in BasePerson
carsharingMember: validated in BasePerson
carsharingUser: validated in BasePerson
bikesharingMember: validated in BasePerson
bikesharingUser: validated in BasePerson
ridesharingMember: validated in BasePerson
ridesharingUser: validated in BasePerson
occupation: validated in BasePerson
jobCategory: override in Person
jobName: validated in BasePerson
isOnTheRoadWorker: validated in BasePerson
isJobTelecommuteCompatible: validated in BasePerson
educationalAttainment: validated in BasePerson
_completedSections.profile: validateParams: boolean
_completedSections.segments: validateParams: boolean
_completedSections.travelBehavior: validateParams: boolean
_completedSections.tripsIntro: validateParams: boolean
_completedSections.visitedPlaces: validateParams: boolean
_sequence: validateParams: positive integer
bixiBikesharingUsage
bixiBikesharingUsage_NewOptions2023-10-18 // -> removed in parser
bixiBikesharingUsageV2
bikeOwnership
canRemoteWork
communautoFlexCarsharingUsage
daysAtOfficePerWeek
departurePlaceIsHome
departurePlaceIsHomeConfirm
departurePlaceOther
departurePlaceType
didTripsOnTripsDate
disabilities
disabilitiesComments
doesNotStudiesFromFixedLocationReason
doesNotStudyFromFixedLocationReason
drivingLicenseOwner // -> move to basePerson drivingLicenseOwnership
electricBikeOwnership
enrolledInSchool
everUsedBixiBikesharingServices
everUsedCommunautoFlexCarsharingServicesAsADriver
freeParkingAtSchool
freeParkingAtWork
genderCustom
genderSpecify
hasDisability
hasOmittedActiveModesTrips
hasUsualSchoolPlace
hasUsualWorkPlace
job
jobActivitySector
jobCategory
jobCompatibleWithTelecommuting
jobHoursFlexibility
jobHoursSchedulesType
jobType
mobilityAssistiveDevices
mobilityAssistiveDevicesSpecify
mostUsedMobilityAssistiveDevice
nickname // remove/ignored (confidential)
noSchoolTripReason
noSchoolTripReasonSpecify
noUsualSchoolPlaceReason
noWorkOrStudyTripReason
noWorkTripReason
noWorkTripReasonSpecify
occupationSpecify
parentConsent
consentConfirm
personDidTrips
personDidTripsChangeConfirm
previousWeekDidTripsDays
previousWeekNoWorkingDaysReasons
previousWeekWentToSchoolOutsideHomeDays
previousWeekWentToWorkOutsideHomeDays
previousWeekWorkingDays
refuseAge // ignore
remoteStudyDays
remoteWorkDays
schoolType
shortTripSectionDidSchoolTripsOnTripsDate
shortTripSectionDidTripOnTripsDate
shortTripSectionDidTripToUsualSchoolPlaceOnTripsDate
shortTripSectionDidTripToUsualWorkPlaceOnTripsDate
shortTripSectionDidWorkTripsOnTripsDate
studentType
studiesFromFixedLocation
transitFares // move to transitPassTypes (od_qc_2023) or transitFaresUsed (od_mtl_ete_2023)
transitFaresUsed
transitPassOwner // -> move to basePerson transitPassOwnership
transitPasses
transitPassSpecify
travelToStudyDays
travelToWorkDays
useBikeForUtilitarianTravel
usedBixiBikesharingServicesInLast30Days
usedBixiBikesharingServicesInLast6Months
usedCommunautoCarsharingServicesAsADriverInLast6Months
usedTransitInLast30Days
useParatransit
usualSchoolPlaceParkingType
usualWorkPlaceIsHome
usualWorkPlaceParkingType
usualWorkPlaceUsageAtLeastOnceAWeek
usualWorkPlaceWasHomeBeforeThePandemic
whoAnsweredForThisPerson
whoWillAnswerForThisPerson
workerAndStudentType
workingPlace
workOnTheRoad
worksFromFixedLocation
workTripsDaysCountPerWeek
workType
usualSchoolPlace
usualSchoolPlace.geography
usualSchoolPlace.geography.geometry.coordinates.#
usualSchoolPlace.geography.geometry.type
usualSchoolPlace.geography.id
usualSchoolPlace.geography.properties.geocodingQueryString
usualSchoolPlace.geography.properties.geocodingResultsData.formatted_address
usualSchoolPlace.geography.properties.geocodingResultsData.place_id
usualSchoolPlace.geography.properties.geocodingResultsData.types.#
usualSchoolPlace.geography.properties.lastAction
usualSchoolPlace.geography.properties.platform
usualSchoolPlace.geography.properties.zoom
usualSchoolPlace.geography.type
usualSchoolPlace.geometry.coordinates.#
usualSchoolPlace.geometry.type
usualSchoolPlace.id
usualSchoolPlace.name
usualSchoolPlace.properties.geocodingQueryString
usualSchoolPlace.properties.lastAction
usualSchoolPlace.properties.zoom
usualSchoolPlace.type
usualSchoolPlaceName // move to usualSchoolPlace.name
usualStudyPlaceName // move to usualSchoolPlace.name
usualStudyPlaceNameGeographie.geometry.coordinates.# // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.geometry.type // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.id // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.properties.geocodingQueryString // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.properties.geocodingResultsData.formatted_address // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.properties.geocodingResultsData.place_id // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.properties.geocodingResultsData.types.# // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.properties.lastAction // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.properties.zoom // incorrect naming, move to usualSchoolPlace.geography
usualStudyPlaceNameGeographie.type // incorrect naming, move to usualSchoolPlace.geography
usualWorkPlace
usualWorkPlace.geography
usualWorkPlace.geography.geometry.coordinates.#
usualWorkPlace.geography.geometry.type
usualWorkPlace.geography.id
usualWorkPlace.geography.properties.geocodingQueryString
usualWorkPlace.geography.properties.geocodingResultsData.formatted_address
usualWorkPlace.geography.properties.geocodingResultsData.place_id
usualWorkPlace.geography.properties.geocodingResultsData.types.#
usualWorkPlace.geography.properties.lastAction
usualWorkPlace.geography.properties.platform
usualWorkPlace.geography.properties.zoom
usualWorkPlace.geography.type
usualWorkPlace.geometry.coordinates.#
usualWorkPlace.geometry.type
usualWorkPlace.id
usualWorkPlace.name
usualWorkPlace.properties.geocodingQueryString
usualWorkPlace.properties.lastAction
usualWorkPlace.properties.zoom
usualWorkPlace.type
usualWorkPlaceName // move to usualWorkPlace.name
usualWorkPlaceNameGeographie // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.geometry.coordinates.# // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.geometry.type // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.id // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.properties.geocodingQueryString // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.properties.geocodingResultsData.formatted_address // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.properties.geocodingResultsData.place_id // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.properties.geocodingResultsData.types.# // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.properties.lastAction // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.properties.zoom // incorrect naming, move to usualWorkPlace.geography
usualWorkPlaceNameGeographie.type // incorrect naming, move to usualWorkPlace.geography
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment