From 37d7b67a05b9cc2bdbf836c9ddb2ae5e6ff1301b Mon Sep 17 00:00:00 2001 From: Landon Fackrell <128620767+LandonSmarty@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:59:58 -0700 Subject: [PATCH] Landon/us enrichment (#36) Complete enrichment SDK and fix other tests --- Sources/SmartyStreets/ClientBuilder.swift | 6 + .../LookupTypes/EnrichmentLookup.swift | 29 ++ .../PropertyFinancialEnrichmentLookup.swift | 17 + .../PropertyPrincipalEnrichmentLookup.swift | 15 + .../FinancialAttributes.swift | 131 +++++ .../FinancialHistoryEntry.swift | 61 +++ .../PropertyFinancial/FinancialResult.swift | 13 + .../PropertyFinancialSerializer.swift | 46 ++ .../PrincipalAttributes.swift | 448 ++++++++++++++++++ .../PropertyPrincipal/PrincipalResult.swift | 13 + .../PropertyPrincipalSerializer.swift | 46 ++ .../USEnrichment/USEnrichmentClient.swift | 68 +++ .../USReverseGeo/USReverseGeoSerializer.swift | 1 + .../USStreet/USStreetSerializer.swift | 1 + .../USZipCode/USZipCodeSerializer.swift | 1 + .../SmartyStreetsTests/SerializerTests.swift | 2 +- .../FinancialResultTest.swift | 200 ++++++++ .../PrincipalResultTest.swift | 421 ++++++++++++++++ .../USReverseGeoSerializerTests.swift | 2 +- .../USStreetCandidateTests.swift | 2 +- .../SwiftUSEnrichmentExample.swift | 105 ++++ .../swiftExamples/USEnrichmentExample.swift | 79 +++ samples/Sources/swiftExamples/main.swift | 1 + 23 files changed, 1705 insertions(+), 3 deletions(-) create mode 100644 Sources/SmartyStreets/USEnrichment/LookupTypes/EnrichmentLookup.swift create mode 100644 Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyFinancialEnrichmentLookup.swift create mode 100644 Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyPrincipalEnrichmentLookup.swift create mode 100644 Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialAttributes.swift create mode 100644 Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialHistoryEntry.swift create mode 100644 Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialResult.swift create mode 100644 Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/PropertyFinancialSerializer.swift create mode 100644 Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalAttributes.swift create mode 100644 Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalResult.swift create mode 100644 Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PropertyPrincipalSerializer.swift create mode 100644 Sources/SmartyStreets/USEnrichment/USEnrichmentClient.swift create mode 100644 Tests/SmartyStreetsTests/USEnrichmentTests/FinancialResultTest.swift create mode 100644 Tests/SmartyStreetsTests/USEnrichmentTests/PrincipalResultTest.swift create mode 100644 UISamples/UISamples/SwiftSamples/SwiftUSEnrichmentExample.swift create mode 100644 samples/Sources/swiftExamples/USEnrichmentExample.swift diff --git a/Sources/SmartyStreets/ClientBuilder.swift b/Sources/SmartyStreets/ClientBuilder.swift index 1e5812d..b73f0a7 100644 --- a/Sources/SmartyStreets/ClientBuilder.swift +++ b/Sources/SmartyStreets/ClientBuilder.swift @@ -22,6 +22,7 @@ import Foundation var usStreetApiURL:String = "https://us-street.api.smarty.com/street-address" var usZipCodeApiURL:String = "https://us-zipcode.api.smarty.com/lookup" var usReverseGeoApiURL:String = "https://us-reverse-geo.api.smarty.com/lookup" + var usEnrichemntApiURL:String = "https://us-enrichment.api.smarty.com/lookup" override init() { self.serializer = SmartySerializer() @@ -164,6 +165,11 @@ import Foundation return USReverseGeoClient(sender: buildSender(), serializer: serializer) } + public func buildUsEnrichmentApiClient() -> USEnrichmentClient { + ensureURLPrefixNotNil(url: self.usEnrichemntApiURL) + return USEnrichmentClient(sender: buildSender()) + } + func buildSender() -> SmartySender { if let httpSender = self.sender { return httpSender diff --git a/Sources/SmartyStreets/USEnrichment/LookupTypes/EnrichmentLookup.swift b/Sources/SmartyStreets/USEnrichment/LookupTypes/EnrichmentLookup.swift new file mode 100644 index 0000000..d93c913 --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/LookupTypes/EnrichmentLookup.swift @@ -0,0 +1,29 @@ +import Foundation + +public class EnrichmentLookup: Encodable { + private let smarty_key: String + private let data_set_name: String + private let data_subset_name: String + + public init(smartyKey: String, datasetName: String, dataSubsetName: String) { + self.smarty_key = smartyKey + self.data_set_name = datasetName + self.data_subset_name = dataSubsetName + } + + public func getSmartyKey() -> String { + return smarty_key + } + + public func getDatasetName() -> String { + return data_set_name + } + + public func getDataSubsetName() -> String { + return data_subset_name + } + + public func deserializeAndSetResults(serializer: SmartySerializer, payload: Data, error: UnsafeMutablePointer) { + fatalError("You must use a Lookup subclass with an implemented version of deserializeAndSetResults") + } +} diff --git a/Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyFinancialEnrichmentLookup.swift b/Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyFinancialEnrichmentLookup.swift new file mode 100644 index 0000000..51b08ac --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyFinancialEnrichmentLookup.swift @@ -0,0 +1,17 @@ +import Foundation + +public class PropertyFinancialEnrichmentLookup: EnrichmentLookup { + + public var results:[FinancialResult]? + + init(smartyKey: String){ + self.results = nil + super.init(smartyKey: smartyKey, datasetName: "property", dataSubsetName: "financial") + } + + override public func deserializeAndSetResults(serializer: SmartySerializer, payload: Data, error: UnsafeMutablePointer) { + self.results = serializer.Deserialize(payload: payload, error: &error.pointee) as? [FinancialResult] + } + + +} diff --git a/Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyPrincipalEnrichmentLookup.swift b/Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyPrincipalEnrichmentLookup.swift new file mode 100644 index 0000000..7a4e741 --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/LookupTypes/PropertyPrincipalEnrichmentLookup.swift @@ -0,0 +1,15 @@ +import Foundation + +public class PropertyPrincipalEnrichmentLookup: EnrichmentLookup { + + public var results:[PrincipalResult]? + + init(smartyKey: String){ + self.results = nil + super.init(smartyKey: smartyKey, datasetName: "property", dataSubsetName: "principal") + } + + override public func deserializeAndSetResults(serializer: SmartySerializer, payload: Data, error: UnsafeMutablePointer) { + self.results = serializer.Deserialize(payload: payload, error: &error.pointee) as? [PrincipalResult] + } +} diff --git a/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialAttributes.swift b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialAttributes.swift new file mode 100644 index 0000000..e7d4c4f --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialAttributes.swift @@ -0,0 +1,131 @@ +import Foundation + +public struct FinancialAttributes: Codable { + let assessedImprovementPercent, assessedImprovementValue, assessedLandValue, assessedValue: String? + let assessorLastUpdate, assessorTaxrollUpdate, contactCity, contactCrrt: String? + let contactFullAddress, contactHouseNumber, contactMailInfoFormat, contactMailInfoPrivacy: String? + let contactMailingCounty, contactMailingFIPS, contactPostDirection, contactPreDirection: String? + let contactState, contactStreetName, contactSuffix, contactUnitDesignator: String? + let contactValue, contactZip, contactZip4, deedDocumentBook: String? + let deedDocumentNumber, deedDocumentPage, deedOwnerFirstName, deedOwnerFirstName2: String? + let deedOwnerFirstName3, deedOwnerFirstName4, deedOwnerFullName, deedOwnerFullName2: String? + let deedOwnerFullName3, deedOwnerFullName4, deedOwnerLastName, deedOwnerLastName2: String? + let deedOwnerLastName3, deedOwnerLastName4, deedOwnerMiddleName, deedOwnerMiddleName2: String? + let deedOwnerMiddleName3, deedOwnerMiddleName4, deedOwnerSuffix, deedOwnerSuffix2: String? + let deedOwnerSuffix3, deedOwnerSuffix4, deedSaleDate, deedSalePrice: String? + let deedTransactionID, disabledTaxExemption: String? + let financialHistory: [FinancialHistoryEntry] + let firstName, firstName2, firstName3, firstName4: String? + let homeownerTaxExemption, lastName, lastName2, lastName3: String? + let lastName4, marketImprovementPercent, marketImprovementValue, marketLandValue: String? + let marketValueYear, matchType, middleName, middleName2: String? + let middleName3, middleName4, otherTaxExemption, ownerFullName: String? + let ownerFullName2, ownerFullName3, ownerFullName4, ownershipTransferDate: String? + let ownershipTransferDocNumber, ownershipTransferTransactionID, ownershipType, ownershipType2: String? + let previousAssessedValue, priorSaleAmount, priorSaleDate, saleAmount: String? + let saleDate, seniorTaxExemption, suffix, suffix2: String? + let suffix3, suffix4, taxAssessYear, taxBilledAmount: String? + let taxDelinquentYear, taxFiscalYear, taxRateArea, totalMarketValue: String? + let trustDescription, veteranTaxExemption, widowTaxExemption: String? + + enum CodingKeys: String, CodingKey { + case assessedImprovementPercent = "assessed_improvement_percent" + case assessedImprovementValue = "assessed_improvement_value" + case assessedLandValue = "assessed_land_value" + case assessedValue = "assessed_value" + case assessorLastUpdate = "assessor_last_update" + case assessorTaxrollUpdate = "assessor_taxroll_update" + case contactCity = "contact_city" + case contactCrrt = "contact_crrt" + case contactFullAddress = "contact_full_address" + case contactHouseNumber = "contact_house_number" + case contactMailInfoFormat = "contact_mail_info_format" + case contactMailInfoPrivacy = "contact_mail_info_privacy" + case contactMailingCounty = "contact_mailing_county" + case contactMailingFIPS = "contact_mailing_fips" + case contactPostDirection = "contact_post_direction" + case contactPreDirection = "contact_pre_direction" + case contactState = "contact_state" + case contactStreetName = "contact_street_name" + case contactSuffix = "contact_suffix" + case contactUnitDesignator = "contact_unit_designator" + case contactValue = "contact_value" + case contactZip = "contact_zip" + case contactZip4 = "contact_zip4" + case deedDocumentBook = "deed_document_book" + case deedDocumentNumber = "deed_document_number" + case deedDocumentPage = "deed_document_page" + case deedOwnerFirstName = "deed_owner_first_name" + case deedOwnerFirstName2 = "deed_owner_first_name2" + case deedOwnerFirstName3 = "deed_owner_first_name3" + case deedOwnerFirstName4 = "deed_owner_first_name4" + case deedOwnerFullName = "deed_owner_full_name" + case deedOwnerFullName2 = "deed_owner_full_name2" + case deedOwnerFullName3 = "deed_owner_full_name3" + case deedOwnerFullName4 = "deed_owner_full_name4" + case deedOwnerLastName = "deed_owner_last_name" + case deedOwnerLastName2 = "deed_owner_last_name2" + case deedOwnerLastName3 = "deed_owner_last_name3" + case deedOwnerLastName4 = "deed_owner_last_name4" + case deedOwnerMiddleName = "deed_owner_middle_name" + case deedOwnerMiddleName2 = "deed_owner_middle_name2" + case deedOwnerMiddleName3 = "deed_owner_middle_name3" + case deedOwnerMiddleName4 = "deed_owner_middle_name4" + case deedOwnerSuffix = "deed_owner_suffix" + case deedOwnerSuffix2 = "deed_owner_suffix2" + case deedOwnerSuffix3 = "deed_owner_suffix3" + case deedOwnerSuffix4 = "deed_owner_suffix4" + case deedSaleDate = "deed_sale_date" + case deedSalePrice = "deed_sale_price" + case deedTransactionID = "deed_transaction_id" + case disabledTaxExemption = "disabled_tax_exemption" + case financialHistory = "financial_history" + case firstName = "first_name" + case firstName2 = "first_name_2" + case firstName3 = "first_name_3" + case firstName4 = "first_name_4" + case homeownerTaxExemption = "homeowner_tax_exemption" + case lastName = "last_name" + case lastName2 = "last_name_2" + case lastName3 = "last_name_3" + case lastName4 = "last_name_4" + case marketImprovementPercent = "market_improvement_percent" + case marketImprovementValue = "market_improvement_value" + case marketLandValue = "market_land_value" + case marketValueYear = "market_value_year" + case matchType = "match_type" + case middleName = "middle_name" + case middleName2 = "middle_name_2" + case middleName3 = "middle_name_3" + case middleName4 = "middle_name_4" + case otherTaxExemption = "other_tax_exemption" + case ownerFullName = "owner_full_name" + case ownerFullName2 = "owner_full_name_2" + case ownerFullName3 = "owner_full_name_3" + case ownerFullName4 = "owner_full_name_4" + case ownershipTransferDate = "ownership_transfer_date" + case ownershipTransferDocNumber = "ownership_transfer_doc_number" + case ownershipTransferTransactionID = "ownership_transfer_transaction_id" + case ownershipType = "ownership_type" + case ownershipType2 = "ownership_type_2" + case previousAssessedValue = "previous_assessed_value" + case priorSaleAmount = "prior_sale_amount" + case priorSaleDate = "prior_sale_date" + case saleAmount = "sale_amount" + case saleDate = "sale_date" + case seniorTaxExemption = "senior_tax_exemption" + case suffix + case suffix2 = "suffix_2" + case suffix3 = "suffix_3" + case suffix4 = "suffix_4" + case taxAssessYear = "tax_assess_year" + case taxBilledAmount = "tax_billed_amount" + case taxDelinquentYear = "tax_delinquent_year" + case taxFiscalYear = "tax_fiscal_year" + case taxRateArea = "tax_rate_area" + case totalMarketValue = "total_market_value" + case trustDescription = "trust_description" + case veteranTaxExemption = "veteran_tax_exemption" + case widowTaxExemption = "widow_tax_exemption" + } +} diff --git a/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialHistoryEntry.swift b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialHistoryEntry.swift new file mode 100644 index 0000000..877e4c5 --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialHistoryEntry.swift @@ -0,0 +1,61 @@ +import Foundation + +public struct FinancialHistoryEntry: Codable { + let codeTitleCompany, documentTypeDescription, instrumentDate, interestRateType2: String? + let lenderAddress, lenderAddress2, lenderCity, lenderCity2: String? + let lenderCode2, lenderFirstName, lenderFirstName2, lenderLastName: String? + let lenderLastName2, lenderName, lenderName2, lenderSellerCarryBack: String? + let lenderSellerCarryBack2, lenderState, lenderState2, lenderZip: String? + let lenderZip2, lenderZipExtended, lenderZipExtended2, mortgageAmount: String? + let mortgageAmount2, mortgageDueDate, mortgageDueDate2, mortgageInterestRate: String? + let mortgageInterestRateType, mortgageLenderCode, mortgageRate2, mortgageRecordingDate: String? + let mortgageRecordingDate2, mortgageTerm, mortgageTerm2, mortgageTermType: String? + let mortgageTermType2, mortgageType, mortgageType2, multiParcelFlag: String? + let nameTitleCompany, recordingDate, transferAmount: String? + + enum CodingKeys: String, CodingKey { + case codeTitleCompany = "code_title_company" + case documentTypeDescription = "document_type_description" + case instrumentDate = "instrument_date" + case interestRateType2 = "interest_rate_type_2" + case lenderAddress = "lender_address" + case lenderAddress2 = "lender_address_2" + case lenderCity = "lender_city" + case lenderCity2 = "lender_city_2" + case lenderCode2 = "lender_code_2" + case lenderFirstName = "lender_first_name" + case lenderFirstName2 = "lender_first_name_2" + case lenderLastName = "lender_last_name" + case lenderLastName2 = "lender_last_name_2" + case lenderName = "lender_name" + case lenderName2 = "lender_name_2" + case lenderSellerCarryBack = "lender_seller_carry_back" + case lenderSellerCarryBack2 = "lender_seller_carry_back_2" + case lenderState = "lender_state" + case lenderState2 = "lender_state_2" + case lenderZip = "lender_zip" + case lenderZip2 = "lender_zip_2" + case lenderZipExtended = "lender_zip_extended" + case lenderZipExtended2 = "lender_zip_extended_2" + case mortgageAmount = "mortgage_amount" + case mortgageAmount2 = "mortgage_amount_2" + case mortgageDueDate = "mortgage_due_date" + case mortgageDueDate2 = "mortgage_due_date_2" + case mortgageInterestRate = "mortgage_interest_rate" + case mortgageInterestRateType = "mortgage_interest_rate_type" + case mortgageLenderCode = "mortgage_lender_code" + case mortgageRate2 = "mortgage_rate_2" + case mortgageRecordingDate = "mortgage_recording_date" + case mortgageRecordingDate2 = "mortgage_recording_date_2" + case mortgageTerm = "mortgage_term" + case mortgageTerm2 = "mortgage_term_2" + case mortgageTermType = "mortgage_term_type" + case mortgageTermType2 = "mortgage_term_type_2" + case mortgageType = "mortgage_type" + case mortgageType2 = "mortgage_type_2" + case multiParcelFlag = "multi_parcel_flag" + case nameTitleCompany = "name_title_company" + case recordingDate = "recording_date" + case transferAmount = "transfer_amount" + } +} diff --git a/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialResult.swift b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialResult.swift new file mode 100644 index 0000000..d15b271 --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/FinancialResult.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct FinancialResult: Codable { + let smartyKey, dataSetName, dataSubsetName: String + let attributes: FinancialAttributes + + enum CodingKeys: String, CodingKey { + case smartyKey = "smarty_key" + case dataSetName = "data_set_name" + case dataSubsetName = "data_subset_name" + case attributes + } +} diff --git a/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/PropertyFinancialSerializer.swift b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/PropertyFinancialSerializer.swift new file mode 100644 index 0000000..c4b906e --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyFinancial/PropertyFinancialSerializer.swift @@ -0,0 +1,46 @@ +import Foundation + + +public class PropertyFinancialSerializer: SmartySerializer { + override func Serialize(obj: Any?, error: inout NSError!) -> Data! { + let raw:PropertyFinancialEnrichmentLookup? = obj as? PropertyFinancialEnrichmentLookup + let smartyErrors = SmartyErrors() + let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = .sortedKeys + if raw == nil { + let details = [NSLocalizedDescriptionKey: "The object to be serialized is nil"] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectNilError.rawValue, userInfo: details) + return nil + } + + do { + let jsonData = try jsonEncoder.encode(raw) as Data + return jsonData + } catch let jsonError { + let details = [NSLocalizedDescriptionKey: jsonError.localizedDescription] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectInvalidTypeError.rawValue, userInfo: details) + } + + + return nil + } + + override public func Deserialize(payload: Data?, error: inout NSError!) -> Any! { + let smartyErrors = SmartyErrors() + let jsonDecoder = JSONDecoder() + if payload == nil { + let details = [NSLocalizedDescriptionKey: "The payload is nil."] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectNilError.rawValue, userInfo: details) + return nil + } + + do { + let result:[FinancialResult] = try jsonDecoder.decode([FinancialResult].self, from: payload!) + return result + } catch let jsonError { + let details = [NSLocalizedDescriptionKey:jsonError.localizedDescription] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectInvalidTypeError.rawValue, userInfo: details) + return nil + } + } +} diff --git a/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalAttributes.swift b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalAttributes.swift new file mode 100644 index 0000000..5b1db2f --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalAttributes.swift @@ -0,0 +1,448 @@ +import Foundation + +public struct PrincipalAttributes: Codable { + let firstFloorSqft, secondFloorSqft, acres, airConditioner, arborPergola: String? + let assessedImprovementPercent, assessedImprovementValue, assessedLandValue, assessedValue: String? + let assessorLastUpdate, assessorTaxrollUpdate, atticArea, atticFlag: String? + let balcony, balconyArea, basementSqft, basementSqftFinished: String? + let basementSqftUnfinished, bathHouse, bathHouseSqft, bathroomsPartial: String? + let bathroomsTotal, bedrooms, block1, block2: String? + let boatAccess, boatHouse, boatHouseSqft, boatLift: String? + let bonusRoom, breakfastNook, breezeway, buildingDefinitionCode: String? + let buildingSqft, cabin, cabinSqft, canopy: String? + let canopySqft, carport, carportSqft, cbsaCode: String? + let cbsaName, cellar, censusBlock, censusBlockGroup: String? + let censusFIPSPlaceCode, censusTract, centralVacuum, codeTitleCompany: String? + let combinedStatisticalArea, communityRec, companyFlag, congressionalDistrict: String? + let constructionType, contactCity, contactCrrt, contactFullAddress: String? + let contactHouseNumber, contactMailInfoFormat, contactMailInfoPrivacy, contactMailingCounty: String? + let contactMailingFIPS, contactPostDirection, contactPreDirection, contactState: String? + let contactStreetName, contactSuffix, contactUnitDesignator, contactValue: String? + let contactZip, contactZip4, courtyard, courtyardArea: String? + let deck, deckArea, deedDocumentBook, deedDocumentNumber: String? + let deedDocumentPage, deedOwnerFirstName, deedOwnerFirstName2, deedOwnerFirstName3: String? + let deedOwnerFirstName4, deedOwnerFullName, deedOwnerFullName2, deedOwnerFullName3: String? + let deedOwnerFullName4, deedOwnerLastName, deedOwnerLastName2, deedOwnerLastName3: String? + let deedOwnerLastName4, deedOwnerMiddleName, deedOwnerMiddleName2, deedOwnerMiddleName3: String? + let deedOwnerMiddleName4, deedOwnerSuffix, deedOwnerSuffix2, deedOwnerSuffix3: String? + let deedOwnerSuffix4, deedSaleDate, deedSalePrice, deedTransactionID: String? + let depthLinearFootage, disabledTaxExemption, documentTypeDescription, drivewaySqft: String? + let drivewayType, effectiveYearBuilt, elevationFeet, elevator: String? + let equestrianArena, escalator, exerciseRoom, exteriorWalls: String? + let familyRoom, fence, fenceArea, fipsCode: String? + let fireResistanceCode, fireSprinklersFlag, fireplace, fireplaceNumber: String? + let firstName, firstName2, firstName3, firstName4: String? + let flooring, foundation, gameRoom, garage: String? + let garageSqft, gazebo, gazeboSqft, golfCourse: String? + let grainery, grainerySqft, greatRoom, greenhouse: String? + let greenhouseSqft, grossSqft, guesthouse, guesthouseSqft: String? + let handicapAccessibility, heat, heatFuelType, hobbyRoom: String? + let homeownerTaxExemption, instrumentDate, intercomSystem, interestRateType2: String? + let interiorStructure, kennel, kennelSqft, landUseCode: String? + let landUseGroup, landUseStandard, lastName, lastName2: String? + let lastName3, lastName4, latitude, laundry: String? + let leanTo, leanToSqft, legalDescription, legalUnit: String? + let lenderAddress, lenderAddress2, lenderCity, lenderCity2: String? + let lenderCode2, lenderFirstName, lenderFirstName2, lenderLastName: String? + let lenderLastName2, lenderName, lenderName2, lenderSellerCarryBack: String? + let lenderSellerCarryBack2, lenderState, lenderState2, lenderZip: String? + let lenderZip2, lenderZipExtended, lenderZipExtended2, loadingPlatform: String? + let loadingPlatformSqft, longitude, lot1, lot2: String? + let lot3, lotSqft, marketImprovementPercent, marketImprovementValue: String? + let marketLandValue, marketValueYear, matchType, mediaRoom: String? + let metroDivision, middleName, middleName2, middleName3: String? + let middleName4, milkhouse, milkhouseSqft, minorCivilDivisionCode: String? + let minorCivilDivisionName, mobileHomeHookup, mortgageAmount, mortgageAmount2: String? + let mortgageDueDate, mortgageDueDate2, mortgageInterestRate, mortgageInterestRateType: String? + let mortgageLenderCode, mortgageRate2, mortgageRecordingDate, mortgageRecordingDate2: String? + let mortgageTerm, mortgageTerm2, mortgageTermType, mortgageTermType2: String? + let mortgageType, mortgageType2, msaCode, msaName: String? + let mudRoom, multiParcelFlag, nameTitleCompany, neighborhoodCode: String? + let numberOfBuildings, office, officeSqft, otherTaxExemption: String? + let outdoorKitchenFireplace, overheadDoor, ownerFullName, ownerFullName2: String? + let ownerFullName3, ownerFullName4, ownerOccupancyStatus, ownershipTransferDate: String? + let ownershipTransferDocNumber, ownershipTransferTransactionID, ownershipType, ownershipType2: String? + let ownershipVestingRelationCode, parcelAccountNumber, parcelMapBook, parcelMapPage: String? + let parcelNumberAlternate, parcelNumberFormatted, parcelNumberPrevious, parcelNumberYearAdded: String? + let parcelNumberYearChange, parcelRawNumber, parcelShellRecord, parkingSpaces: String? + let patioArea, phaseName, plumbingFixturesCount, poleStruct: String? + let poleStructSqft, pond, pool, poolArea: String? + let poolhouse, poolhouseSqft, porch, porchArea: String? + let poultryHouse, poultryHouseSqft, previousAssessedValue, priorSaleAmount: String? + let priorSaleDate, propertyAddressCarrierRouteCode, propertyAddressCity, propertyAddressFull: String? + let propertyAddressHouseNumber, propertyAddressPostDirection, propertyAddressPreDirection, propertyAddressState: String? + let propertyAddressStreetName, propertyAddressStreetSuffix, propertyAddressUnitDesignator, propertyAddressUnitValue: String? + let propertyAddressZip4, propertyAddressZipcode, publicationDate, quarter: String? + let quarterQuarter, quonset, quonsetSqft, range: String? + let recordingDate, roofCover, roofFrame, rooms: String? + let rvParking, safeRoom, saleAmount, saleDate: String? + let sauna, section, securityAlarm, seniorTaxExemption: String? + let sewerType, shed, shedSqft, silo: String? + let siloSqft, sittingRoom, situsCounty, situsState: String? + let soundSystem, sportsCourt, sprinklers, stable: String? + let stableSqft, storageBuilding, storageBuildingSqft, storiesNumber: String? + let stormShelter, stormShutter, structureStyle, study: String? + let subdivision, suffix, suffix2, suffix3: String? + let suffix4, sunroom, taxAssessYear, taxBilledAmount: String? + let taxDelinquentYear, taxFiscalYear, taxJurisdiction, taxRateArea: String? + let tennisCourt, topographyCode, totalMarketValue, township: String? + let tractNumber, transferAmount, trustDescription, unitCount: String? + let upperFloorsSqft, utility, utilityBuilding, utilityBuildingSqft: String? + let utilitySqft, veteranTaxExemption, viewDescription, waterFeature: String? + let waterServiceType, wetBar, widowTaxExemption, widthLinearFootage: String? + let wineCellar, yearBuilt, zoning: String? + + enum CodingKeys: String, CodingKey { + case firstFloorSqft = "1st_floor_sqft" + case secondFloorSqft = "2nd_floor_sqft" + case acres + case airConditioner = "air_conditioner" + case arborPergola = "arbor_pergola" + case assessedImprovementPercent = "assessed_improvement_percent" + case assessedImprovementValue = "assessed_improvement_value" + case assessedLandValue = "assessed_land_value" + case assessedValue = "assessed_value" + case assessorLastUpdate = "assessor_last_update" + case assessorTaxrollUpdate = "assessor_taxroll_update" + case atticArea = "attic_area" + case atticFlag = "attic_flag" + case balcony + case balconyArea = "balcony_area" + case basementSqft = "basement_sqft" + case basementSqftFinished = "basement_sqft_finished" + case basementSqftUnfinished = "basement_sqft_unfinished" + case bathHouse = "bath_house" + case bathHouseSqft = "bath_house_sqft" + case bathroomsPartial = "bathrooms_partial" + case bathroomsTotal = "bathrooms_total" + case bedrooms, block1, block2 + case boatAccess = "boat_access" + case boatHouse = "boat_house" + case boatHouseSqft = "boat_house_sqft" + case boatLift = "boat_lift" + case bonusRoom = "bonus_room" + case breakfastNook = "breakfast_nook" + case breezeway + case buildingDefinitionCode = "building_definition_code" + case buildingSqft = "building_sqft" + case cabin + case cabinSqft = "cabin_sqft" + case canopy + case canopySqft = "canopy_sqft" + case carport + case carportSqft = "carport_sqft" + case cbsaCode = "cbsa_code" + case cbsaName = "cbsa_name" + case cellar + case censusBlock = "census_block" + case censusBlockGroup = "census_block_group" + case censusFIPSPlaceCode = "census_fips_place_code" + case censusTract = "census_tract" + case centralVacuum = "central_vacuum" + case codeTitleCompany = "code_title_company" + case combinedStatisticalArea = "combined_statistical_area" + case communityRec = "community_rec" + case companyFlag = "company_flag" + case congressionalDistrict = "congressional_district" + case constructionType = "construction_type" + case contactCity = "contact_city" + case contactCrrt = "contact_crrt" + case contactFullAddress = "contact_full_address" + case contactHouseNumber = "contact_house_number" + case contactMailInfoFormat = "contact_mail_info_format" + case contactMailInfoPrivacy = "contact_mail_info_privacy" + case contactMailingCounty = "contact_mailing_county" + case contactMailingFIPS = "contact_mailing_fips" + case contactPostDirection = "contact_post_direction" + case contactPreDirection = "contact_pre_direction" + case contactState = "contact_state" + case contactStreetName = "contact_street_name" + case contactSuffix = "contact_suffix" + case contactUnitDesignator = "contact_unit_designator" + case contactValue = "contact_value" + case contactZip = "contact_zip" + case contactZip4 = "contact_zip4" + case courtyard + case courtyardArea = "courtyard_area" + case deck + case deckArea = "deck_area" + case deedDocumentBook = "deed_document_book" + case deedDocumentNumber = "deed_document_number" + case deedDocumentPage = "deed_document_page" + case deedOwnerFirstName = "deed_owner_first_name" + case deedOwnerFirstName2 = "deed_owner_first_name2" + case deedOwnerFirstName3 = "deed_owner_first_name3" + case deedOwnerFirstName4 = "deed_owner_first_name4" + case deedOwnerFullName = "deed_owner_full_name" + case deedOwnerFullName2 = "deed_owner_full_name2" + case deedOwnerFullName3 = "deed_owner_full_name3" + case deedOwnerFullName4 = "deed_owner_full_name4" + case deedOwnerLastName = "deed_owner_last_name" + case deedOwnerLastName2 = "deed_owner_last_name2" + case deedOwnerLastName3 = "deed_owner_last_name3" + case deedOwnerLastName4 = "deed_owner_last_name4" + case deedOwnerMiddleName = "deed_owner_middle_name" + case deedOwnerMiddleName2 = "deed_owner_middle_name2" + case deedOwnerMiddleName3 = "deed_owner_middle_name3" + case deedOwnerMiddleName4 = "deed_owner_middle_name4" + case deedOwnerSuffix = "deed_owner_suffix" + case deedOwnerSuffix2 = "deed_owner_suffix2" + case deedOwnerSuffix3 = "deed_owner_suffix3" + case deedOwnerSuffix4 = "deed_owner_suffix4" + case deedSaleDate = "deed_sale_date" + case deedSalePrice = "deed_sale_price" + case deedTransactionID = "deed_transaction_id" + case depthLinearFootage = "depth_linear_footage" + case disabledTaxExemption = "disabled_tax_exemption" + case documentTypeDescription = "document_type_description" + case drivewaySqft = "driveway_sqft" + case drivewayType = "driveway_type" + case effectiveYearBuilt = "effective_year_built" + case elevationFeet = "elevation_feet" + case elevator + case equestrianArena = "equestrian_arena" + case escalator + case exerciseRoom = "exercise_room" + case exteriorWalls = "exterior_walls" + case familyRoom = "family_room" + case fence + case fenceArea = "fence_area" + case fipsCode = "fips_code" + case fireResistanceCode = "fire_resistance_code" + case fireSprinklersFlag = "fire_sprinklers_flag" + case fireplace + case fireplaceNumber = "fireplace_number" + case firstName = "first_name" + case firstName2 = "first_name_2" + case firstName3 = "first_name_3" + case firstName4 = "first_name_4" + case flooring, foundation + case gameRoom = "game_room" + case garage + case garageSqft = "garage_sqft" + case gazebo + case gazeboSqft = "gazebo_sqft" + case golfCourse = "golf_course" + case grainery + case grainerySqft = "grainery_sqft" + case greatRoom = "great_room" + case greenhouse + case greenhouseSqft = "greenhouse_sqft" + case grossSqft = "gross_sqft" + case guesthouse + case guesthouseSqft = "guesthouse_sqft" + case handicapAccessibility = "handicap_accessibility" + case heat + case heatFuelType = "heat_fuel_type" + case hobbyRoom = "hobby_room" + case homeownerTaxExemption = "homeowner_tax_exemption" + case instrumentDate = "instrument_date" + case intercomSystem = "intercom_system" + case interestRateType2 = "interest_rate_type_2" + case interiorStructure = "interior_structure" + case kennel + case kennelSqft = "kennel_sqft" + case landUseCode = "land_use_code" + case landUseGroup = "land_use_group" + case landUseStandard = "land_use_standard" + case lastName = "last_name" + case lastName2 = "last_name_2" + case lastName3 = "last_name_3" + case lastName4 = "last_name_4" + case latitude, laundry + case leanTo = "lean_to" + case leanToSqft = "lean_to_sqft" + case legalDescription = "legal_description" + case legalUnit = "legal_unit" + case lenderAddress = "lender_address" + case lenderAddress2 = "lender_address_2" + case lenderCity = "lender_city" + case lenderCity2 = "lender_city_2" + case lenderCode2 = "lender_code_2" + case lenderFirstName = "lender_first_name" + case lenderFirstName2 = "lender_first_name_2" + case lenderLastName = "lender_last_name" + case lenderLastName2 = "lender_last_name_2" + case lenderName = "lender_name" + case lenderName2 = "lender_name_2" + case lenderSellerCarryBack = "lender_seller_carry_back" + case lenderSellerCarryBack2 = "lender_seller_carry_back_2" + case lenderState = "lender_state" + case lenderState2 = "lender_state_2" + case lenderZip = "lender_zip" + case lenderZip2 = "lender_zip_2" + case lenderZipExtended = "lender_zip_extended" + case lenderZipExtended2 = "lender_zip_extended_2" + case loadingPlatform = "loading_platform" + case loadingPlatformSqft = "loading_platform_sqft" + case longitude + case lot1 = "lot_1" + case lot2 = "lot_2" + case lot3 = "lot_3" + case lotSqft = "lot_sqft" + case marketImprovementPercent = "market_improvement_percent" + case marketImprovementValue = "market_improvement_value" + case marketLandValue = "market_land_value" + case marketValueYear = "market_value_year" + case matchType = "match_type" + case mediaRoom = "media_room" + case metroDivision = "metro_division" + case middleName = "middle_name" + case middleName2 = "middle_name_2" + case middleName3 = "middle_name_3" + case middleName4 = "middle_name_4" + case milkhouse + case milkhouseSqft = "milkhouse_sqft" + case minorCivilDivisionCode = "minor_civil_division_code" + case minorCivilDivisionName = "minor_civil_division_name" + case mobileHomeHookup = "mobile_home_hookup" + case mortgageAmount = "mortgage_amount" + case mortgageAmount2 = "mortgage_amount_2" + case mortgageDueDate = "mortgage_due_date" + case mortgageDueDate2 = "mortgage_due_date_2" + case mortgageInterestRate = "mortgage_interest_rate" + case mortgageInterestRateType = "mortgage_interest_rate_type" + case mortgageLenderCode = "mortgage_lender_code" + case mortgageRate2 = "mortgage_rate_2" + case mortgageRecordingDate = "mortgage_recording_date" + case mortgageRecordingDate2 = "mortgage_recording_date_2" + case mortgageTerm = "mortgage_term" + case mortgageTerm2 = "mortgage_term_2" + case mortgageTermType = "mortgage_term_type" + case mortgageTermType2 = "mortgage_term_type_2" + case mortgageType = "mortgage_type" + case mortgageType2 = "mortgage_type_2" + case msaCode = "msa_code" + case msaName = "msa_name" + case mudRoom = "mud_room" + case multiParcelFlag = "multi_parcel_flag" + case nameTitleCompany = "name_title_company" + case neighborhoodCode = "neighborhood_code" + case numberOfBuildings = "number_of_buildings" + case office + case officeSqft = "office_sqft" + case otherTaxExemption = "other_tax_exemption" + case outdoorKitchenFireplace = "outdoor_kitchen_fireplace" + case overheadDoor = "overhead_door" + case ownerFullName = "owner_full_name" + case ownerFullName2 = "owner_full_name_2" + case ownerFullName3 = "owner_full_name_3" + case ownerFullName4 = "owner_full_name_4" + case ownerOccupancyStatus = "owner_occupancy_status" + case ownershipTransferDate = "ownership_transfer_date" + case ownershipTransferDocNumber = "ownership_transfer_doc_number" + case ownershipTransferTransactionID = "ownership_transfer_transaction_id" + case ownershipType = "ownership_type" + case ownershipType2 = "ownership_type_2" + case ownershipVestingRelationCode = "ownership_vesting_relation_code" + case parcelAccountNumber = "parcel_account_number" + case parcelMapBook = "parcel_map_book" + case parcelMapPage = "parcel_map_page" + case parcelNumberAlternate = "parcel_number_alternate" + case parcelNumberFormatted = "parcel_number_formatted" + case parcelNumberPrevious = "parcel_number_previous" + case parcelNumberYearAdded = "parcel_number_year_added" + case parcelNumberYearChange = "parcel_number_year_change" + case parcelRawNumber = "parcel_raw_number" + case parcelShellRecord = "parcel_shell_record" + case parkingSpaces = "parking_spaces" + case patioArea = "patio_area" + case phaseName = "phase_name" + case plumbingFixturesCount = "plumbing_fixtures_count" + case poleStruct = "pole_struct" + case poleStructSqft = "pole_struct_sqft" + case pond, pool + case poolArea = "pool_area" + case poolhouse + case poolhouseSqft = "poolhouse_sqft" + case porch + case porchArea = "porch_area" + case poultryHouse = "poultry_house" + case poultryHouseSqft = "poultry_house_sqft" + case previousAssessedValue = "previous_assessed_value" + case priorSaleAmount = "prior_sale_amount" + case priorSaleDate = "prior_sale_date" + case propertyAddressCarrierRouteCode = "property_address_carrier_route_code" + case propertyAddressCity = "property_address_city" + case propertyAddressFull = "property_address_full" + case propertyAddressHouseNumber = "property_address_house_number" + case propertyAddressPostDirection = "property_address_post_direction" + case propertyAddressPreDirection = "property_address_pre_direction" + case propertyAddressState = "property_address_state" + case propertyAddressStreetName = "property_address_street_name" + case propertyAddressStreetSuffix = "property_address_street_suffix" + case propertyAddressUnitDesignator = "property_address_unit_designator" + case propertyAddressUnitValue = "property_address_unit_value" + case propertyAddressZip4 = "property_address_zip_4" + case propertyAddressZipcode = "property_address_zipcode" + case publicationDate = "publication_date" + case quarter + case quarterQuarter = "quarter_quarter" + case quonset + case quonsetSqft = "quonset_sqft" + case range + case recordingDate = "recording_date" + case roofCover = "roof_cover" + case roofFrame = "roof_frame" + case rooms + case rvParking = "rv_parking" + case safeRoom = "safe_room" + case saleAmount = "sale_amount" + case saleDate = "sale_date" + case sauna, section + case securityAlarm = "security_alarm" + case seniorTaxExemption = "senior_tax_exemption" + case sewerType = "sewer_type" + case shed + case shedSqft = "shed_sqft" + case silo + case siloSqft = "silo_sqft" + case sittingRoom = "sitting_room" + case situsCounty = "situs_county" + case situsState = "situs_state" + case soundSystem = "sound_system" + case sportsCourt = "sports_court" + case sprinklers, stable + case stableSqft = "stable_sqft" + case storageBuilding = "storage_building" + case storageBuildingSqft = "storage_building_sqft" + case storiesNumber = "stories_number" + case stormShelter = "storm_shelter" + case stormShutter = "storm_shutter" + case structureStyle = "structure_style" + case study, subdivision, suffix + case suffix2 = "suffix_2" + case suffix3 = "suffix_3" + case suffix4 = "suffix_4" + case sunroom + case taxAssessYear = "tax_assess_year" + case taxBilledAmount = "tax_billed_amount" + case taxDelinquentYear = "tax_delinquent_year" + case taxFiscalYear = "tax_fiscal_year" + case taxJurisdiction = "tax_jurisdiction" + case taxRateArea = "tax_rate_area" + case tennisCourt = "tennis_court" + case topographyCode = "topography_code" + case totalMarketValue = "total_market_value" + case township + case tractNumber = "tract_number" + case transferAmount = "transfer_amount" + case trustDescription = "trust_description" + case unitCount = "unit_count" + case upperFloorsSqft = "upper_floors_sqft" + case utility + case utilityBuilding = "utility_building" + case utilityBuildingSqft = "utility_building_sqft" + case utilitySqft = "utility_sqft" + case veteranTaxExemption = "veteran_tax_exemption" + case viewDescription = "view_description" + case waterFeature = "water_feature" + case waterServiceType = "water_service_type" + case wetBar = "wet_bar" + case widowTaxExemption = "widow_tax_exemption" + case widthLinearFootage = "width_linear_footage" + case wineCellar = "wine_cellar" + case yearBuilt = "year_built" + case zoning + } +} diff --git a/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalResult.swift b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalResult.swift new file mode 100644 index 0000000..5a6c643 --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PrincipalResult.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct PrincipalResult: Codable { + let smartyKey, dataSetName, dataSubsetName: String + let attributes: PrincipalAttributes + + enum CodingKeys: String, CodingKey { + case smartyKey = "smarty_key" + case dataSetName = "data_set_name" + case dataSubsetName = "data_subset_name" + case attributes + } +} diff --git a/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PropertyPrincipalSerializer.swift b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PropertyPrincipalSerializer.swift new file mode 100644 index 0000000..4aaf838 --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/ResultTypes/PropertyPrincipal/PropertyPrincipalSerializer.swift @@ -0,0 +1,46 @@ +import Foundation + + +public class PropertyPrincipalSerializer: SmartySerializer { + override func Serialize(obj: Any?, error: inout NSError!) -> Data! { + let raw:PropertyPrincipalEnrichmentLookup? = obj as? PropertyPrincipalEnrichmentLookup + let smartyErrors = SmartyErrors() + let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = .sortedKeys + if raw == nil { + let details = [NSLocalizedDescriptionKey: "The object to be serialized is nil"] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectNilError.rawValue, userInfo: details) + return nil + } + + do { + let jsonData = try jsonEncoder.encode(raw) as Data + return jsonData + } catch let jsonError { + let details = [NSLocalizedDescriptionKey: jsonError.localizedDescription] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectInvalidTypeError.rawValue, userInfo: details) + } + + + return nil + } + + override public func Deserialize(payload: Data?, error: inout NSError!) -> Any! { + let smartyErrors = SmartyErrors() + let jsonDecoder = JSONDecoder() + if payload == nil { + let details = [NSLocalizedDescriptionKey: "The payload is nil."] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectNilError.rawValue, userInfo: details) + return nil + } + + do { + let result:[PrincipalResult] = try jsonDecoder.decode([PrincipalResult].self, from: payload!) + return result + } catch let jsonError { + let details = [NSLocalizedDescriptionKey:jsonError.localizedDescription] + error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectInvalidTypeError.rawValue, userInfo: details) + return nil + } + } +} diff --git a/Sources/SmartyStreets/USEnrichment/USEnrichmentClient.swift b/Sources/SmartyStreets/USEnrichment/USEnrichmentClient.swift new file mode 100644 index 0000000..edc1f88 --- /dev/null +++ b/Sources/SmartyStreets/USEnrichment/USEnrichmentClient.swift @@ -0,0 +1,68 @@ +import Foundation + +public class USEnrichmentClient: NSObject { + + private var sender:SmartySender + private var propertyPrincipalSerializer:PropertyPrincipalSerializer + private var propertyFinancialSerializer:PropertyFinancialSerializer + + init(sender:Any) { + // Is is recommended to instantiate this class using SSClientBuilder + + self.sender = sender as! SmartySender + self.propertyPrincipalSerializer = PropertyPrincipalSerializer() + self.propertyFinancialSerializer = PropertyFinancialSerializer() + } + + public func sendPropertyFinancialLookup(smartyKey: String, error: UnsafeMutablePointer) -> [FinancialResult]? { + let lookup = PropertyFinancialEnrichmentLookup(smartyKey: smartyKey) + let lookupPointer = UnsafeMutablePointer.allocate(capacity: 1) + lookupPointer.initialize(to: lookup) + _ = send(lookup: lookupPointer, error: error) + lookupPointer.deinitialize(count: 1) + lookupPointer.deallocate() + return lookup.results + } + + public func sendPropertyPrincipalLookup(smartyKey: String, error: UnsafeMutablePointer) -> [PrincipalResult]? { + let lookup = PropertyPrincipalEnrichmentLookup(smartyKey: smartyKey) + let lookupPointer = UnsafeMutablePointer.allocate(capacity: 1) + lookupPointer.initialize(to: lookup) + _ = send(lookup: lookupPointer, error: error) + lookupPointer.deinitialize(count: 1) + lookupPointer.deallocate() + return lookup.results + } + + private func send(lookup: UnsafeMutablePointer, error: UnsafeMutablePointer) -> Bool { + + if error.pointee != nil { return false } + + let request = buildRequest(lookup: lookup.pointee) + + let response = sender.sendRequest(request: request, error: &error.pointee) + if error.pointee != nil { return false } + + var serializer:SmartySerializer? = nil + + if lookup.pointee is PropertyPrincipalEnrichmentLookup { + serializer = self.propertyPrincipalSerializer + } else if lookup.pointee is PropertyFinancialEnrichmentLookup { + serializer = self.propertyFinancialSerializer + } + + if let response = response { + lookup.pointee.deserializeAndSetResults(serializer: serializer!, payload: response.payload, error: error) + } + + if error.pointee != nil { return false } + + return true + } + + func buildRequest(lookup:EnrichmentLookup) -> SmartyRequest { + let request = SmartyRequest() + request.urlPrefix = "/" + lookup.getSmartyKey() + "/" + lookup.getDatasetName() + "/" + lookup.getDataSubsetName() + return request + } +} diff --git a/Sources/SmartyStreets/USReverseGeo/USReverseGeoSerializer.swift b/Sources/SmartyStreets/USReverseGeo/USReverseGeoSerializer.swift index cf1fd33..fc48861 100644 --- a/Sources/SmartyStreets/USReverseGeo/USReverseGeoSerializer.swift +++ b/Sources/SmartyStreets/USReverseGeo/USReverseGeoSerializer.swift @@ -5,6 +5,7 @@ class USReverseGeoSerializer: SmartySerializer { let raw:USReverseGeoLookup? = obj as? USReverseGeoLookup let smartyErrors = SmartyErrors() let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = .sortedKeys if raw == nil { let details = [NSLocalizedDescriptionKey: "The object to be serialized is nil"] error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectNilError.rawValue, userInfo: details) diff --git a/Sources/SmartyStreets/USStreet/USStreetSerializer.swift b/Sources/SmartyStreets/USStreet/USStreetSerializer.swift index 9c274d8..2d63cf6 100644 --- a/Sources/SmartyStreets/USStreet/USStreetSerializer.swift +++ b/Sources/SmartyStreets/USStreet/USStreetSerializer.swift @@ -6,6 +6,7 @@ public class USStreetSerializer: SmartySerializer { let raw:[USStreetLookup]? = obj as? [USStreetLookup] let smartyErrors = SmartyErrors() let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = .sortedKeys if raw == nil { let details = [NSLocalizedDescriptionKey: "The object to be serialized is nil"] error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectNilError.rawValue, userInfo: details) diff --git a/Sources/SmartyStreets/USZipCode/USZipCodeSerializer.swift b/Sources/SmartyStreets/USZipCode/USZipCodeSerializer.swift index 31c3c88..57f83c0 100644 --- a/Sources/SmartyStreets/USZipCode/USZipCodeSerializer.swift +++ b/Sources/SmartyStreets/USZipCode/USZipCodeSerializer.swift @@ -5,6 +5,7 @@ public class USZipCodeSerializer: SmartySerializer { let raw:[USZipCodeLookup]? = obj as? [USZipCodeLookup] let smartyErrors = SmartyErrors() let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = .sortedKeys if raw == nil { let details = [NSLocalizedDescriptionKey: "The object to be serialized is nil"] error = NSError(domain: smartyErrors.SSErrorDomain, code: SmartyErrors.SSErrors.ObjectNilError.rawValue, userInfo: details) diff --git a/Tests/SmartyStreetsTests/SerializerTests.swift b/Tests/SmartyStreetsTests/SerializerTests.swift index 726690d..ecf9ac0 100644 --- a/Tests/SmartyStreetsTests/SerializerTests.swift +++ b/Tests/SmartyStreetsTests/SerializerTests.swift @@ -76,7 +76,7 @@ class SerializerTests: XCTestCase { func testSerialize() { let expectedOutput = """ - [{"state":"02","inputId":"04","city":"01","zipcode":"03"},{"state":"06","inputId":"08","city":"05","zipcode":"07"}] + [{"city":"01","inputId":"04","state":"02","zipcode":"03"},{"city":"05","inputId":"08","state":"06","zipcode":"07"}] """ let lookup1 = USZipCodeLookup(city: "01", state: "02", zipcode: "03", inputId: "04") let lookup2 = USZipCodeLookup(city: "05", state: "06", zipcode: "07", inputId: "08") diff --git a/Tests/SmartyStreetsTests/USEnrichmentTests/FinancialResultTest.swift b/Tests/SmartyStreetsTests/USEnrichmentTests/FinancialResultTest.swift new file mode 100644 index 0000000..bd7c014 --- /dev/null +++ b/Tests/SmartyStreetsTests/USEnrichmentTests/FinancialResultTest.swift @@ -0,0 +1,200 @@ +import XCTest +@testable import SmartyStreets + +class USEnrichmentFinancialResultTest: XCTestCase { + + var expectedJsonInput:String! + var obj:NSDictionary! + var sobj:String! + var error:NSError! + let serializer = PropertyFinancialSerializer() + + override func setUp() { + super.setUp() + expectedJsonInput = """ + {"data_set_name":"property","data_subset_name":"financial","smarty_key":"xxx"} + """ + + sobj = """ + [{"smarty_key":"xxx","data_set_name":"property","data_subset_name":"financial","attributes":{"assessed_improvement_percent":"Assessed_Improvement_Percent","assessed_improvement_value":"Assessed_Improvement_Value","assessed_land_value":"Assessed_Land_Value","assessed_value":"Assessed_Value","assessor_last_update":"Assessor_Last_Update","assessor_taxroll_update":"Assessor_Taxroll_Update","contact_city":"Contact_City","contact_crrt":"Contact_Crrt","contact_full_address":"Contact_Full_Address","contact_house_number":"Contact_House_Number","contact_mail_info_format":"Contact_Mail_Info_Format","contact_mail_info_privacy":"Contact_Mail_Info_Privacy","contact_mailing_county":"Contact_Mailing_County","contact_mailing_fips":"Contact_Mailing_Fips","contact_post_direction":"Contact_Post_Direction","contact_pre_direction":"Contact_PRE_Direction","contact_state":"Contact_State","contact_street_name":"Contact_Street_Name","contact_suffix":"Contact_Suffix","contact_unit_designator":"Contact_Unit_Designator","contact_value":"Contact_Value","contact_zip":"Contact_Zip","contact_zip4":"Contact_Zip4","deed_document_book":"Deed_Document_Book","deed_document_number":"Deed_Document_Number","deed_document_page":"Deed_Document_Page","deed_owner_first_name":"Deed_Owner_First_Name","deed_owner_first_name2":"Deed_Owner_First_Name2","deed_owner_first_name3":"Deed_Owner_First_Name3","deed_owner_first_name4":"Deed_Owner_First_Name4","deed_owner_full_name":"Deed_Owner_Full_Name","deed_owner_full_name2":"Deed_Owner_Full_Name2","deed_owner_full_name3":"Deed_Owner_Full_Name3","deed_owner_full_name4":"Deed_Owner_Full_Name4","deed_owner_last_name":"Deed_Owner_Last_Name","deed_owner_last_name2":"Deed_Owner_Last_Name2","deed_owner_last_name3":"Deed_Owner_Last_Name3","deed_owner_last_name4":"Deed_Owner_Last_Name4","deed_owner_middle_name":"Deed_Owner_Middle_Name","deed_owner_middle_name2":"Deed_Owner_Middle_Name2","deed_owner_middle_name3":"Deed_Owner_Middle_Name3","deed_owner_middle_name4":"Deed_Owner_Middle_Name4","deed_owner_suffix":"Deed_Owner_Suffix","deed_owner_suffix2":"Deed_Owner_Suffix2","deed_owner_suffix3":"Deed_Owner_Suffix3","deed_owner_suffix4":"Deed_Owner_Suffix4","deed_sale_date":"Deed_Sale_Date","deed_sale_price":"Deed_Sale_Price","deed_transaction_id":"Deed_Transaction_ID","disabled_tax_exemption":"Disabled_Tax_Exemption","financial_history":[{"code_title_company":"Code_Title_Company","document_type_description":"Document_Type_Description","instrument_date":"Instrument_Date","interest_rate_type_2":"Interest_Rate_Type_2","lender_address":"Lender_Address","lender_address_2":"Lender_Address_2","lender_city":"Lender_City","lender_city_2":"Lender_City_2","lender_code_2":"Lender_Code_2","lender_first_name":"Lender_First_Name","lender_first_name_2":"Lender_First_Name_2","lender_last_name":"Lender_Last_Name","lender_last_name_2":"Lender_Last_Name_2","lender_name":"Lender_Name","lender_name_2":"Lender_Name_2","lender_seller_carry_back":"Lender_Seller_Carry_Back","lender_seller_carry_back_2":"Lender_Seller_Carry_Back_2","lender_state":"Lender_State","lender_state_2":"Lender_State_2","lender_zip":"Lender_Zip","lender_zip_2":"Lender_Zip_2","lender_zip_extended":"Lender_Zip_Extended","lender_zip_extended_2":"Lender_Zip_Extended_2","mortgage_amount":"Mortgage_Amount","mortgage_amount_2":"Mortgage_Amount_2","mortgage_due_date":"Mortgage_Due_Date","mortgage_due_date_2":"Mortgage_Due_Date_2","mortgage_interest_rate":"Mortgage_Interest_Rate","mortgage_interest_rate_type":"Mortgage_Interest_Rate_Type","mortgage_lender_code":"Mortgage_Lender_Code","mortgage_rate_2":"Mortgage_Rate_2","mortgage_recording_date":"Mortgage_Recording_Date","mortgage_recording_date_2":"Mortgage_Recording_Date_2","mortgage_term":"Mortgage_Term","mortgage_term_2":"Mortgage_Term_2","mortgage_term_type":"Mortgage_Term_Type","mortgage_term_type_2":"Mortgage_Term_Type_2","mortgage_type":"Mortgage_Type","mortgage_type_2":"Mortgage_Type_2","multi_parcel_flag":"Multi_Parcel_Flag","name_title_company":"Name_Title_Company","recording_date":"Recording_Date","transfer_amount":"Transfer_Amount"}],"first_name":"First_Name","first_name_2":"First_Name_2","first_name_3":"First_Name_3","first_name_4":"First_Name_4","homeowner_tax_exemption":"Homeowner_Tax_Exemption","last_name":"Last_Name","last_name_2":"Last_Name_2","last_name_3":"Last_Name_3","last_name_4":"Last_Name_4","market_improvement_percent":"Market_Improvement_Percent","market_improvement_value":"Market_Improvement_Value","market_land_value":"Market_Land_Value","market_value_year":"Market_Value_Year","match_type":"match_type","middle_name":"Middle_Name","middle_name_2":"Middle_Name_2","middle_name_3":"Middle_Name_3","middle_name_4":"Middle_Name_4","other_tax_exemption":"Other_Tax_Exemption","owner_full_name":"Owner_Full_Name","owner_full_name_2":"Owner_Full_Name_2","owner_full_name_3":"Owner_Full_Name_3","owner_full_name_4":"Owner_Full_Name_4","ownership_transfer_date":"Ownership_Transfer_Date","ownership_transfer_doc_number":"Ownership_Transfer_DOC_Number","ownership_transfer_transaction_id":"Ownership_Transfer_Transaction_ID","ownership_type":"Ownership_Type","ownership_type_2":"Ownership_Type_2","previous_assessed_value":"Previous_Assessed_Value","prior_sale_amount":"Prior_Sale_Amount","prior_sale_date":"Prior_Sale_Date","sale_amount":"Sale_Amount","sale_date":"Sale_Date","senior_tax_exemption":"Senior_Tax_Exemption","suffix":"Suffix","suffix_2":"Suffix_2","suffix_3":"Suffix_3","suffix_4":"Suffix_4","tax_assess_year":"Tax_Assess_Year","tax_billed_amount":"Tax_Billed_Amount","tax_delinquent_year":"Tax_Delinquent_Year","tax_fiscal_year":"Tax_Fiscal_Year","tax_rate_area":"Tax_Rate_Area","total_market_value":"Total_Market_Value","trust_description":"Trust_Description","veteran_tax_exemption":"Veteran_Tax_Exemption","widow_tax_exemption":"Widow_Tax_Exemption"}}] + """ + self.error = nil + } + + override func tearDown() { + super.tearDown() + self.error = nil + } + + func testSerialization() { + let lookup = PropertyFinancialEnrichmentLookup(smartyKey: "xxx") + let actualBytes = serializer.Serialize(obj: lookup, error: &self.error) + + let data = Data(base64Encoded: (actualBytes?.base64EncodedString())!) + let string = String(data: data!, encoding: .utf8) + XCTAssertNil(self.error) + XCTAssertEqual(string, expectedJsonInput) + } + + func testAllFieldsFilledCorrectly() throws { + let data = sobj.data(using: .utf8) + // Convert the JSON string to a JSON object + let jsonObject = try JSONSerialization.jsonObject(with: data!, options: []) as? [[String: Any]] + // Convert the JSON object to JSON data + let jsonData = try JSONSerialization.data(withJSONObject: jsonObject!, options: .prettyPrinted) + + // Deserialize the JSON data + let results = serializer.Deserialize(payload: jsonData, error: &self.error) as? [FinancialResult] + print(results!) + let result = results![0] + + XCTAssertEqual("xxx", result.smartyKey) + XCTAssertEqual("property", result.dataSetName.lowercased()) + XCTAssertEqual("financial", result.dataSubsetName.lowercased()) + + let attributes = result.attributes + + XCTAssertEqual("assessed_improvement_percent", attributes.assessedImprovementPercent!.lowercased()) + XCTAssertEqual("assessed_improvement_value", attributes.assessedImprovementValue!.lowercased()) + XCTAssertEqual("assessed_land_value", attributes.assessedLandValue!.lowercased()) + XCTAssertEqual("assessed_value", attributes.assessedValue!.lowercased()) + XCTAssertEqual("assessor_last_update", attributes.assessorLastUpdate!.lowercased()) + XCTAssertEqual("assessor_taxroll_update", attributes.assessorTaxrollUpdate!.lowercased()) + XCTAssertEqual("contact_city", attributes.contactCity!.lowercased()) + XCTAssertEqual("contact_crrt", attributes.contactCrrt!.lowercased()) + XCTAssertEqual("contact_full_address", attributes.contactFullAddress!.lowercased()) + XCTAssertEqual("contact_house_number", attributes.contactHouseNumber!.lowercased()) + XCTAssertEqual("contact_mail_info_format", attributes.contactMailInfoFormat!.lowercased()) + XCTAssertEqual("contact_mail_info_privacy", attributes.contactMailInfoPrivacy!.lowercased()) + XCTAssertEqual("contact_mailing_county", attributes.contactMailingCounty!.lowercased()) + XCTAssertEqual("contact_mailing_fips", attributes.contactMailingFIPS!.lowercased()) + XCTAssertEqual("contact_post_direction", attributes.contactPostDirection!.lowercased()) + XCTAssertEqual("contact_pre_direction", attributes.contactPreDirection!.lowercased()) + XCTAssertEqual("contact_state", attributes.contactState!.lowercased()) + XCTAssertEqual("contact_street_name", attributes.contactStreetName!.lowercased()) + XCTAssertEqual("contact_suffix", attributes.contactSuffix!.lowercased()) + XCTAssertEqual("contact_unit_designator", attributes.contactUnitDesignator!.lowercased()) + XCTAssertEqual("contact_value", attributes.contactValue!.lowercased()) + XCTAssertEqual("contact_zip", attributes.contactZip!.lowercased()) + XCTAssertEqual("contact_zip4", attributes.contactZip4!.lowercased()) + XCTAssertEqual("deed_document_page", attributes.deedDocumentPage!.lowercased()) + XCTAssertEqual("deed_document_book", attributes.deedDocumentBook!.lowercased()) + XCTAssertEqual("deed_document_number", attributes.deedDocumentNumber!.lowercased()) + XCTAssertEqual("deed_owner_first_name", attributes.deedOwnerFirstName!.lowercased()) + XCTAssertEqual("deed_owner_first_name2", attributes.deedOwnerFirstName2!.lowercased()) + XCTAssertEqual("deed_owner_first_name3", attributes.deedOwnerFirstName3!.lowercased()) + XCTAssertEqual("deed_owner_first_name4", attributes.deedOwnerFirstName4!.lowercased()) + XCTAssertEqual("deed_owner_full_name", attributes.deedOwnerFullName!.lowercased()) + XCTAssertEqual("deed_owner_full_name2", attributes.deedOwnerFullName2!.lowercased()) + XCTAssertEqual("deed_owner_full_name3", attributes.deedOwnerFullName3!.lowercased()) + XCTAssertEqual("deed_owner_full_name4", attributes.deedOwnerFullName4!.lowercased()) + XCTAssertEqual("deed_owner_last_name", attributes.deedOwnerLastName!.lowercased()) + XCTAssertEqual("deed_owner_last_name2", attributes.deedOwnerLastName2!.lowercased()) + XCTAssertEqual("deed_owner_last_name3", attributes.deedOwnerLastName3!.lowercased()) + XCTAssertEqual("deed_owner_last_name4", attributes.deedOwnerLastName4!.lowercased()) + XCTAssertEqual("deed_owner_middle_name", attributes.deedOwnerMiddleName!.lowercased()) + XCTAssertEqual("deed_owner_middle_name2", attributes.deedOwnerMiddleName2!.lowercased()) + XCTAssertEqual("deed_owner_middle_name3", attributes.deedOwnerMiddleName3!.lowercased()) + XCTAssertEqual("deed_owner_middle_name4", attributes.deedOwnerMiddleName4!.lowercased()) + XCTAssertEqual("deed_owner_suffix", attributes.deedOwnerSuffix!.lowercased()) + XCTAssertEqual("deed_owner_suffix2", attributes.deedOwnerSuffix2!.lowercased()) + XCTAssertEqual("deed_owner_suffix3", attributes.deedOwnerSuffix3!.lowercased()) + XCTAssertEqual("deed_owner_suffix4", attributes.deedOwnerSuffix4!.lowercased()) + XCTAssertEqual("deed_sale_date", attributes.deedSaleDate!.lowercased()) + XCTAssertEqual("deed_sale_price", attributes.deedSalePrice!.lowercased()) + XCTAssertEqual("deed_transaction_id", attributes.deedTransactionID!.lowercased()) + XCTAssertEqual("disabled_tax_exemption", attributes.disabledTaxExemption!.lowercased()) + XCTAssertEqual("first_name", attributes.firstName!.lowercased()) + XCTAssertEqual("first_name_2", attributes.firstName2!.lowercased()) + XCTAssertEqual("first_name_3", attributes.firstName3!.lowercased()) + XCTAssertEqual("first_name_4", attributes.firstName4!.lowercased()) + XCTAssertEqual("homeowner_tax_exemption", attributes.homeownerTaxExemption!.lowercased()) + XCTAssertEqual("last_name", attributes.lastName!.lowercased()) + XCTAssertEqual("last_name_2", attributes.lastName2!.lowercased()) + XCTAssertEqual("last_name_3", attributes.lastName3!.lowercased()) + XCTAssertEqual("last_name_4", attributes.lastName4!.lowercased()) + XCTAssertEqual("market_improvement_percent", attributes.marketImprovementPercent!.lowercased()) + XCTAssertEqual("market_improvement_value", attributes.marketImprovementValue!.lowercased()) + XCTAssertEqual("market_land_value", attributes.marketLandValue!.lowercased()) + XCTAssertEqual("market_value_year", attributes.marketValueYear!.lowercased()) + XCTAssertEqual("match_type", attributes.matchType!.lowercased()) + XCTAssertEqual("middle_name", attributes.middleName!.lowercased()) + XCTAssertEqual("middle_name_2", attributes.middleName2!.lowercased()) + XCTAssertEqual("middle_name_3", attributes.middleName3!.lowercased()) + XCTAssertEqual("middle_name_4", attributes.middleName4!.lowercased()) + XCTAssertEqual("other_tax_exemption", attributes.otherTaxExemption!.lowercased()) + XCTAssertEqual("owner_full_name", attributes.ownerFullName!.lowercased()) + XCTAssertEqual("owner_full_name_2", attributes.ownerFullName2!.lowercased()) + XCTAssertEqual("owner_full_name_3", attributes.ownerFullName3!.lowercased()) + XCTAssertEqual("owner_full_name_4", attributes.ownerFullName4!.lowercased()) + XCTAssertEqual("ownership_transfer_date", attributes.ownershipTransferDate!.lowercased()) + XCTAssertEqual("ownership_transfer_doc_number", attributes.ownershipTransferDocNumber!.lowercased()) + XCTAssertEqual("ownership_transfer_transaction_id", attributes.ownershipTransferTransactionID!.lowercased()) + XCTAssertEqual("ownership_type", attributes.ownershipType!.lowercased()) + XCTAssertEqual("ownership_type_2", attributes.ownershipType2!.lowercased()) + XCTAssertEqual("previous_assessed_value", attributes.previousAssessedValue!.lowercased()) + XCTAssertEqual("prior_sale_amount", attributes.priorSaleAmount!.lowercased()) + XCTAssertEqual("prior_sale_date", attributes.priorSaleDate!.lowercased()) + XCTAssertEqual("sale_amount", attributes.saleAmount!.lowercased()) + XCTAssertEqual("sale_date", attributes.saleDate!.lowercased()) + XCTAssertEqual("senior_tax_exemption", attributes.seniorTaxExemption!.lowercased()) + XCTAssertEqual("suffix", attributes.suffix!.lowercased()) + XCTAssertEqual("suffix_2", attributes.suffix2!.lowercased()) + XCTAssertEqual("suffix_3", attributes.suffix3!.lowercased()) + XCTAssertEqual("suffix_4", attributes.suffix4!.lowercased()) + XCTAssertEqual("tax_assess_year", attributes.taxAssessYear!.lowercased()) + XCTAssertEqual("tax_billed_amount", attributes.taxBilledAmount!.lowercased()) + XCTAssertEqual("tax_delinquent_year", attributes.taxDelinquentYear!.lowercased()) + XCTAssertEqual("tax_fiscal_year", attributes.taxFiscalYear!.lowercased()) + XCTAssertEqual("tax_rate_area", attributes.taxRateArea!.lowercased()) + XCTAssertEqual("total_market_value", attributes.totalMarketValue!.lowercased()) + XCTAssertEqual("trust_description", attributes.trustDescription!.lowercased()) + XCTAssertEqual("veteran_tax_exemption", attributes.veteranTaxExemption!.lowercased()) + + let financialHistory = attributes.financialHistory[0] + + XCTAssertEqual("code_title_company", financialHistory.codeTitleCompany!.lowercased()) + XCTAssertEqual("instrument_date", financialHistory.instrumentDate!.lowercased()) + XCTAssertEqual("interest_rate_type_2", financialHistory.interestRateType2!.lowercased()) + XCTAssertEqual("lender_address", financialHistory.lenderAddress!.lowercased()) + XCTAssertEqual("lender_address_2", financialHistory.lenderAddress2!.lowercased()) + XCTAssertEqual("lender_city", financialHistory.lenderCity!.lowercased()) + XCTAssertEqual("lender_city_2", financialHistory.lenderCity2!.lowercased()) + XCTAssertEqual("lender_code_2", financialHistory.lenderCode2!.lowercased()) + XCTAssertEqual("lender_first_name", financialHistory.lenderFirstName!.lowercased()) + XCTAssertEqual("lender_first_name_2", financialHistory.lenderFirstName2!.lowercased()) + XCTAssertEqual("lender_last_name", financialHistory.lenderLastName!.lowercased()) + XCTAssertEqual("lender_last_name_2", financialHistory.lenderLastName2!.lowercased()) + XCTAssertEqual("lender_name", financialHistory.lenderName!.lowercased()) + XCTAssertEqual("lender_name_2", financialHistory.lenderName2!.lowercased()) + XCTAssertEqual("lender_seller_carry_back", financialHistory.lenderSellerCarryBack!.lowercased()) + XCTAssertEqual("lender_seller_carry_back_2", financialHistory.lenderSellerCarryBack2!.lowercased()) + XCTAssertEqual("lender_state", financialHistory.lenderState!.lowercased()) + XCTAssertEqual("lender_state_2", financialHistory.lenderState2!.lowercased()) + XCTAssertEqual("lender_zip", financialHistory.lenderZip!.lowercased()) + XCTAssertEqual("lender_zip_2", financialHistory.lenderZip2!.lowercased()) + XCTAssertEqual("lender_zip_extended", financialHistory.lenderZipExtended!.lowercased()) + XCTAssertEqual("lender_zip_extended_2", financialHistory.lenderZipExtended2!.lowercased()) + XCTAssertEqual("mortgage_amount", financialHistory.mortgageAmount!.lowercased()) + XCTAssertEqual("mortgage_amount_2", financialHistory.mortgageAmount2!.lowercased()) + XCTAssertEqual("mortgage_due_date", financialHistory.mortgageDueDate!.lowercased()) + XCTAssertEqual("mortgage_due_date_2", financialHistory.mortgageDueDate2!.lowercased()) + XCTAssertEqual("mortgage_interest_rate", financialHistory.mortgageInterestRate!.lowercased()) + XCTAssertEqual("mortgage_interest_rate_type", financialHistory.mortgageInterestRateType!.lowercased()) + XCTAssertEqual("mortgage_lender_code", financialHistory.mortgageLenderCode!.lowercased()) + XCTAssertEqual("mortgage_rate_2", financialHistory.mortgageRate2!.lowercased()) + XCTAssertEqual("mortgage_recording_date", financialHistory.mortgageRecordingDate!.lowercased()) + XCTAssertEqual("mortgage_recording_date_2", financialHistory.mortgageRecordingDate2!.lowercased()) + XCTAssertEqual("mortgage_term", financialHistory.mortgageTerm!.lowercased()) + XCTAssertEqual("mortgage_term_2", financialHistory.mortgageTerm2!.lowercased()) + XCTAssertEqual("mortgage_term_type", financialHistory.mortgageTermType!.lowercased()) + XCTAssertEqual("mortgage_term_type_2", financialHistory.mortgageTermType2!.lowercased()) + XCTAssertEqual("mortgage_type", financialHistory.mortgageType!.lowercased()) + XCTAssertEqual("mortgage_type_2", financialHistory.mortgageType2!.lowercased()) + XCTAssertEqual("multi_parcel_flag", financialHistory.multiParcelFlag!.lowercased()) + XCTAssertEqual("name_title_company", financialHistory.nameTitleCompany!.lowercased()) + XCTAssertEqual("recording_date", financialHistory.recordingDate!.lowercased()) + XCTAssertEqual("transfer_amount", financialHistory.transferAmount!.lowercased()) + + } +} diff --git a/Tests/SmartyStreetsTests/USEnrichmentTests/PrincipalResultTest.swift b/Tests/SmartyStreetsTests/USEnrichmentTests/PrincipalResultTest.swift new file mode 100644 index 0000000..b990149 --- /dev/null +++ b/Tests/SmartyStreetsTests/USEnrichmentTests/PrincipalResultTest.swift @@ -0,0 +1,421 @@ +import Foundation + +import XCTest +@testable import SmartyStreets + +class USEnrichmentPrincipalResultTest: XCTestCase { + + var expectedJsonInput:String! + var obj:NSDictionary! + var sobj:String! + var error:NSError! + let serializer = PropertyPrincipalSerializer() + + override func setUp() { + super.setUp() + expectedJsonInput = """ + {"data_set_name":"property","data_subset_name":"principal","smarty_key":"xxx"} + """ + + + sobj = """ + [{"smarty_key":"xxx","data_set_name":"property","data_subset_name":"principal","attributes":{"1st_floor_sqft":"1st_Floor_Sqft","2nd_floor_sqft":"2nd_Floor_Sqft","acres":"Acres","air_conditioner":"Air_Conditioner","arbor_pergola":"Arbor_Pergola","assessed_improvement_percent":"Assessed_Improvement_Percent","assessed_improvement_value":"Assessed_Improvement_Value","assessed_land_value":"Assessed_Land_Value","assessed_value":"Assessed_Value","assessor_last_update":"Assessor_Last_Update","assessor_taxroll_update":"Assessor_Taxroll_Update","attic_area":"Attic_Area","attic_flag":"Attic_Flag","balcony":"Balcony","balcony_area":"Balcony_Area","basement_sqft":"Basement_Sqft","basement_sqft_finished":"Basement_Sqft_Finished","basement_sqft_unfinished":"Basement_Sqft_Unfinished","bath_house":"Bath_House","bath_house_sqft":"Bath_House_Sqft","bathrooms_partial":"Bathrooms_Partial","bathrooms_total":"Bathrooms_Total","bedrooms":"Bedrooms","block1":"Block1","block2":"Block2","boat_access":"Boat_Access","boat_house":"Boat_House","boat_house_sqft":"Boat_House_Sqft","boat_lift":"Boat_Lift","bonus_room":"Bonus_Room","breakfast_nook":"Breakfast_Nook","breezeway":"Breezeway","building_definition_code":"Building_Definition_Code","building_sqft":"Building_Sqft","cabin":"Cabin","cabin_sqft":"Cabin_Sqft","canopy":"Canopy","canopy_sqft":"Canopy_Sqft","carport":"Carport","carport_sqft":"Carport_Sqft","cbsa_code":"Cbsa_Code","cbsa_name":"Cbsa_Name","cellar":"Cellar","census_block":"Census_Block","census_block_group":"Census_Block_Group","census_fips_place_code":"Census_Fips_Place_Code","census_tract":"Census_Tract","central_vacuum":"Central_Vacuum","code_title_company":"Code_Title_Company","combined_statistical_area":"Combined_Statistical_Area","community_rec":"Community_Rec","company_flag":"Company_Flag","congressional_district":"Congressional_District","construction_type":"Construction_Type","contact_city":"Contact_City","contact_crrt":"Contact_Crrt","contact_full_address":"Contact_Full_Address","contact_house_number":"Contact_House_Number","contact_mail_info_format":"Contact_Mail_Info_Format","contact_mail_info_privacy":"Contact_Mail_Info_Privacy","contact_mailing_county":"Contact_Mailing_County","contact_mailing_fips":"Contact_Mailing_Fips","contact_post_direction":"Contact_Post_Direction","contact_pre_direction":"Contact_PRE_Direction","contact_state":"Contact_State","contact_street_name":"Contact_Street_Name","contact_suffix":"Contact_Suffix","contact_unit_designator":"Contact_Unit_Designator","contact_value":"Contact_Value","contact_zip":"Contact_Zip","contact_zip4":"Contact_Zip4","courtyard":"Courtyard","courtyard_area":"Courtyard_Area","deck":"Deck","deck_area":"Deck_Area","deed_document_book":"Deed_Document_Book","deed_document_number":"Deed_Document_Number","deed_document_page":"Deed_Document_Page","deed_owner_first_name":"Deed_Owner_First_Name","deed_owner_first_name2":"Deed_Owner_First_Name2","deed_owner_first_name3":"Deed_Owner_First_Name3","deed_owner_first_name4":"Deed_Owner_First_Name4","deed_owner_full_name":"Deed_Owner_Full_Name","deed_owner_full_name2":"Deed_Owner_Full_Name2","deed_owner_full_name3":"Deed_Owner_Full_Name3","deed_owner_full_name4":"Deed_Owner_Full_Name4","deed_owner_last_name":"Deed_Owner_Last_Name","deed_owner_last_name2":"Deed_Owner_Last_Name2","deed_owner_last_name3":"Deed_Owner_Last_Name3","deed_owner_last_name4":"Deed_Owner_Last_Name4","deed_owner_middle_name":"Deed_Owner_Middle_Name","deed_owner_middle_name2":"Deed_Owner_Middle_Name2","deed_owner_middle_name3":"Deed_Owner_Middle_Name3","deed_owner_middle_name4":"Deed_Owner_Middle_Name4","deed_owner_suffix":"Deed_Owner_Suffix","deed_owner_suffix2":"Deed_Owner_Suffix2","deed_owner_suffix3":"Deed_Owner_Suffix3","deed_owner_suffix4":"Deed_Owner_Suffix4","deed_sale_date":"Deed_Sale_Date","deed_sale_price":"Deed_Sale_Price","deed_transaction_id":"Deed_Transaction_ID","depth_linear_footage":"Depth_Linear_Footage","disabled_tax_exemption":"Disabled_Tax_Exemption","document_type_description":"Document_Type_Description","driveway_sqft":"Driveway_Sqft","driveway_type":"Driveway_Type","effective_year_built":"Effective_Year_Built","elevation_feet":"138","elevator":"Elevator","equestrian_arena":"Equestrian_Arena","escalator":"Escalator","exercise_room":"Exercise_Room","exterior_walls":"Exterior_Walls","family_room":"Family_Room","fence":"Fence","fence_area":"Fence_Area","fips_code":"Fips_Code","fire_resistance_code":"Fire_Resistance_Code","fire_sprinklers_flag":"Fire_Sprinklers_Flag","fireplace":"Fireplace","fireplace_number":"Fireplace_Number","first_name":"First_Name","first_name_2":"First_Name_2","first_name_3":"First_Name_3","first_name_4":"First_Name_4","flooring":"Flooring","foundation":"Foundation","game_room":"Game_Room","garage":"Garage","garage_sqft":"Garage_Sqft","gazebo":"Gazebo","gazebo_sqft":"Gazebo_Sqft","golf_course":"Golf_Course","grainery":"Grainery","grainery_sqft":"Grainery_Sqft","great_room":"Great_Room","greenhouse":"Greenhouse","greenhouse_sqft":"Greenhouse_Sqft","gross_sqft":"Gross_Sqft","guesthouse":"Guesthouse","guesthouse_sqft":"Guesthouse_Sqft","handicap_accessibility":"Handicap_Accessibility","heat":"Heat","heat_fuel_type":"Heat_Fuel_Type","hobby_room":"Hobby_Room","homeowner_tax_exemption":"Homeowner_Tax_Exemption","instrument_date":"Instrument_Date","intercom_system":"Intercom_System","interest_rate_type_2":"Interest_Rate_Type_2","interior_structure":"Interior_Structure","kennel":"Kennel","kennel_sqft":"Kennel_Sqft","land_use_code":"Land_USE_Code","land_use_group":"Land_USE_Group","land_use_standard":"Land_USE_Standard","last_name":"Last_Name","last_name_2":"Last_Name_2","last_name_3":"Last_Name_3","last_name_4":"Last_Name_4","latitude":"Latitude","laundry":"Laundry","lean_to":"Lean_To","lean_to_sqft":"Lean_To_Sqft","legal_description":"Legal_Description","legal_unit":"Legal_Unit","lender_address":"Lender_Address","lender_address_2":"Lender_Address_2","lender_city":"Lender_City","lender_city_2":"Lender_City_2","lender_code_2":"Lender_Code_2","lender_first_name":"Lender_First_Name","lender_first_name_2":"Lender_First_Name_2","lender_last_name":"Lender_Last_Name","lender_last_name_2":"Lender_Last_Name_2","lender_name":"Lender_Name","lender_name_2":"Lender_Name_2","lender_seller_carry_back":"Lender_Seller_Carry_Back","lender_seller_carry_back_2":"Lender_Seller_Carry_Back_2","lender_state":"Lender_State","lender_state_2":"Lender_State_2","lender_zip":"Lender_Zip","lender_zip_2":"Lender_Zip_2","lender_zip_extended":"Lender_Zip_Extended","lender_zip_extended_2":"Lender_Zip_Extended_2","loading_platform":"Loading_Platform","loading_platform_sqft":"Loading_Platform_Sqft","longitude":"Longitude","lot_1":"Lot_1","lot_2":"Lot_2","lot_3":"Lot_3","lot_sqft":"Lot_Sqft","market_improvement_percent":"Market_Improvement_Percent","market_improvement_value":"Market_Improvement_Value","market_land_value":"Market_Land_Value","market_value_year":"Market_Value_Year","match_type":"match_type","media_room":"Media_Room","metro_division":"Metro_Division","middle_name":"Middle_Name","middle_name_2":"Middle_Name_2","middle_name_3":"Middle_Name_3","middle_name_4":"Middle_Name_4","milkhouse":"Milkhouse","milkhouse_sqft":"Milkhouse_Sqft","minor_civil_division_code":"Minor_Civil_Division_Code","minor_civil_division_name":"Minor_Civil_Division_Name","mobile_home_hookup":"Mobile_Home_Hookup","mortgage_amount":"Mortgage_Amount","mortgage_amount_2":"Mortgage_Amount_2","mortgage_due_date":"Mortgage_Due_Date","mortgage_due_date_2":"Mortgage_Due_Date_2","mortgage_interest_rate":"Mortgage_Interest_Rate","mortgage_interest_rate_type":"Mortgage_Interest_Rate_Type","mortgage_lender_code":"Mortgage_Lender_Code","mortgage_rate_2":"Mortgage_Rate_2","mortgage_recording_date":"Mortgage_Recording_Date","mortgage_recording_date_2":"Mortgage_Recording_Date_2","mortgage_term":"Mortgage_Term","mortgage_term_2":"Mortgage_Term_2","mortgage_term_type":"Mortgage_Term_Type","mortgage_term_type_2":"Mortgage_Term_Type_2","mortgage_type":"Mortgage_Type","mortgage_type_2":"Mortgage_Type_2","msa_code":"MSA_Code","msa_name":"MSA_Name","mud_room":"Mud_Room","multi_parcel_flag":"Multi_Parcel_Flag","name_title_company":"Name_Title_Company","neighborhood_code":"Neighborhood_Code","number_of_buildings":"Number_of_Buildings","office":"Office","office_sqft":"Office_Sqft","other_tax_exemption":"Other_Tax_Exemption","outdoor_kitchen_fireplace":"Outdoor_Kitchen_Fireplace","overhead_door":"Overhead_Door","owner_full_name":"Owner_Full_Name","owner_full_name_2":"Owner_Full_Name_2","owner_full_name_3":"Owner_Full_Name_3","owner_full_name_4":"Owner_Full_Name_4","owner_occupancy_status":"Owner_Occupancy_Status","ownership_transfer_date":"Ownership_Transfer_Date","ownership_transfer_doc_number":"Ownership_Transfer_DOC_Number","ownership_transfer_transaction_id":"Ownership_Transfer_Transaction_ID","ownership_type":"Ownership_Type","ownership_type_2":"Ownership_Type_2","ownership_vesting_relation_code":"Ownership_Vesting_Relation_Code","parcel_account_number":"Parcel_Account_Number","parcel_map_book":"Parcel_Map_Book","parcel_map_page":"Parcel_Map_Page","parcel_number_alternate":"Parcel_Number_Alternate","parcel_number_formatted":"Parcel_Number_Formatted","parcel_number_previous":"Parcel_Number_Previous","parcel_number_year_added":"Parcel_Number_Year_Added","parcel_number_year_change":"Parcel_Number_Year_Change","parcel_raw_number":"Parcel_Raw_Number","parcel_shell_record":"Parcel_Shell_Record","parking_spaces":"Parking_Spaces","patio_area":"Patio_Area","phase_name":"Phase_Name","plumbing_fixtures_count":"Plumbing_Fixtures_Count","pole_struct":"Pole_Struct","pole_struct_sqft":"Pole_Struct_Sqft","pond":"Pond","pool":"Pool","pool_area":"Pool_Area","poolhouse":"Poolhouse","poolhouse_sqft":"Poolhouse_Sqft","porch":"Porch","porch_area":"Porch_Area","poultry_house":"Poultry_House","poultry_house_sqft":"Poultry_House_Sqft","previous_assessed_value":"Previous_Assessed_Value","prior_sale_amount":"Prior_Sale_Amount","prior_sale_date":"Prior_Sale_Date","property_address_carrier_route_code":"Property_Address_Carrier_Route_Code","property_address_city":"Property_Address_City","property_address_full":"Property_Address_Full","property_address_house_number":"Property_Address_House_Number","property_address_post_direction":"Property_Address_Post_Direction","property_address_pre_direction":"Property_Address_PRE_Direction","property_address_state":"Property_Address_State","property_address_street_name":"Property_Address_Street_Name","property_address_street_suffix":"Property_Address_Street_Suffix","property_address_unit_designator":"Property_Address_Unit_Designator","property_address_unit_value":"Property_Address_Unit_Value","property_address_zip_4":"Property_Address_Zip_4","property_address_zipcode":"Property_Address_Zipcode","publication_date":"Publication_Date","quarter":"Quarter","quarter_quarter":"Quarter_Quarter","quonset":"Quonset","quonset_sqft":"Quonset_Sqft","range":"Range","recording_date":"Recording_Date","roof_cover":"Roof_Cover","roof_frame":"Roof_Frame","rooms":"Rooms","rv_parking":"Rv_Parking","safe_room":"Safe_Room","sale_amount":"Sale_Amount","sale_date":"Sale_Date","sauna":"Sauna","section":"Section","security_alarm":"Security_Alarm","senior_tax_exemption":"Senior_Tax_Exemption","sewer_type":"Sewer_Type","shed":"Shed","shed_sqft":"Shed_Sqft","silo":"Silo","silo_sqft":"Silo_Sqft","sitting_room":"Sitting_Room","situs_county":"Situs_County","situs_state":"Situs_State","sound_system":"Sound_System","sports_court":"Sports_Court","sprinklers":"Sprinklers","stable":"Stable","stable_sqft":"Stable_Sqft","storage_building":"Storage_Building","storage_building_sqft":"Storage_Building_Sqft","stories_number":"Stories_Number","storm_shelter":"Storm_Shelter","storm_shutter":"Storm_Shutter","structure_style":"Structure_Style","study":"Study","subdivision":"Subdivision","suffix":"Suffix","suffix_2":"Suffix_2","suffix_3":"Suffix_3","suffix_4":"Suffix_4","sunroom":"Sunroom","tax_assess_year":"Tax_Assess_Year","tax_billed_amount":"Tax_Billed_Amount","tax_delinquent_year":"Tax_Delinquent_Year","tax_fiscal_year":"Tax_Fiscal_Year","tax_jurisdiction":"Tax_Jurisdiction","tax_rate_area":"Tax_Rate_Area","tennis_court":"Tennis_Court","topography_code":"Topography_Code","total_market_value":"Total_Market_Value","township":"Township","tract_number":"Tract_Number","transfer_amount":"Transfer_Amount","trust_description":"Trust_Description","unit_count":"Unit_Count","upper_floors_sqft":"Upper_Floors_Sqft","utility":"Utility","utility_building":"Utility_Building","utility_building_sqft":"Utility_Building_Sqft","utility_sqft":"Utility_Sqft","veteran_tax_exemption":"Veteran_Tax_Exemption","view_description":"View_Description","water_feature":"Water_Feature","water_service_type":"Water_Service_Type","wet_bar":"Wet_Bar","widow_tax_exemption":"Widow_Tax_Exemption","width_linear_footage":"Width_Linear_Footage","wine_cellar":"Wine_Cellar","year_built":"Year_Built","zoning":"Zoning"}}] + + """ + self.error = nil + } + + override func tearDown() { + super.tearDown() + self.error = nil + } + + func testLookupSerialization() { + let lookup = PropertyPrincipalEnrichmentLookup(smartyKey: "xxx") + let actualBytes = serializer.Serialize(obj: lookup, error: &self.error) + + let data = Data(base64Encoded: (actualBytes?.base64EncodedString())!) + let string = String(data: data!, encoding: .utf8) + XCTAssertNil(self.error) + XCTAssertEqual(string, expectedJsonInput) + } + + func testAllFieldsFilledCorrectly() throws { + let data = sobj.data(using: .utf8) + // Convert the JSON string to a JSON object + let jsonObject = try JSONSerialization.jsonObject(with: data!, options: []) as? [[String: Any]] + // Convert the JSON object to JSON data + let jsonData = try JSONSerialization.data(withJSONObject: jsonObject!, options: .prettyPrinted) + + // Deserialize the JSON data + let results = serializer.Deserialize(payload: jsonData, error: &self.error) as? [PrincipalResult] + print(results!) + let result = results![0] + let attributes = result.attributes + + XCTAssertEqual("xxx", result.smartyKey) + XCTAssertEqual("property", result.dataSetName) + XCTAssertEqual("principal", result.dataSubsetName) + + XCTAssertEqual("1st_floor_sqft", attributes.firstFloorSqft!.lowercased()) + XCTAssertEqual("2nd_floor_sqft", attributes.secondFloorSqft!.lowercased()) + XCTAssertEqual("acres", attributes.acres!.lowercased()) + XCTAssertEqual("air_conditioner", attributes.airConditioner!.lowercased()) + XCTAssertEqual("arbor_pergola", attributes.arborPergola!.lowercased()) + XCTAssertEqual("assessed_improvement_percent", attributes.assessedImprovementPercent!.lowercased()) + XCTAssertEqual("assessed_improvement_value", attributes.assessedImprovementValue!.lowercased()) + XCTAssertEqual("assessed_land_value", attributes.assessedLandValue!.lowercased()) + XCTAssertEqual("assessed_value", attributes.assessedValue!.lowercased()) + XCTAssertEqual("assessor_last_update", attributes.assessorLastUpdate!.lowercased()) + XCTAssertEqual("assessor_taxroll_update", attributes.assessorTaxrollUpdate!.lowercased()) + XCTAssertEqual("attic_area", attributes.atticArea!.lowercased()) + XCTAssertEqual("attic_flag", attributes.atticFlag!.lowercased()) + XCTAssertEqual("balcony", attributes.balcony!.lowercased()) + XCTAssertEqual("balcony_area", attributes.balconyArea!.lowercased()) + XCTAssertEqual("basement_sqft", attributes.basementSqft!.lowercased()) + XCTAssertEqual("basement_sqft_finished", attributes.basementSqftFinished!.lowercased()) + XCTAssertEqual("basement_sqft_unfinished", attributes.basementSqftUnfinished!.lowercased()) + XCTAssertEqual("bath_house", attributes.bathHouse!.lowercased()) + XCTAssertEqual("bath_house_sqft", attributes.bathHouseSqft!.lowercased()) + XCTAssertEqual("bathrooms_partial", attributes.bathroomsPartial!.lowercased()) + XCTAssertEqual("bathrooms_total", attributes.bathroomsTotal!.lowercased()) + XCTAssertEqual("bedrooms", attributes.bedrooms!.lowercased()) + XCTAssertEqual("block1", attributes.block1!.lowercased()) + XCTAssertEqual("block2", attributes.block2!.lowercased()) + XCTAssertEqual("boat_access", attributes.boatAccess!.lowercased()) + XCTAssertEqual("boat_house", attributes.boatHouse!.lowercased()) + XCTAssertEqual("boat_house_sqft", attributes.boatHouseSqft!.lowercased()) + XCTAssertEqual("boat_lift", attributes.boatLift!.lowercased()) + XCTAssertEqual("bonus_room", attributes.bonusRoom!.lowercased()) + XCTAssertEqual("breakfast_nook", attributes.breakfastNook!.lowercased()) + XCTAssertEqual("breezeway", attributes.breezeway!.lowercased()) + XCTAssertEqual("building_definition_code", attributes.buildingDefinitionCode!.lowercased()) + XCTAssertEqual("building_sqft", attributes.buildingSqft!.lowercased()) + XCTAssertEqual("cabin", attributes.cabin!.lowercased()) + XCTAssertEqual("cabin_sqft", attributes.cabinSqft!.lowercased()) + XCTAssertEqual("canopy", attributes.canopy!.lowercased()) + XCTAssertEqual("canopy_sqft", attributes.canopySqft!.lowercased()) + XCTAssertEqual("carport", attributes.carport!.lowercased()) + XCTAssertEqual("carport_sqft", attributes.carportSqft!.lowercased()) + XCTAssertEqual("cbsa_code", attributes.cbsaCode!.lowercased()) + XCTAssertEqual("cbsa_name", attributes.cbsaName!.lowercased()) + XCTAssertEqual("cellar", attributes.cellar!.lowercased()) + XCTAssertEqual("census_block", attributes.censusBlock!.lowercased()) + XCTAssertEqual("census_block_group", attributes.censusBlockGroup!.lowercased()) + XCTAssertEqual("census_fips_place_code", attributes.censusFIPSPlaceCode!.lowercased()) + XCTAssertEqual("census_tract", attributes.censusTract!.lowercased()) + XCTAssertEqual("central_vacuum", attributes.centralVacuum!.lowercased()) + XCTAssertEqual("code_title_company", attributes.codeTitleCompany!.lowercased()) + XCTAssertEqual("combined_statistical_area", attributes.combinedStatisticalArea!.lowercased()) + XCTAssertEqual("community_rec", attributes.communityRec!.lowercased()) + XCTAssertEqual("company_flag", attributes.companyFlag!.lowercased()) + XCTAssertEqual("congressional_district", attributes.congressionalDistrict!.lowercased()) + XCTAssertEqual("construction_type", attributes.constructionType!.lowercased()) + XCTAssertEqual("contact_city", attributes.contactCity!.lowercased()) + XCTAssertEqual("contact_crrt", attributes.contactCrrt!.lowercased()) + XCTAssertEqual("contact_full_address", attributes.contactFullAddress!.lowercased()) + XCTAssertEqual("contact_house_number", attributes.contactHouseNumber!.lowercased()) + XCTAssertEqual("contact_mail_info_format", attributes.contactMailInfoFormat!.lowercased()) + XCTAssertEqual("contact_mail_info_privacy", attributes.contactMailInfoPrivacy!.lowercased()) + XCTAssertEqual("contact_mailing_county", attributes.contactMailingCounty!.lowercased()) + XCTAssertEqual("contact_mailing_fips", attributes.contactMailingFIPS!.lowercased()) + XCTAssertEqual("contact_post_direction", attributes.contactPostDirection!.lowercased()) + XCTAssertEqual("contact_pre_direction", attributes.contactPreDirection!.lowercased()) + XCTAssertEqual("contact_state", attributes.contactState!.lowercased()) + XCTAssertEqual("contact_street_name", attributes.contactStreetName!.lowercased()) + XCTAssertEqual("contact_suffix", attributes.contactSuffix!.lowercased()) + XCTAssertEqual("contact_unit_designator", attributes.contactUnitDesignator!.lowercased()) + XCTAssertEqual("contact_value", attributes.contactValue!.lowercased()) + XCTAssertEqual("contact_zip", attributes.contactZip!.lowercased()) + XCTAssertEqual("contact_zip4", attributes.contactZip4!.lowercased()) + XCTAssertEqual("courtyard", attributes.courtyard!.lowercased()) + XCTAssertEqual("courtyard_area", attributes.courtyardArea!.lowercased()) + XCTAssertEqual("deck", attributes.deck!.lowercased()) + XCTAssertEqual("deck_area", attributes.deckArea!.lowercased()) + XCTAssertEqual("deed_document_page", attributes.deedDocumentPage!.lowercased()) + XCTAssertEqual("deed_document_book", attributes.deedDocumentBook!.lowercased()) + XCTAssertEqual("deed_document_number", attributes.deedDocumentNumber!.lowercased()) + XCTAssertEqual("deed_owner_first_name", attributes.deedOwnerFirstName!.lowercased()) + XCTAssertEqual("deed_owner_first_name2", attributes.deedOwnerFirstName2!.lowercased()) + XCTAssertEqual("deed_owner_first_name3", attributes.deedOwnerFirstName3!.lowercased()) + XCTAssertEqual("deed_owner_first_name4", attributes.deedOwnerFirstName4!.lowercased()) + XCTAssertEqual("deed_owner_full_name", attributes.deedOwnerFullName!.lowercased()) + XCTAssertEqual("deed_owner_full_name2", attributes.deedOwnerFullName2!.lowercased()) + XCTAssertEqual("deed_owner_full_name3", attributes.deedOwnerFullName3!.lowercased()) + XCTAssertEqual("deed_owner_full_name4", attributes.deedOwnerFullName4!.lowercased()) + XCTAssertEqual("deed_owner_last_name", attributes.deedOwnerLastName!.lowercased()) + XCTAssertEqual("deed_owner_last_name2", attributes.deedOwnerLastName2!.lowercased()) + XCTAssertEqual("deed_owner_last_name3", attributes.deedOwnerLastName3!.lowercased()) + XCTAssertEqual("deed_owner_last_name4", attributes.deedOwnerLastName4!.lowercased()) + XCTAssertEqual("deed_owner_middle_name", attributes.deedOwnerMiddleName!.lowercased()) + XCTAssertEqual("deed_owner_middle_name2", attributes.deedOwnerMiddleName2!.lowercased()) + XCTAssertEqual("deed_owner_middle_name3", attributes.deedOwnerMiddleName3!.lowercased()) + XCTAssertEqual("deed_owner_middle_name4", attributes.deedOwnerMiddleName4!.lowercased()) + XCTAssertEqual("deed_owner_suffix", attributes.deedOwnerSuffix!.lowercased()) + XCTAssertEqual("deed_owner_suffix2", attributes.deedOwnerSuffix2!.lowercased()) + XCTAssertEqual("deed_owner_suffix3", attributes.deedOwnerSuffix3!.lowercased()) + XCTAssertEqual("deed_owner_suffix4", attributes.deedOwnerSuffix4!.lowercased()) + XCTAssertEqual("deed_sale_date", attributes.deedSaleDate!.lowercased()) + XCTAssertEqual("deed_sale_price", attributes.deedSalePrice!.lowercased()) + XCTAssertEqual("deed_transaction_id", attributes.deedTransactionID!.lowercased()) + XCTAssertEqual("depth_linear_footage", attributes.depthLinearFootage!.lowercased()) + XCTAssertEqual("disabled_tax_exemption", attributes.disabledTaxExemption!.lowercased()) + XCTAssertEqual("driveway_sqft", attributes.drivewaySqft!.lowercased()) + XCTAssertEqual("driveway_type", attributes.drivewayType!.lowercased()) + XCTAssertEqual("effective_year_built", attributes.effectiveYearBuilt!.lowercased()) + XCTAssertEqual("138", attributes.elevationFeet!.lowercased()) + XCTAssertEqual("elevator", attributes.elevator!.lowercased()) + XCTAssertEqual("equestrian_arena", attributes.equestrianArena!.lowercased()) + XCTAssertEqual("escalator", attributes.escalator!.lowercased()) + XCTAssertEqual("exercise_room", attributes.exerciseRoom!.lowercased()) + XCTAssertEqual("exterior_walls", attributes.exteriorWalls!.lowercased()) + XCTAssertEqual("family_room", attributes.familyRoom!.lowercased()) + XCTAssertEqual("fence", attributes.fence!.lowercased()) + XCTAssertEqual("fence_area", attributes.fenceArea!.lowercased()) + XCTAssertEqual("fips_code", attributes.fipsCode!.lowercased()) + XCTAssertEqual("fire_resistance_code", attributes.fireResistanceCode!.lowercased()) + XCTAssertEqual("fire_sprinklers_flag", attributes.fireSprinklersFlag!.lowercased()) + XCTAssertEqual("fireplace", attributes.fireplace!.lowercased()) + XCTAssertEqual("fireplace_number", attributes.fireplaceNumber!.lowercased()) + XCTAssertEqual("first_name", attributes.firstName!.lowercased()) + XCTAssertEqual("first_name_2", attributes.firstName2!.lowercased()) + XCTAssertEqual("first_name_3", attributes.firstName3!.lowercased()) + XCTAssertEqual("first_name_4", attributes.firstName4!.lowercased()) + XCTAssertEqual("flooring", attributes.flooring!.lowercased()) + XCTAssertEqual("foundation", attributes.foundation!.lowercased()) + XCTAssertEqual("game_room", attributes.gameRoom!.lowercased()) + XCTAssertEqual("garage", attributes.garage!.lowercased()) + XCTAssertEqual("garage_sqft", attributes.garageSqft!.lowercased()) + XCTAssertEqual("gazebo", attributes.gazebo!.lowercased()) + XCTAssertEqual("gazebo_sqft", attributes.gazeboSqft!.lowercased()) + XCTAssertEqual("golf_course", attributes.golfCourse!.lowercased()) + XCTAssertEqual("grainery", attributes.grainery!.lowercased()) + XCTAssertEqual("grainery_sqft", attributes.grainerySqft!.lowercased()) + XCTAssertEqual("great_room", attributes.greatRoom!.lowercased()) + XCTAssertEqual("greenhouse", attributes.greenhouse!.lowercased()) + XCTAssertEqual("greenhouse_sqft", attributes.greenhouseSqft!.lowercased()) + XCTAssertEqual("gross_sqft", attributes.grossSqft!.lowercased()) + XCTAssertEqual("guesthouse", attributes.guesthouse!.lowercased()) + XCTAssertEqual("guesthouse_sqft", attributes.guesthouseSqft!.lowercased()) + XCTAssertEqual("handicap_accessibility", attributes.handicapAccessibility!.lowercased()) + XCTAssertEqual("heat", attributes.heat!.lowercased()) + XCTAssertEqual("heat_fuel_type", attributes.heatFuelType!.lowercased()) + XCTAssertEqual("hobby_room", attributes.hobbyRoom!.lowercased()) + XCTAssertEqual("homeowner_tax_exemption", attributes.homeownerTaxExemption!.lowercased()) + XCTAssertEqual("instrument_date", attributes.instrumentDate!.lowercased()) + XCTAssertEqual("intercom_system", attributes.intercomSystem!.lowercased()) + XCTAssertEqual("interest_rate_type_2", attributes.interestRateType2!.lowercased()) + XCTAssertEqual("interior_structure", attributes.interiorStructure!.lowercased()) + XCTAssertEqual("kennel", attributes.kennel!.lowercased()) + XCTAssertEqual("kennel_sqft", attributes.kennelSqft!.lowercased()) + XCTAssertEqual("land_use_code", attributes.landUseCode!.lowercased()) + XCTAssertEqual("land_use_group", attributes.landUseGroup!.lowercased()) + XCTAssertEqual("land_use_standard", attributes.landUseStandard!.lowercased()) + XCTAssertEqual("last_name", attributes.lastName!.lowercased()) + XCTAssertEqual("last_name_2", attributes.lastName2!.lowercased()) + XCTAssertEqual("last_name_3", attributes.lastName3!.lowercased()) + XCTAssertEqual("last_name_4", attributes.lastName4!.lowercased()) + XCTAssertEqual("latitude", attributes.latitude!.lowercased()) + XCTAssertEqual("laundry", attributes.laundry!.lowercased()) + XCTAssertEqual("lean_to", attributes.leanTo!.lowercased()) + XCTAssertEqual("lean_to_sqft", attributes.leanToSqft!.lowercased()) + XCTAssertEqual("legal_description", attributes.legalDescription!.lowercased()) + XCTAssertEqual("legal_unit", attributes.legalUnit!.lowercased()) + XCTAssertEqual("lender_address", attributes.lenderAddress!.lowercased()) + XCTAssertEqual("lender_address_2", attributes.lenderAddress2!.lowercased()) + XCTAssertEqual("lender_city", attributes.lenderCity!.lowercased()) + XCTAssertEqual("lender_city_2", attributes.lenderCity2!.lowercased()) + XCTAssertEqual("lender_code_2", attributes.lenderCode2!.lowercased()) + XCTAssertEqual("lender_first_name", attributes.lenderFirstName!.lowercased()) + XCTAssertEqual("lender_first_name_2", attributes.lenderFirstName2!.lowercased()) + XCTAssertEqual("lender_last_name", attributes.lenderLastName!.lowercased()) + XCTAssertEqual("lender_last_name_2", attributes.lenderLastName2!.lowercased()) + XCTAssertEqual("lender_name", attributes.lenderName!.lowercased()) + XCTAssertEqual("lender_name_2", attributes.lenderName2!.lowercased()) + XCTAssertEqual("lender_seller_carry_back", attributes.lenderSellerCarryBack!.lowercased()) + XCTAssertEqual("lender_seller_carry_back_2", attributes.lenderSellerCarryBack2!.lowercased()) + XCTAssertEqual("lender_state", attributes.lenderState!.lowercased()) + XCTAssertEqual("lender_state_2", attributes.lenderState2!.lowercased()) + XCTAssertEqual("lender_zip", attributes.lenderZip!.lowercased()) + XCTAssertEqual("lender_zip_2", attributes.lenderZip2!.lowercased()) + XCTAssertEqual("lender_zip_extended", attributes.lenderZipExtended!.lowercased()) + XCTAssertEqual("lender_zip_extended_2", attributes.lenderZipExtended2!.lowercased()) + XCTAssertEqual("loading_platform", attributes.loadingPlatform!.lowercased()) + XCTAssertEqual("loading_platform_sqft", attributes.loadingPlatformSqft!.lowercased()) + XCTAssertEqual("longitude", attributes.longitude!.lowercased()) + XCTAssertEqual("lot_1", attributes.lot1!.lowercased()) + XCTAssertEqual("lot_2", attributes.lot2!.lowercased()) + XCTAssertEqual("lot_3", attributes.lot3!.lowercased()) + XCTAssertEqual("lot_sqft", attributes.lotSqft!.lowercased()) + XCTAssertEqual("market_improvement_percent", attributes.marketImprovementPercent!.lowercased()) + XCTAssertEqual("market_improvement_value", attributes.marketImprovementValue!.lowercased()) + XCTAssertEqual("market_land_value", attributes.marketLandValue!.lowercased()) + XCTAssertEqual("market_value_year", attributes.marketValueYear!.lowercased()) + XCTAssertEqual("match_type", attributes.matchType!.lowercased()) + XCTAssertEqual("media_room", attributes.mediaRoom!.lowercased()) + XCTAssertEqual("metro_division", attributes.metroDivision!.lowercased()) + XCTAssertEqual("middle_name", attributes.middleName!.lowercased()) + XCTAssertEqual("middle_name_2", attributes.middleName2!.lowercased()) + XCTAssertEqual("middle_name_3", attributes.middleName3!.lowercased()) + XCTAssertEqual("middle_name_4", attributes.middleName4!.lowercased()) + XCTAssertEqual("milkhouse", attributes.milkhouse!.lowercased()) + XCTAssertEqual("milkhouse_sqft", attributes.milkhouseSqft!.lowercased()) + XCTAssertEqual("minor_civil_division_code", attributes.minorCivilDivisionCode!.lowercased()) + XCTAssertEqual("minor_civil_division_name", attributes.minorCivilDivisionName!.lowercased()) + XCTAssertEqual("mobile_home_hookup", attributes.mobileHomeHookup!.lowercased()) + XCTAssertEqual("mortgage_amount", attributes.mortgageAmount!.lowercased()) + XCTAssertEqual("mortgage_amount_2", attributes.mortgageAmount2!.lowercased()) + XCTAssertEqual("mortgage_due_date", attributes.mortgageDueDate!.lowercased()) + XCTAssertEqual("mortgage_due_date_2", attributes.mortgageDueDate2!.lowercased()) + XCTAssertEqual("mortgage_interest_rate", attributes.mortgageInterestRate!.lowercased()) + XCTAssertEqual("mortgage_interest_rate_type", attributes.mortgageInterestRateType!.lowercased()) + XCTAssertEqual("mortgage_lender_code", attributes.mortgageLenderCode!.lowercased()) + XCTAssertEqual("mortgage_rate_2", attributes.mortgageRate2!.lowercased()) + XCTAssertEqual("mortgage_recording_date", attributes.mortgageRecordingDate!.lowercased()) + XCTAssertEqual("mortgage_recording_date_2", attributes.mortgageRecordingDate2!.lowercased()) + XCTAssertEqual("mortgage_term", attributes.mortgageTerm!.lowercased()) + XCTAssertEqual("mortgage_term_2", attributes.mortgageTerm2!.lowercased()) + XCTAssertEqual("mortgage_term_type", attributes.mortgageTermType!.lowercased()) + XCTAssertEqual("mortgage_term_type_2", attributes.mortgageTermType2!.lowercased()) + XCTAssertEqual("mortgage_type", attributes.mortgageType!.lowercased()) + XCTAssertEqual("mortgage_type_2", attributes.mortgageType2!.lowercased()) + XCTAssertEqual("msa_code", attributes.msaCode!.lowercased()) + XCTAssertEqual("msa_name", attributes.msaName!.lowercased()) + XCTAssertEqual("mud_room", attributes.mudRoom!.lowercased()) + XCTAssertEqual("multi_parcel_flag", attributes.multiParcelFlag!.lowercased()) + XCTAssertEqual("name_title_company", attributes.nameTitleCompany!.lowercased()) + XCTAssertEqual("neighborhood_code", attributes.neighborhoodCode!.lowercased()) + XCTAssertEqual("number_of_buildings", attributes.numberOfBuildings!.lowercased()) + XCTAssertEqual("office", attributes.office!.lowercased()) + XCTAssertEqual("office_sqft", attributes.officeSqft!.lowercased()) + XCTAssertEqual("other_tax_exemption", attributes.otherTaxExemption!.lowercased()) + XCTAssertEqual("outdoor_kitchen_fireplace", attributes.outdoorKitchenFireplace!.lowercased()) + XCTAssertEqual("overhead_door", attributes.overheadDoor!.lowercased()) + XCTAssertEqual("owner_full_name", attributes.ownerFullName!.lowercased()) + XCTAssertEqual("owner_full_name_2", attributes.ownerFullName2!.lowercased()) + XCTAssertEqual("owner_full_name_3", attributes.ownerFullName3!.lowercased()) + XCTAssertEqual("owner_full_name_4", attributes.ownerFullName4!.lowercased()) + XCTAssertEqual("owner_occupancy_status", attributes.ownerOccupancyStatus!.lowercased()) + XCTAssertEqual("ownership_transfer_date", attributes.ownershipTransferDate!.lowercased()) + XCTAssertEqual("ownership_transfer_doc_number", attributes.ownershipTransferDocNumber!.lowercased()) + XCTAssertEqual("ownership_transfer_transaction_id", attributes.ownershipTransferTransactionID!.lowercased()) + XCTAssertEqual("ownership_type", attributes.ownershipType!.lowercased()) + XCTAssertEqual("ownership_type_2", attributes.ownershipType2!.lowercased()) + XCTAssertEqual("ownership_vesting_relation_code", attributes.ownershipVestingRelationCode!.lowercased()) + XCTAssertEqual("parcel_account_number", attributes.parcelAccountNumber!.lowercased()) + XCTAssertEqual("parcel_map_book", attributes.parcelMapBook!.lowercased()) + XCTAssertEqual("parcel_map_page", attributes.parcelMapPage!.lowercased()) + XCTAssertEqual("parcel_number_alternate", attributes.parcelNumberAlternate!.lowercased()) + XCTAssertEqual("parcel_number_formatted", attributes.parcelNumberFormatted!.lowercased()) + XCTAssertEqual("parcel_number_previous", attributes.parcelNumberPrevious!.lowercased()) + XCTAssertEqual("parcel_number_year_added", attributes.parcelNumberYearAdded!.lowercased()) + XCTAssertEqual("parcel_number_year_change", attributes.parcelNumberYearChange!.lowercased()) + XCTAssertEqual("parcel_raw_number", attributes.parcelRawNumber!.lowercased()) + XCTAssertEqual("parcel_shell_record", attributes.parcelShellRecord!.lowercased()) + XCTAssertEqual("parking_spaces", attributes.parkingSpaces!.lowercased()) + XCTAssertEqual("patio_area", attributes.patioArea!.lowercased()) + XCTAssertEqual("phase_name", attributes.phaseName!.lowercased()) + XCTAssertEqual("plumbing_fixtures_count", attributes.plumbingFixturesCount!.lowercased()) + XCTAssertEqual("pole_struct", attributes.poleStruct!.lowercased()) + XCTAssertEqual("pole_struct_sqft", attributes.poleStructSqft!.lowercased()) + XCTAssertEqual("pond", attributes.pond!.lowercased()) + XCTAssertEqual("pool", attributes.pool!.lowercased()) + XCTAssertEqual("pool_area", attributes.poolArea!.lowercased()) + XCTAssertEqual("poolhouse", attributes.poolhouse!.lowercased()) + XCTAssertEqual("poolhouse_sqft", attributes.poolhouseSqft!.lowercased()) + XCTAssertEqual("porch", attributes.porch!.lowercased()) + XCTAssertEqual("porch_area", attributes.porchArea!.lowercased()) + XCTAssertEqual("poultry_house", attributes.poultryHouse!.lowercased()) + XCTAssertEqual("poultry_house_sqft", attributes.poultryHouseSqft!.lowercased()) + XCTAssertEqual("previous_assessed_value", attributes.previousAssessedValue!.lowercased()) + XCTAssertEqual("prior_sale_amount", attributes.priorSaleAmount!.lowercased()) + XCTAssertEqual("prior_sale_date", attributes.priorSaleDate!.lowercased()) + XCTAssertEqual("property_address_carrier_route_code", attributes.propertyAddressCarrierRouteCode!.lowercased()) + XCTAssertEqual("property_address_city", attributes.propertyAddressCity!.lowercased()) + XCTAssertEqual("property_address_full", attributes.propertyAddressFull!.lowercased()) + XCTAssertEqual("property_address_house_number", attributes.propertyAddressHouseNumber!.lowercased()) + XCTAssertEqual("property_address_post_direction", attributes.propertyAddressPostDirection!.lowercased()) + XCTAssertEqual("property_address_pre_direction", attributes.propertyAddressPreDirection!.lowercased()) + XCTAssertEqual("property_address_state", attributes.propertyAddressState!.lowercased()) + XCTAssertEqual("property_address_street_name", attributes.propertyAddressStreetName!.lowercased()) + XCTAssertEqual("property_address_street_suffix", attributes.propertyAddressStreetSuffix!.lowercased()) + XCTAssertEqual("property_address_unit_designator", attributes.propertyAddressUnitDesignator!.lowercased()) + XCTAssertEqual("property_address_unit_value", attributes.propertyAddressUnitValue!.lowercased()) + XCTAssertEqual("property_address_zip_4", attributes.propertyAddressZip4!.lowercased()) + XCTAssertEqual("property_address_zipcode", attributes.propertyAddressZipcode!.lowercased()) + XCTAssertEqual("publication_date", attributes.publicationDate!.lowercased()) + XCTAssertEqual("quarter", attributes.quarter!.lowercased()) + XCTAssertEqual("quarter_quarter", attributes.quarterQuarter!.lowercased()) + XCTAssertEqual("quonset", attributes.quonset!.lowercased()) + XCTAssertEqual("quonset_sqft", attributes.quonsetSqft!.lowercased()) + XCTAssertEqual("range", attributes.range!.lowercased()) + XCTAssertEqual("recording_date", attributes.recordingDate!.lowercased()) + XCTAssertEqual("roof_cover", attributes.roofCover!.lowercased()) + XCTAssertEqual("roof_frame", attributes.roofFrame!.lowercased()) + XCTAssertEqual("rooms", attributes.rooms!.lowercased()) + XCTAssertEqual("rv_parking", attributes.rvParking!.lowercased()) + XCTAssertEqual("safe_room", attributes.safeRoom!.lowercased()) + XCTAssertEqual("sale_amount", attributes.saleAmount!.lowercased()) + XCTAssertEqual("sale_date", attributes.saleDate!.lowercased()) + XCTAssertEqual("sauna", attributes.sauna!.lowercased()) + XCTAssertEqual("section", attributes.section!.lowercased()) + XCTAssertEqual("security_alarm", attributes.securityAlarm!.lowercased()) + XCTAssertEqual("senior_tax_exemption", attributes.seniorTaxExemption!.lowercased()) + XCTAssertEqual("sewer_type", attributes.sewerType!.lowercased()) + XCTAssertEqual("shed", attributes.shed!.lowercased()) + XCTAssertEqual("shed_sqft", attributes.shedSqft!.lowercased()) + XCTAssertEqual("silo", attributes.silo!.lowercased()) + XCTAssertEqual("silo_sqft", attributes.siloSqft!.lowercased()) + XCTAssertEqual("sitting_room", attributes.sittingRoom!.lowercased()) + XCTAssertEqual("situs_county", attributes.situsCounty!.lowercased()) + XCTAssertEqual("situs_state", attributes.situsState!.lowercased()) + XCTAssertEqual("sound_system", attributes.soundSystem!.lowercased()) + XCTAssertEqual("sports_court", attributes.sportsCourt!.lowercased()) + XCTAssertEqual("sprinklers", attributes.sprinklers!.lowercased()) + XCTAssertEqual("stable", attributes.stable!.lowercased()) + XCTAssertEqual("stable_sqft", attributes.stableSqft!.lowercased()) + XCTAssertEqual("storage_building", attributes.storageBuilding!.lowercased()) + XCTAssertEqual("storage_building_sqft", attributes.storageBuildingSqft!.lowercased()) + XCTAssertEqual("stories_number", attributes.storiesNumber!.lowercased()) + XCTAssertEqual("storm_shelter", attributes.stormShelter!.lowercased()) + XCTAssertEqual("storm_shutter", attributes.stormShutter!.lowercased()) + XCTAssertEqual("structure_style", attributes.structureStyle!.lowercased()) + XCTAssertEqual("study", attributes.study!.lowercased()) + XCTAssertEqual("subdivision", attributes.subdivision!.lowercased()) + XCTAssertEqual("suffix", attributes.suffix!.lowercased()) + XCTAssertEqual("suffix_2", attributes.suffix2!.lowercased()) + XCTAssertEqual("suffix_3", attributes.suffix3!.lowercased()) + XCTAssertEqual("suffix_4", attributes.suffix4!.lowercased()) + XCTAssertEqual("sunroom", attributes.sunroom!.lowercased()) + XCTAssertEqual("tax_assess_year", attributes.taxAssessYear!.lowercased()) + XCTAssertEqual("tax_billed_amount", attributes.taxBilledAmount!.lowercased()) + XCTAssertEqual("tax_delinquent_year", attributes.taxDelinquentYear!.lowercased()) + XCTAssertEqual("tax_fiscal_year", attributes.taxFiscalYear!.lowercased()) + XCTAssertEqual("tax_jurisdiction", attributes.taxJurisdiction!.lowercased()) + XCTAssertEqual("tax_rate_area", attributes.taxRateArea!.lowercased()) + XCTAssertEqual("tennis_court", attributes.tennisCourt!.lowercased()) + XCTAssertEqual("topography_code", attributes.topographyCode!.lowercased()) + XCTAssertEqual("total_market_value", attributes.totalMarketValue!.lowercased()) + XCTAssertEqual("township", attributes.township!.lowercased()) + XCTAssertEqual("tract_number", attributes.tractNumber!.lowercased()) + XCTAssertEqual("transfer_amount", attributes.transferAmount!.lowercased()) + XCTAssertEqual("trust_description", attributes.trustDescription!.lowercased()) + XCTAssertEqual("unit_count", attributes.unitCount!.lowercased()) + XCTAssertEqual("upper_floors_sqft", attributes.upperFloorsSqft!.lowercased()) + XCTAssertEqual("utility", attributes.utility!.lowercased()) + XCTAssertEqual("utility_building", attributes.utilityBuilding!.lowercased()) + XCTAssertEqual("utility_building_sqft", attributes.utilityBuildingSqft!.lowercased()) + XCTAssertEqual("utility_sqft", attributes.utilitySqft!.lowercased()) + XCTAssertEqual("veteran_tax_exemption", attributes.veteranTaxExemption!.lowercased()) + XCTAssertEqual("view_description", attributes.viewDescription!.lowercased()) + XCTAssertEqual("water_feature", attributes.waterFeature!.lowercased()) + XCTAssertEqual("water_service_type", attributes.waterServiceType!.lowercased()) + XCTAssertEqual("wet_bar", attributes.wetBar!.lowercased()) + XCTAssertEqual("widow_tax_exemption", attributes.widowTaxExemption!.lowercased()) + XCTAssertEqual("width_linear_footage", attributes.widthLinearFootage!.lowercased()) + XCTAssertEqual("wine_cellar", attributes.wineCellar!.lowercased()) + XCTAssertEqual("year_built", attributes.yearBuilt!.lowercased()) + XCTAssertEqual("zoning", attributes.zoning!.lowercased()) + + } +} diff --git a/Tests/SmartyStreetsTests/USReverseGeoTests/USReverseGeoSerializerTests.swift b/Tests/SmartyStreetsTests/USReverseGeoTests/USReverseGeoSerializerTests.swift index 86da7f7..c1463e3 100644 --- a/Tests/SmartyStreetsTests/USReverseGeoTests/USReverseGeoSerializerTests.swift +++ b/Tests/SmartyStreetsTests/USReverseGeoTests/USReverseGeoSerializerTests.swift @@ -42,7 +42,7 @@ class USReverseGeoSerializerTests: XCTestCase { func testSerialize() { let expectedOutput = """ - {"source":"","longitude":"-111.11111111","latitude":"44.88888889"} + {"latitude":"44.88888889","longitude":"-111.11111111","source":""} """ let lookup = USReverseGeoLookup(latitude: 44.888888888, longitude: -111.111111111, source: "") diff --git a/Tests/SmartyStreetsTests/USStreetTests/USStreetCandidateTests.swift b/Tests/SmartyStreetsTests/USStreetTests/USStreetCandidateTests.swift index 6b01a85..b560a5f 100644 --- a/Tests/SmartyStreetsTests/USStreetTests/USStreetCandidateTests.swift +++ b/Tests/SmartyStreetsTests/USStreetTests/USStreetCandidateTests.swift @@ -10,7 +10,7 @@ class USStreetCandidateTests: XCTestCase { override func setUp() { super.setUp() expectedJsonInput = """ - [{\"state\":\"state_value\",\"secondary\":\"secondary\",\"street2\":\"street2_value\",\"street\":\"street_value\",\"maxCandidates\":5,\"urbanization\":\"urbanization_value\",\"matchStrategy\":\"match_value\",\"city\":\"city_value\",\"result\":[],\"zipCode\":\"zipCode_value\",\"addressee\":\"addressee_value\",\"lastline\":\"lastline_value\"},{\"result\":[],\"maxCandidates\":1,\"state\":\"California\",\"street\":\"1600 amphitheatre parkway\",\"city\":\"Mountain view\"},{\"result\":[],\"street\":\"1 Rosedale, Baltimore, Maryland\",\"maxCandidates\":1}] + [{\"addressee\":\"addressee_value\",\"city\":\"city_value\",\"lastline\":\"lastline_value\",\"matchStrategy\":\"match_value\",\"maxCandidates\":5,\"result\":[],\"secondary\":\"secondary\",\"state\":\"state_value\",\"street\":\"street_value\",\"street2\":\"street2_value\",\"urbanization\":\"urbanization_value\",\"zipCode\":\"zipCode_value\"},{\"city\":\"Mountain view\",\"maxCandidates\":1,\"result\":[],\"state\":\"California\",\"street\":\"1600 amphitheatre parkway\"},{\"maxCandidates\":1,\"result\":[],\"street\":\"1 Rosedale, Baltimore, Maryland\"}] """ obj = [ diff --git a/UISamples/UISamples/SwiftSamples/SwiftUSEnrichmentExample.swift b/UISamples/UISamples/SwiftSamples/SwiftUSEnrichmentExample.swift new file mode 100644 index 0000000..269ee59 --- /dev/null +++ b/UISamples/UISamples/SwiftSamples/SwiftUSEnrichmentExample.swift @@ -0,0 +1,105 @@ +import UIKit +import SmartyStreets + +class SwiftUSEnrichmentExample: UIViewController, UITextFieldDelegate { + + @IBOutlet weak var smartyKey: UITextField! + @IBOutlet weak var lookupType: UITextField! + + override func viewDidLoad() { + super.viewDidLoad() + UIGraphicsBeginImageContext(self.view.frame.size) + UIImage(named: "lines-map")?.draw(in: self.view.bounds) + let background = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + self.view.backgroundColor = UIColor(patternImage: background!) + + smartyKey.delegate = self + lookupType.delegate = self + } + + @IBAction func lookup(_ sender: Any) { + results.text = run() + self.view.endEditing(true) + } + + func run() -> String{ + // The appropriate license values to be used for your subscriptions can be found on the Subscriptions page of the account dashboard. + // https://www.smartystreets.com/docs/cloud/licensing + let client = ClientBuilder(id: "KEY", hostname: "hostname") + .buildUsEnrichmentApiClient() + + var error:NSError! = nil + + if lookupType.text.lowercased() == "principal" { + var results = client.sendPropertyPrincipalLookup(smartyKey: smartyKey.text, error: error) + return self.outputPrincipalResults(results) + } else if lookup.text.lowercased() == "financial" { + var results = client.sendPropertyFinancialLookup(smartyKey: smartyKey.text, error: error) + return self.outputFinancialResults(results) + } + } + + @IBAction func Return(_ sender: Any) { + dismiss(animated: true, completion: nil) + } + + func outputFinancialResults(results: [FinancialAttributes]) -> String { + if let error = error { + let output = """ + Domain: \(error.domain) + Error Code: \(error.code) + Description:\n\(error.userInfo[NSLocalizedDescriptionKey] as! NSString) + """ + NSLog(output) + return output + } + + var output = "Results: \n" + + if results == nil { + return "\nNo Result Found\n" + } + + for result in results { + let jsonData = try encoder.encode(result) + let jsonString = String(data: jsonData, encoding: .utf8) + output.append(jsonString) + output.append("\n******************************\n") + } + + output.append("\n******************************\n") + + return output + } + + func outputPrincipalResults(results: [PrincipalAttributes]) -> String { + if let error = error { + let output = """ + Domain: \(error.domain) + Error Code: \(error.code) + Description:\n\(error.userInfo[NSLocalizedDescriptionKey] as! NSString) + """ + NSLog(output) + return output + } + + var output = "Results: \n" + + if results == nil { + return "\nNo Result Found\n" + } + + for result in results { + let jsonData = try encoder.encode(result) + let jsonString = String(data: jsonData, encoding: .utf8) + output.append(jsonString) + output.append("\n******************************\n") + } + + output.append("\n******************************\n") + + return output + } +} diff --git a/samples/Sources/swiftExamples/USEnrichmentExample.swift b/samples/Sources/swiftExamples/USEnrichmentExample.swift new file mode 100644 index 0000000..971c577 --- /dev/null +++ b/samples/Sources/swiftExamples/USEnrichmentExample.swift @@ -0,0 +1,79 @@ +import Foundation +import SmartyStreets + +class USEnrichmentExample{ + func run() -> String { + let client = ClientBuilder(id: "KEY", hostname: "hostname").withLicenses(["us-rooftop-geocoding-cloud"]) + .buildUsEnrichmentApiClient() + + var error:NSError! = nil + + let smartyKey = "7" + + if lookupType.text.lowercased() == "principal" { + var results = client.sendPropertyPrincipalLookup(smartyKey: smartyKey, error: error) + return self.outputPrincipalResults(results) + } else if lookup.text.lowercased() == "financial" { + var results = client.sendPropertyFinancialLookup(smartyKey: smartyKey, error: error) + return self.outputFinancialResults(results) + } + } + + func outputFinancialResults(results: [FinancialAttributes]) -> String { + if let error = error { + let output = """ + Domain: \(error.domain) + Error Code: \(error.code) + Description:\n\(error.userInfo[NSLocalizedDescriptionKey] as! NSString) + """ + NSLog(output) + return output + } + + var output = "Results: \n" + + if results == nil { + return "\nNo Result Found\n" + } + + for result in results { + let jsonData = try encoder.encode(result) + let jsonString = String(data: jsonData, encoding: .utf8) + output.append(jsonString) + output.append("\n******************************\n") + } + + output.append("\n******************************\n") + + return output + } + + func outputPrincipalResults(results: [PrincipalAttributes]) -> String { + if let error = error { + let output = """ + Domain: \(error.domain) + Error Code: \(error.code) + Description:\n\(error.userInfo[NSLocalizedDescriptionKey] as! NSString) + """ + NSLog(output) + return output + } + + var output = "Results: \n" + + if results == nil { + return "\nNo Result Found\n" + } + + for result in results { + let jsonData = try encoder.encode(result) + let jsonString = String(data: jsonData, encoding: .utf8) + output.append(jsonString) + output.append("\n******************************\n") + } + + output.append("\n******************************\n") + + return output + } +} \ No newline at end of file diff --git a/samples/Sources/swiftExamples/main.swift b/samples/Sources/swiftExamples/main.swift index 5abc817..94881d5 100644 --- a/samples/Sources/swiftExamples/main.swift +++ b/samples/Sources/swiftExamples/main.swift @@ -11,3 +11,4 @@ print(USExtractExample().run()) print(InternationalStreetExample().run()) print(InternationalAutocompleteExample().run()) print(USReverseGeoExample().run()) +print(USEnrichmentExample().run())