diff --git a/Slingshot.Elvanto/LibElvanto/Attributes/ElvantoResourceAttriubte.cs b/Slingshot.Elvanto/LibElvanto/Attributes/ElvantoResourceAttriubte.cs new file mode 100644 index 0000000..b2ae7d0 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Attributes/ElvantoResourceAttriubte.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibElvanto.Attributes +{ + public class ElvantoResourceAttribute : Attribute + { + public string Url { get => url; } + private readonly string url; + + public string PluralName { get => pluralName; } + private readonly string pluralName; + + public string SingleName { get => singleName; } + private readonly string singleName; + + public List Fields { get => fields?.ToList() ?? new List(); } + private readonly string[]? fields; + + public ElvantoResourceAttribute( string url, string pluralName, string singleName, string[]? fields = null ) + { + this.url = url; + this.pluralName = pluralName; + this.singleName = singleName; + this.fields = fields; + } + } +} diff --git a/Slingshot.Elvanto/LibElvanto/Client.cs b/Slingshot.Elvanto/LibElvanto/Client.cs new file mode 100644 index 0000000..6ae1f5e --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Client.cs @@ -0,0 +1,138 @@ +using System.Net.Http.Headers; +using System.Text; +using System.Text.Json; +using LibElvanto.Attributes; +using LibElvanto.Contracts; + +namespace LibElvanto; + +public class Client +{ + private readonly string authValue; + public Client( string apiKey ) + { + authValue = Convert.ToBase64String( System.Text.ASCIIEncoding.ASCII.GetBytes( $"{apiKey}:x" ) ); + } + + public async IAsyncEnumerable Get( List? fields = null ) where T : ElvantoContract + { + ElvantoResourceAttribute? elvantoResource = ( ElvantoResourceAttribute? ) Attribute.GetCustomAttribute( typeof( T ), typeof( ElvantoResourceAttribute ) ); + + if ( elvantoResource == null ) + { + throw new Exception( $"Type: {typeof( T ).Name} is not decorated with ElvantoResourceAttriubte" ); + } + + HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", authValue ); + + var page = 1; + + fields = fields ?? new List(); + fields.AddRange( elvantoResource.Fields ); + + var fieldsString = GetFieldsString( fields ); + + if ( typeof( T ) == typeof( Transaction ) ) + { + fieldsString += $"&start=2000-01-01&end={DateTime.Today:yyyy-MM-dd}"; + } + + do + { + var results = await client.GetAsync( $"{elvantoResource.Url}?page={page}{fieldsString}" ); + if ( results == null ) + { + throw new Exception( "Bad request" ); + } + + var content = await results.Content.ReadAsStringAsync(); + + var paginatedResponse = ParseContent( content, elvantoResource, fields ); + + foreach ( var item in paginatedResponse.Data ) + { + yield return item; + } + + if ( paginatedResponse.Total < page * paginatedResponse.PerPage ) + { + break; + } + + page++; + } + while ( true ); + } + + private PaginatedResponse ParseContent( + string content, + ElvantoResourceAttribute elvantoResource, + List fields ) where T : ElvantoContract + { + var document = JsonDocument.Parse( content ); + + if ( document == null ) + { + throw new Exception( "Could not parse JSON" ); + } + + var response = new PaginatedResponse(); + + var root = document.RootElement; + root.TryGetProperty( elvantoResource.PluralName, out var plural ); + + + if ( plural.TryGetProperty( "total", out var totalElement ) && totalElement.ValueKind == JsonValueKind.Number && totalElement.TryGetInt32( out var total ) ) + { + response.Total = total; + } + + if ( plural.TryGetProperty( "page", out var pageElement ) && pageElement.ValueKind == JsonValueKind.Number && pageElement.TryGetInt32( out var page ) ) + { + response.Page = page; + } + + if ( plural.TryGetProperty( "per_page", out var perpageElement ) && perpageElement.ValueKind == JsonValueKind.Number && perpageElement.TryGetInt32( out var perpage ) ) + { + response.PerPage = perpage; + } + + if ( plural.TryGetProperty( "on_this_page", out var onthisPageElement ) && onthisPageElement.ValueKind == JsonValueKind.Number && onthisPageElement.TryGetInt32( out var onthisPage ) ) + { + response.OnThisPage = onthisPage; + } + + if ( plural.TryGetProperty( elvantoResource.SingleName, out var dataset ) ) + { + var dataElements = dataset.EnumerateArray(); + foreach ( var dataElement in dataElements ) + { + var item = dataElement.Deserialize(); + + if ( item == null ) + { + continue; + } + + response.Data.Add( item ); + + item.Process( dataElement, fields ); + + } + } + + return response; + } + + private string GetFieldsString( List fields ) + { + StringBuilder stringBuilder = new StringBuilder(); + for ( var i = 0; i < fields.Count; i++ ) + { + stringBuilder.Append( $"&fields[{i}]={fields[i]}" ); + } + return stringBuilder.ToString(); + } + +} \ No newline at end of file diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/Category.cs b/Slingshot.Elvanto/LibElvanto/Contracts/Category.cs new file mode 100644 index 0000000..9c50f37 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/Category.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using LibElvanto.Attributes; + +namespace LibElvanto.Contracts; + +[ElvantoResource( "https://api.elvanto.com/v1/people/categories/getAll.json", "categories", "category" )] +public class Category : ElvantoContract +{ + [JsonPropertyName("id")] + public string? Id { get; set; } + + [JsonPropertyName("name")] + public string? Name { get; set; } +} \ No newline at end of file diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/CustomFields.cs b/Slingshot.Elvanto/LibElvanto/Contracts/CustomFields.cs new file mode 100644 index 0000000..0d559cf --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/CustomFields.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using LibElvanto.Attributes; + +namespace LibElvanto.Contracts; + +[ElvantoResource( "https://api.elvanto.com/v1/people/customFields/getAll.json", "custom_fields", "custom_field" )] +public class CustomFields : ElvantoContract +{ + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "name" )] + public string? Name { get; set; } + + [JsonPropertyName( "type" )] + public string? Type { get; set; } + + [JsonPropertyName( "values" )] + public dynamic? Values { get; set; } +} + +public class Value +{ + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "name" )] + public string? Name { get; set; } +} + +public class Values +{ + [JsonPropertyName( "value" )] + public List? Value { get; set; } +} + diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/ElvantoContract.cs b/Slingshot.Elvanto/LibElvanto/Contracts/ElvantoContract.cs new file mode 100644 index 0000000..041a693 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/ElvantoContract.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace LibElvanto.Contracts; + +public abstract class ElvantoContract +{ + public Dictionary AttributeValues { get; set; } = new Dictionary(); + + public virtual void Process( JsonElement dataElement, List? fields ) + { + + } + +} diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/FinancialCategory.cs b/Slingshot.Elvanto/LibElvanto/Contracts/FinancialCategory.cs new file mode 100644 index 0000000..a84bd12 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/FinancialCategory.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using LibElvanto.Attributes; + +namespace LibElvanto.Contracts; + +[ElvantoResource( "https://api.elvanto.com/v1/financial/categories/getAll.json", "categories", "category" )] +public class FinancialCategory : ElvantoContract +{ + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "name" )] + public string? Name { get; set; } + +} diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/Group.cs b/Slingshot.Elvanto/LibElvanto/Contracts/Group.cs new file mode 100644 index 0000000..f7fec3d --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/Group.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using LibElvanto.Attributes; + +namespace LibElvanto.Contracts; + +[ElvantoResource( "https://api.elvanto.com/v1/groups/getAll.json", "groups", "group", new string[] { + "people", + "locations", + "categories" +} )] +public class Group : ElvantoContract +{ + [JsonPropertyName( "name" )] + public string? Name { get; set; } + + [JsonPropertyName( "description" )] + public string? Description { get; set; } + + [JsonPropertyName( "status" )] + public string? Status { get; set; } + + [JsonPropertyName( "meeting_address" )] + public string? MeetingAddress { get; set; } + + [JsonPropertyName( "meeting_city" )] + public string? MeetingCity { get; set; } + + [JsonPropertyName( "meeting_state" )] + public string? MeetingState { get; set; } + + [JsonPropertyName( "meeting_postcode" )] + public string? MeetingPostcode { get; set; } + + [JsonPropertyName( "meeting_country" )] + public string? MeetingCountry { get; set; } + + [JsonPropertyName( "meeting_day" )] + public string? MeetingDay { get; set; } + + [JsonPropertyName( "meeting_time" )] + public string? MeetingTime { get; set; } + + [JsonPropertyName( "meeting_frequency" )] + public string? MeetingFrequency { get; set; } + + [JsonPropertyName( "picture" )] + public string? Picture { get; set; } + + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + public List GroupMembers { get; set; } = new List(); + + public IdNameContract? Campus { get; set; } + + public IdNameContract? GroupType { get; set; } + + public override void Process( JsonElement dataElement, List? fields ) + { + if ( dataElement.TryGetProperty( "locations", out var locations ) ) + { + if ( locations.ValueKind == JsonValueKind.Object + && locations.TryGetProperty( "location", out var location ) + && location.ValueKind == JsonValueKind.Array ) + { + + var campus = location.EnumerateArray().FirstOrDefault(); + if ( campus.ValueKind == JsonValueKind.Object ) + { + this.Campus = campus.Deserialize(); + } + } + } + + if ( dataElement.TryGetProperty( "categories", out var categories ) ) + { + if ( categories.ValueKind == JsonValueKind.Object + && categories.TryGetProperty( "category", out var category ) + && category.ValueKind == JsonValueKind.Array ) + { + + var categoryItem = category.EnumerateArray().FirstOrDefault(); + if ( categoryItem.ValueKind == JsonValueKind.Object ) + { + this.GroupType = categoryItem.Deserialize(); + } + } + } + + if ( dataElement.TryGetProperty( "people", out var people ) ) + { + if ( people.ValueKind == JsonValueKind.Object + && people.TryGetProperty( "person", out var person ) + && person.ValueKind == JsonValueKind.Array ) + { + + var persons = person.EnumerateArray(); + foreach ( var personItem in persons ) + { + if ( personItem.ValueKind == JsonValueKind.Object ) + { + var groupMember = personItem.Deserialize(); + if ( groupMember != null ) + { + this.GroupMembers.Add( groupMember ); + } + } + } + + } + } + } + +} + +public class GroupMember +{ + [JsonPropertyName( "firstname" )] + public string? Firstname { get; set; } + + [JsonPropertyName( "preferred_name" )] + public string? PreferredName { get; set; } + + [JsonPropertyName( "middle_name" )] + public string? MiddleName { get; set; } + + [JsonPropertyName( "lastname" )] + public string? Lastname { get; set; } + + [JsonPropertyName( "email" )] + public string? Email { get; set; } + + [JsonPropertyName( "mobile" )] + public string? Mobile { get; set; } + + [JsonPropertyName( "phone" )] + public string? Phone { get; set; } + + [JsonPropertyName( "picture" )] + public string? Picture { get; set; } + + [JsonPropertyName( "position" )] + public string? Position { get; set; } + + [JsonPropertyName( "id" )] + public string? Id { get; set; } +} + + diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/IdNameContract.cs b/Slingshot.Elvanto/LibElvanto/Contracts/IdNameContract.cs new file mode 100644 index 0000000..995262c --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/IdNameContract.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace LibElvanto.Contracts; + +public class IdNameContract +{ + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "name" )] + public string? Name { get; set; } +} diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/PaginatedResponse.cs b/Slingshot.Elvanto/LibElvanto/Contracts/PaginatedResponse.cs new file mode 100644 index 0000000..f866efc --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/PaginatedResponse.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace LibElvanto.Contracts +{ + internal class PaginatedResponse + { + public int OnThisPage { get; set; } = 0; + public int Page { get; set; } = 0; + public int PerPage { get; set; } = 0; + public int Total { get; set; } = 0; + + public List Data { get; set; } = new List(); + } +} diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/Person.cs b/Slingshot.Elvanto/LibElvanto/Contracts/Person.cs new file mode 100644 index 0000000..9648e05 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/Person.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using LibElvanto.Attributes; + +namespace LibElvanto.Contracts; + +[ElvantoResource( "https://api.elvanto.com/v1/people/getAll.json", "people", "person", new string[] { +"gender", +"birthday", +"anniversary", +"school_grade", +"marital_status", +"home_address", +"home_address2", +"home_city", +"home_state", +"home_postcode", +"home_country", +"locations", +"family" +} )] +public class Person : ElvantoContract +{ + [JsonPropertyName( "date_added" )] + public string? DateAdded { get; set; } + + public string DateAddedFormatted { get => FormatDate( DateAdded ); } + + [JsonPropertyName( "date_modified" )] + public string? DateModified { get; set; } + public string DateModifiedFormatted { get => FormatDate( DateModified ); } + + + [JsonPropertyName( "firstname" )] + public string? Firstname { get; set; } + + [JsonPropertyName( "preferred_name" )] + public string? PreferredName { get; set; } + + [JsonPropertyName( "middle_name" )] + public string? MiddleName { get; set; } + + [JsonPropertyName( "lastname" )] + public string? Lastname { get; set; } + + [JsonPropertyName( "email" )] + public string? Email { get; set; } + + [JsonPropertyName( "phone" )] + public string? Phone { get; set; } + + [JsonPropertyName( "mobile" )] + public string? Mobile { get; set; } + + [JsonPropertyName( "status" )] + public string? Status { get; set; } + + [JsonPropertyName( "username" )] + public string? Username { get; set; } + + [JsonPropertyName( "last_login" )] + public string? LastLogin { get; set; } + + [JsonPropertyName( "timezone" )] + public string? Timezone { get; set; } + + [JsonPropertyName( "picture" )] + public string? Picture { get; set; } + + [JsonPropertyName( "family_relationship" )] + public string? FamilyRelationship { get; set; } + + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "category_id" )] + public string? CategoryId { get; set; } + + [JsonPropertyName( "admin" )] + public int? Admin { get; set; } + + [JsonPropertyName( "contact" )] + public int? Contact { get; set; } + + [JsonPropertyName( "archived" )] + public int? Archived { get; set; } + + [JsonPropertyName( "deceased" )] + public int? Deceased { get; set; } + + [JsonPropertyName( "volunteer" )] + public int? Volunteer { get; set; } + + [JsonPropertyName( "family_id" )] + public string? FamilyId { get; set; } + + [JsonPropertyName( "gender" )] + public string? Gender { get; set; } + + [JsonPropertyName( "home_address" )] + public string? Address { get; set; } + + [JsonPropertyName( "home_address2" )] + public string? Address2 { get; set; } + + [JsonPropertyName( "home_city" )] + public string? City { get; set; } + + [JsonPropertyName( "home_state" )] + public string State { get; set; } + + [JsonPropertyName( "home_postcode" )] + public string? PostCode { get; set; } + + [JsonPropertyName( "home_country" )] + public string? Country { get; set; } + + public string? Grade { get; set; } + + [JsonPropertyName( "marital_status" )] + public string? MaritalStatus { get; set; } + + [JsonPropertyName( "birthday" )] + public string? Birthday { get; set; } + + public string BirthdayFormatted { get => FormatDate( Birthday ); } + + public IdNameContract? Campus { get; set; } + + public override void Process( JsonElement dataElement, List? fields ) + { + + var customFields = fields?.Where( f => f.StartsWith( "custom_" ) ).ToList() ?? new List(); + + foreach ( var field in customFields ) + { + dataElement.TryGetProperty( field, out var value ); + if ( value.ValueKind == JsonValueKind.String ) + { + this.AttributeValues[field.Replace( "custom_", "" )] = value.ToString(); + } + else if ( value.TryGetProperty( "name", out var valueValue ) ) + { + this.AttributeValues[field.Replace( "custom_", "" )] = valueValue.ToString(); + } + } + + if ( dataElement.TryGetProperty( "school_grade", out var schoolGrade ) ) + { + if ( schoolGrade.ValueKind != JsonValueKind.String + && schoolGrade.TryGetProperty( "name", out var gradeName ) ) + { + this.Grade = gradeName.ToString(); + } + } + + if ( dataElement.TryGetProperty( "locations", out var locations ) ) + { + if ( locations.ValueKind == JsonValueKind.Object + && locations.TryGetProperty( "location", out var location ) + && location.ValueKind == JsonValueKind.Array ) + { + + var campus = location.EnumerateArray().FirstOrDefault(); + if ( campus.ValueKind == JsonValueKind.Object ) + { + this.Campus = campus.Deserialize(); + } + } + } + } + + public string GetRecordStatus() + { + if (this.Archived == 1 ) + { + return "Inactive"; + } + return "Active"; + } + + private string FormatDate( string? date ) + { + if ( date == null ) + { + return string.Empty; + } + + try + { + return DateTime.Parse( date ).ToString( "M/d/yyyy" ); + } + catch + { + return string.Empty; + } + } +} diff --git a/Slingshot.Elvanto/LibElvanto/Contracts/Transaction.cs b/Slingshot.Elvanto/LibElvanto/Contracts/Transaction.cs new file mode 100644 index 0000000..338390e --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Contracts/Transaction.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using LibElvanto.Attributes; + +namespace LibElvanto.Contracts; + +[ElvantoResource( "https://api.elvanto.com/v1/financial/transactions/getAll.json", "transactions", "transaction" )] + +public class Transaction : ElvantoContract +{ + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "person_id" )] + public string? PersonId { get; set; } + + [JsonPropertyName( "transaction_date" )] + public DateTime? TransactionDate { get; set; } + + [JsonPropertyName( "transaction_method" )] + public string? TransactionMethod { get; set; } + + [JsonPropertyName( "check_number" )] + public string? CheckNumber { get; set; } + + [JsonPropertyName( "batch" )] + public Batch? Batch { get; set; } + + [JsonPropertyName( "transaction_total" )] + public string? TransactionTotal { get; set; } + + [JsonPropertyName( "amounts" )] + public Amounts? Amounts { get; set; } +} + + +public class Amount +{ + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "category" )] + public IdNameContract? Category { get; set; } + + [JsonPropertyName( "total" )] + public string? Total { get; set; } + + [JsonPropertyName( "tax_deductible" )] + public int? TaxDeductible { get; set; } + + [JsonPropertyName( "memo" )] + public string? Memo { get; set; } + + [JsonPropertyName( "external_notes" )] + public string? ExternalNotes { get; set; } +} + +public class Amounts +{ + [JsonPropertyName( "amount" )] + public List? Amount { get; set; } +} + +public class Batch +{ + [JsonPropertyName( "id" )] + public string? Id { get; set; } + + [JsonPropertyName( "number" )] + public string? Number { get; set; } + + [JsonPropertyName( "name" )] + public string? Name { get; set; } +} diff --git a/Slingshot.Elvanto/LibElvanto/Financial/FinancialBatch.cs b/Slingshot.Elvanto/LibElvanto/Financial/FinancialBatch.cs new file mode 100644 index 0000000..cf694e8 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Financial/FinancialBatch.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibElvanto.Financial; + +public class FinancialBatch +{ + public int Id { get; set; } + public string? Name { get; set; } + public int? CampusId { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public string? Status { get; set; } = "Closed"; + public int? ModifiedByPersonId { get; set; } + public string? ModifiedDateTime { get; set; } + public int ControlAmount { get; set; } = 0; +} diff --git a/Slingshot.Elvanto/LibElvanto/Financial/FinancialTransaction.cs b/Slingshot.Elvanto/LibElvanto/Financial/FinancialTransaction.cs new file mode 100644 index 0000000..e9b774c --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Financial/FinancialTransaction.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + + +namespace LibElvanto.Financial; + +public class FinancialTransaction +{ + public int? Id { get; set; } + public int? BatchId { get; set; } + public int? AuthorizedPersonId { get; set; } + public DateTime? TransactionDate { get; set; } + public string? TransactionType { get; set; } = "Contribution"; + public string? TransactionSource { get; set; } = "Website"; + public string? CurrencyType { get; set; } + public string? Summary { get; set; } + public string? TransactionCode { get; set; } + public int? CreatedByPersonId { get; set; } + public DateTime? CreatedDateTime { get; set; } + public int? ModifiedByPersonId { get; set; } + public string? ModifiedDateTime { get; set; } + + public decimal Total { get; set; } = 0; +} \ No newline at end of file diff --git a/Slingshot.Elvanto/LibElvanto/Financial/FinancialTransactionDetail.cs b/Slingshot.Elvanto/LibElvanto/Financial/FinancialTransactionDetail.cs new file mode 100644 index 0000000..ec6c4db --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Financial/FinancialTransactionDetail.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + + +namespace LibElvanto.Financial; + +public class FinancialTransactionDetail +{ + public int? Id { get; set; } + public int? TransactionId { get; set; } + public int? AccountId { get; set; } + public decimal? Amount { get; set; } + public string? Summary { get; set; } + public int? CreatedByPersonId { get; set; } + public string? CreatedDateTime { get; set; } + public int? ModifiedByPersonId { get; set; } + public string? ModifiedDateTime { get; set; } +} \ No newline at end of file diff --git a/Slingshot.Elvanto/LibElvanto/LibElvanto.csproj b/Slingshot.Elvanto/LibElvanto/LibElvanto.csproj new file mode 100644 index 0000000..59f7563 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/LibElvanto.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/Slingshot.Elvanto/LibElvanto/Utilities/CountryAbbreviation.cs b/Slingshot.Elvanto/LibElvanto/Utilities/CountryAbbreviation.cs new file mode 100644 index 0000000..7589244 --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Utilities/CountryAbbreviation.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibElvanto.Utilities; + +public static class CountryAbbreviation +{ + private static Dictionary lookup = new Dictionary + { + {"afghanistan", "af"}, + {"åland islands", "ax"}, + {"albania", "al"}, + {"algeria", "dz"}, + {"american samoa", "as"}, + {"andorra", "ad"}, + {"angola", "ao"}, + {"anguilla", "ai"}, + {"antarctica", "aq"}, + {"antigua and barbuda", "ag"}, + {"argentina", "ar"}, + {"armenia", "am"}, + {"aruba", "aw"}, + {"australia", "au"}, + {"austria", "at"}, + {"azerbaijan", "az"}, + {"bahamas", "bs"}, + {"bahrain", "bh"}, + {"bangladesh", "bd"}, + {"barbados", "bb"}, + {"belarus", "by"}, + {"belgium", "be"}, + {"belize", "bz"}, + {"benin", "bj"}, + {"bermuda", "bm"}, + {"bhutan", "bt"}, + {"bolivia", "bo"}, + {"bosnia and herzegovina", "ba"}, + {"botswana", "bw"}, + {"bouvet island", "bv"}, + {"brazil", "br"}, + {"british indian ocean territory", "io"}, + {"brunei darussalam", "bn"}, + {"bulgaria", "bg"}, + {"burkina faso", "bf"}, + {"burundi", "bi"}, + {"cambodia", "kh"}, + {"cameroon", "cm"}, + {"canada", "ca"}, + {"cape verde", "cv"}, + {"cayman islands", "ky"}, + {"central african republic", "cf"}, + {"chad", "td"}, + {"chile", "cl"}, + {"china", "cn"}, + {"christmas island", "cx"}, + {"cocos (keeling) islands", "cc"}, + {"colombia", "co"}, + {"comoros", "km"}, + {"congo", "cg"}, + {"congo, the democratic republic of the", "cd"}, + {"cook islands", "ck"}, + {"costa rica", "cr"}, + {"cote d\"ivoire", "ci"}, + {"croatia", "hr"}, + {"cuba", "cu"}, + {"cyprus", "cy"}, + {"czech republic", "cz"}, + {"denmark", "dk"}, + {"djibouti", "dj"}, + {"dominica", "dm"}, + {"dominican republic", "do"}, + {"ecuador", "ec"}, + {"egypt", "eg"}, + {"el salvador", "sv"}, + {"equatorial guinea", "gq"}, + {"eritrea", "er"}, + {"estonia", "ee"}, + {"ethiopia", "et"}, + {"falkland islands (malvinas)", "fk"}, + {"faroe islands", "fo"}, + {"fiji", "fj"}, + {"finland", "fi"}, + {"france", "fr"}, + {"french guiana", "gf"}, + {"french polynesia", "pf"}, + {"french southern territories", "tf"}, + {"gabon", "ga"}, + {"gambia", "gm"}, + {"georgia", "ge"}, + {"germany", "de"}, + {"ghana", "gh"}, + {"gibraltar", "gi"}, + {"greece", "gr"}, + {"greenland", "gl"}, + {"grenada", "gd"}, + {"guadeloupe", "gp"}, + {"guam", "gu"}, + {"guatemala", "gt"}, + {"guernsey", "gg"}, + {"guinea", "gn"}, + {"guinea-bissau", "gw"}, + {"guyana", "gy"}, + {"haiti", "ht"}, + {"heard island and mcdonald islands", "hm"}, + {"holy see (vatican city state)", "va"}, + {"honduras", "hn"}, + {"hong kong", "hk"}, + {"hungary", "hu"}, + {"iceland", "is"}, + {"india", "in"}, + {"indonesia", "id"}, + {"iran, islamic republic of", "ir"}, + {"iraq", "iq"}, + {"ireland", "ie"}, + {"isle of man", "im"}, + {"israel", "il"}, + {"italy", "it"}, + {"jamaica", "jm"}, + {"japan", "jp"}, + {"jersey", "je"}, + {"jordan", "jo"}, + {"kazakhstan", "kz"}, + {"kenya", "ke"}, + {"kiribati", "ki"}, + {"korea, democratic people\"s republic of", "kp"}, + {"korea, republic of", "kr"}, + {"kuwait", "kw"}, + {"kyrgyzstan", "kg"}, + {"lao people\"s democratic republic", "la"}, + {"latvia", "lv"}, + {"lebanon", "lb"}, + {"lesotho", "ls"}, + {"liberia", "lr"}, + {"libyan arab jamahiriya", "ly"}, + {"liechtenstein", "li"}, + {"lithuania", "lt"}, + {"luxembourg", "lu"}, + {"macao", "mo"}, + {"macedonia, the former yugoslav republic of", "mk"}, + {"madagascar", "mg"}, + {"malawi", "mw"}, + {"malaysia", "my"}, + {"maldives", "mv"}, + {"mali", "ml"}, + {"malta", "mt"}, + {"marshall islands", "mh"}, + {"martinique", "mq"}, + {"mauritania", "mr"}, + {"mauritius", "mu"}, + {"mayotte", "yt"}, + {"mexico", "mx"}, + {"micronesia, federated states of", "fm"}, + {"moldova, republic of", "md"}, + {"monaco", "mc"}, + {"mongolia", "mn"}, + {"montserrat", "ms"}, + {"morocco", "ma"}, + {"mozambique", "mz"}, + {"myanmar", "mm"}, + {"namibia", "na"}, + {"nauru", "nr"}, + {"nepal", "np"}, + {"netherlands", "nl"}, + {"netherlands antilles", "an"}, + {"new caledonia", "nc"}, + {"new zealand", "nz"}, + {"nicaragua", "ni"}, + {"niger", "ne"}, + {"nigeria", "ng"}, + {"niue", "nu"}, + {"norfolk island", "nf"}, + {"northern mariana islands", "mp"}, + {"norway", "no"}, + {"oman", "om"}, + {"pakistan", "pk"}, + {"palau", "pw"}, + {"palestinian territory, occupied", "ps"}, + {"panama", "pa"}, + {"papua new guinea", "pg"}, + {"paraguay", "py"}, + {"peru", "pe"}, + {"philippines", "ph"}, + {"pitcairn", "pn"}, + {"poland", "pl"}, + {"portugal", "pt"}, + {"puerto rico", "pr"}, + {"qatar", "qa"}, + {"reunion", "re"}, + {"romania", "ro"}, + {"russian federation", "ru"}, + {"rwanda", "rw"}, + {"saint helena", "sh"}, + {"saint kitts and nevis", "kn"}, + {"saint lucia", "lc"}, + {"saint pierre and miquelon", "pm"}, + {"saint vincent and the grenadines", "vc"}, + {"samoa", "ws"}, + {"san marino", "sm"}, + {"sao tome and principe", "st"}, + {"saudi arabia", "sa"}, + {"senegal", "sn"}, + {"serbia and montenegro", "cs"}, + {"seychelles", "sc"}, + {"sierra leone", "sl"}, + {"singapore", "sg"}, + {"slovakia", "sk"}, + {"slovenia", "si"}, + {"solomon islands", "sb"}, + {"somalia", "so"}, + {"south africa", "za"}, + {"south georgia and the south sandwich islands", "gs"}, + {"spain", "es"}, + {"sri lanka", "lk"}, + {"sudan", "sd"}, + {"suriname", "sr"}, + {"svalbard and jan mayen", "sj"}, + {"swaziland", "sz"}, + {"sweden", "se"}, + {"switzerland", "ch"}, + {"syrian arab republic", "sy"}, + {"taiwan, province of china", "tw"}, + {"tajikistan", "tj"}, + {"tanzania, united republic of", "tz"}, + {"thailand", "th"}, + {"timor-leste", "tl"}, + {"togo", "tg"}, + {"tokelau", "tk"}, + {"tonga", "to"}, + {"trinidad and tobago", "tt"}, + {"tunisia", "tn"}, + {"turkey", "tr"}, + {"turkmenistan", "tm"}, + {"turks and caicos islands", "tc"}, + {"tuvalu", "tv"}, + {"uganda", "ug"}, + {"ukraine", "ua"}, + {"united arab emirates", "ae"}, + {"united kingdom", "gb"}, + {"united states", "us"}, + {"united states minor outlying islands", "um"}, + {"uruguay", "uy"}, + {"uzbekistan", "uz"}, + {"vanuatu", "vu"}, + {"venezuela", "ve"}, + {"viet nam", "vn"}, + {"virgin islands, british", "vg"}, + {"virgin islands, u.s.", "vi"}, + {"wallis and futuna", "wf"}, + {"western sahara", "eh"}, + {"yemen", "ye"}, + {"zambia", "zm"}, + {"zimbabwe", "zw"} + + }; + + public static string? GetCode( string? country ) + { + if ( country != null && lookup.ContainsKey( country.ToLower() ) ) + { + return lookup[country.ToLower()].ToUpper(); + } + return country; + } +} diff --git a/Slingshot.Elvanto/LibElvanto/Utilities/IdLookupManager.cs b/Slingshot.Elvanto/LibElvanto/Utilities/IdLookupManager.cs new file mode 100644 index 0000000..4323ffe --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Utilities/IdLookupManager.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibElvanto.Utilities +{ + public class IdLookupManager + { + private int currentInt = 0; + private Dictionary lookup = new Dictionary(); + public IdLookupManager( int startInt = 100 ) + { + currentInt = startInt; + } + + public int GetId( string? key ) + { + if ( string.IsNullOrWhiteSpace( key ) ) + { + return 0; + } + + if ( lookup.ContainsKey( key ) ) + { + return lookup[key]; + } + + lookup.Add( key, currentInt ); + currentInt++; + return lookup[key]; + } + } +} diff --git a/Slingshot.Elvanto/LibElvanto/Utilities/StringExtensions.cs b/Slingshot.Elvanto/LibElvanto/Utilities/StringExtensions.cs new file mode 100644 index 0000000..e56a2df --- /dev/null +++ b/Slingshot.Elvanto/LibElvanto/Utilities/StringExtensions.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using static System.Net.Mime.MediaTypeNames; + +namespace LibElvanto.Utilities; + +public static class StringExtensions +{ + public static decimal AsDecimal( this string? s ) + { + if ( s != null && decimal.TryParse( s, out var value ) ) + { + return value; + } + return 0; + + } + + public static string AsMaritalStatus( this string? s ) + { + if ( string.IsNullOrEmpty( s ) ) + { + return "Unknown"; + } + + var allowed = new List + { + "Married", + "Divorced", + "Single", + "Unknown" + }; + + if ( allowed.Contains( s ) ) + { + return s; + } + + return "Unknown"; + } + + public static string ForCSV( this string? s ) + { + return $"\"{s.Replace( "\"", "\"\"" )}\""; + } + + public static string Truncate( this string value, int maxChars ) + { + return value.Length <= maxChars ? value : value.Substring( 0, maxChars ); + } + + public static string StripHTML( this string input ) + { + return Regex.Replace( input, "<.*?>", String.Empty ); + } + + public static string FormatTime( this string input ) + { + try + { + DateTime dateTime = DateTime.ParseExact( input, "h:mm tt", CultureInfo.InvariantCulture ); + return dateTime.ToString("HH:mm"); + } + catch + { + return string.Empty; + } + } +} diff --git a/Slingshot.Elvanto/Slingshot.Elvanto.sln b/Slingshot.Elvanto/Slingshot.Elvanto.sln new file mode 100644 index 0000000..2490b45 --- /dev/null +++ b/Slingshot.Elvanto/Slingshot.Elvanto.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31611.283 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Slingshot.Elvanto", "Slingshot.Elvanto\Slingshot.Elvanto.csproj", "{ADDAE693-A599-41BE-AB59-C6F674A8E6BA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibElvanto", "LibElvanto\LibElvanto.csproj", "{E77099D8-3A4C-41FB-A572-DF8E77D889B2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ADDAE693-A599-41BE-AB59-C6F674A8E6BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADDAE693-A599-41BE-AB59-C6F674A8E6BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADDAE693-A599-41BE-AB59-C6F674A8E6BA}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {ADDAE693-A599-41BE-AB59-C6F674A8E6BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADDAE693-A599-41BE-AB59-C6F674A8E6BA}.Release|Any CPU.Build.0 = Release|Any CPU + {ADDAE693-A599-41BE-AB59-C6F674A8E6BA}.Release|Any CPU.Deploy.0 = Release|Any CPU + {E77099D8-3A4C-41FB-A572-DF8E77D889B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E77099D8-3A4C-41FB-A572-DF8E77D889B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E77099D8-3A4C-41FB-A572-DF8E77D889B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E77099D8-3A4C-41FB-A572-DF8E77D889B2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} + EndGlobalSection +EndGlobal diff --git a/Slingshot.Elvanto/Slingshot.Elvanto/App.xaml b/Slingshot.Elvanto/Slingshot.Elvanto/App.xaml new file mode 100644 index 0000000..1c7d465 --- /dev/null +++ b/Slingshot.Elvanto/Slingshot.Elvanto/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/Slingshot.Elvanto/Slingshot.Elvanto/App.xaml.cs b/Slingshot.Elvanto/Slingshot.Elvanto/App.xaml.cs new file mode 100644 index 0000000..57b5597 --- /dev/null +++ b/Slingshot.Elvanto/Slingshot.Elvanto/App.xaml.cs @@ -0,0 +1,11 @@ +namespace Slingshot.Elvanto; + +public partial class App : Application +{ + public App() + { + InitializeComponent(); + + MainPage = new AppShell(); + } +} diff --git a/Slingshot.Elvanto/Slingshot.Elvanto/AppShell.xaml b/Slingshot.Elvanto/Slingshot.Elvanto/AppShell.xaml new file mode 100644 index 0000000..c1c74bd --- /dev/null +++ b/Slingshot.Elvanto/Slingshot.Elvanto/AppShell.xaml @@ -0,0 +1,14 @@ + + + + + + diff --git a/Slingshot.Elvanto/Slingshot.Elvanto/AppShell.xaml.cs b/Slingshot.Elvanto/Slingshot.Elvanto/AppShell.xaml.cs new file mode 100644 index 0000000..7279102 --- /dev/null +++ b/Slingshot.Elvanto/Slingshot.Elvanto/AppShell.xaml.cs @@ -0,0 +1,10 @@ +namespace Slingshot.Elvanto; + +public partial class AppShell : Shell +{ + public AppShell() + { + SetNavBarIsVisible(this,false); + InitializeComponent(); + } +} diff --git a/Slingshot.Elvanto/Slingshot.Elvanto/MainPage.xaml b/Slingshot.Elvanto/Slingshot.Elvanto/MainPage.xaml new file mode 100644 index 0000000..67a482e --- /dev/null +++ b/Slingshot.Elvanto/Slingshot.Elvanto/MainPage.xaml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + +