VOOZH about

URL: https://www.nuget.org/packages/Endjin.FreeAgent.Client.Extensions/

⇱ NuGet Gallery | Endjin.FreeAgent.Client.Extensions 1.0.5




👁 Image
Endjin.FreeAgent.Client.Extensions 1.0.5

dotnet add package Endjin.FreeAgent.Client.Extensions --version 1.0.5
 
 
NuGet\Install-Package Endjin.FreeAgent.Client.Extensions -Version 1.0.5
 
 
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Endjin.FreeAgent.Client.Extensions" Version="1.0.5" />
 
 
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Endjin.FreeAgent.Client.Extensions" Version="1.0.5" />
 
Directory.Packages.props
<PackageReference Include="Endjin.FreeAgent.Client.Extensions" />
 
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Endjin.FreeAgent.Client.Extensions --version 1.0.5
 
 
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Endjin.FreeAgent.Client.Extensions, 1.0.5"
 
 
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Endjin.FreeAgent.Client.Extensions@1.0.5
 
 
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Endjin.FreeAgent.Client.Extensions&version=1.0.5
 
Install as a Cake Addin
#tool nuget:?package=Endjin.FreeAgent.Client.Extensions&version=1.0.5
 
Install as a Cake Tool
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Endjin.FreeAgent.Client.Extensions

Extension methods and additional functionality for the Endjin.FreeAgent.Client library, providing enhanced features for working with the FreeAgent API.

Features

  • Extension Members - .NET 10 extension member support for FreeAgent client
  • Timesheets Module - Comprehensive timesheet management and aggregation
  • Project Extensions - Advanced project filtering with flexible rule-based system
  • User Settings - Employee payroll configuration and management
  • Activity Summaries - Time tracking and activity reporting
  • Flexible Architecture - Extensible registry pattern for adding custom modules

Installation

Install via NuGet Package Manager:

dotnet add package Endjin.FreeAgent.Client.Extensions

Or via Package Manager Console:

Install-Package Endjin.FreeAgent.Client.Extensions

Quick Start

Timesheets Extension

The Timesheets extension provides comprehensive time tracking functionality:

using Endjin.FreeAgent.Client;
using Endjin.FreeAgent.Client.Extensions.Extensions;
using Endjin.FreeAgent.Domain.Extensions;
using Microsoft.Extensions.Caching.Memory;
using Spectre.IO;

// Create FilePath for employee profile
FilePath employeeProfilePath = new("Artefacts/example-employee-payroll.yml");

// Initialize client with Timesheets extension
FreeAgentClient client = FreeAgentClient.CreateWithTimesheets(
 options,
 cache,
 httpClientFactory,
 loggerFactory,
 employeeProfilePath);

// Or add to existing client
client.WithTimesheets(cache, employeeProfilePath);

// Get timesheets for current week
List<WeeklyTimesheet> weeklyTimesheets = await client.Timesheets
 .GetTimesheetsForCurrentWeekAsync();

// Get timesheets for specific week
List<WeeklyTimesheet> specificWeek = await client.Timesheets
 .GetTimeslipsForYearAndWeekNumberAsync(2024, 42);

// Get monthly timesheets
List<MonthlyTimesheet> monthlyTimesheets = await client.Timesheets
 .GetTimesheetsForMonthAsync(DateTime.Now.Year, DateTime.Now.Month);

Project Extensions

Advanced project filtering with flexible rule-based system:

using Endjin.FreeAgent.Client.Extensions;
using Endjin.FreeAgent.Client.Extensions.Extensions;

// Register projects extension
client.WithProjectsExtended(cache);

// Configure project filtering with rules
var filterOptions = new ProjectFilterOptions
{
 Rules = new[]
 {
 // Exclude projects with specific name prefixes
 new FilterRule(FilterField.ProjectName, FilterRuleType.Prefix, "test", FilterAction.Exclude),
 new FilterRule(FilterField.ProjectName, FilterRuleType.Prefix, "demo", FilterAction.Exclude),

 // Exclude projects containing certain keywords
 new FilterRule(FilterField.ProjectName, FilterRuleType.Contains, "internal", FilterAction.Exclude),

 // Use regex for complex patterns
 new FilterRule(FilterField.ProjectName, FilterRuleType.Regex, @"^(DEV|TEST)-\d{3}-",
 FilterAction.Exclude, caseSensitive: true)
 },
 ExcludedProjectIds = new[] { "999", "888" },
 RequireContactEntry = true,
 RequireProjectName = true,
 RequireOrganizationName = false
};

// Get filtered active projects
IEnumerable<Project> filteredProjects = await client.Projects.GetIncludedActiveAsync(filterOptions);

// Get detailed project information using NodaTime DateInterval
using NodaTime;

LocalDate start = LocalDate.FromDateTime(DateTime.Now.AddMonths(-1));
LocalDate end = LocalDate.FromDateTime(DateTime.Now);
DateInterval range = new DateInterval(start, end);

List<ProjectDetails> projectDetails = await client.ProjectsExtended
 .GetAllProjectDetailsAsync(range);

foreach (ProjectDetails details in projectDetails)
{
 Console.WriteLine($"Project: {details.Project.Name}");
 Console.WriteLine($" Total Hours: {details.TotalHours}");
 Console.WriteLine($" Total Cost: {details.TotalCost:C}");
}

User Settings

Manage employee payroll configuration from YAML:

using Endjin.FreeAgent.Client.Extensions.Extensions;
using Endjin.FreeAgent.Domain.Extensions;
using Spectre.IO;

// Create FilePath for employee profile
FilePath employeeProfilePath = new("Artefacts/example-employee-payroll.yml");

// Initialize user settings service
client.WithUserSettings(cache, employeeProfilePath);

// Access via extension property
UserSettingsService settingsService = client.UserSettings;

// Get all user settings (async methods)
List<UserSettings> allUsers = await settingsService.GetAllUserSettingsAsync();

// Get only directors
List<UserSettings> directors = await settingsService.GetAllDirectorsUserSettingsAsync();

// Get active employees (excluding directors)
List<UserSettings> employees = await settingsService.GetAllActiveEmployeeUserSettingsAsync();

// Work with user settings
foreach (UserSettings user in allUsers)
{
 // Use extension members
 string fullName = user.FullName; // Extension member property
 bool isActive = user.IsActive; // Extension member property

 Console.WriteLine($"{fullName} - Active: {isActive}");

 // Access roles
 EmploymentRole? currentRole = user.Roles
 .OrderBy(r => r.StartDate)
 .LastOrDefault(r => r.EndDate == null);

 if (currentRole != null)
 {
 Console.WriteLine($" Role: {currentRole.Title}");
 Console.WriteLine($" Cost: {currentRole.Cost:C}");
 }
}

Extension Registry

The extension registry pattern allows for modular functionality:

// Check if extensions are available
if (client.HasTimesheets)
{
 Timesheets timesheets = client.Timesheets;
 // Use timesheet functionality
}

// Check extension count
int count = client.ExtensionCount;
Console.WriteLine($"Loaded {count} extensions");

// Get all extension types
IReadOnlyCollection<Type> extensions = client.Extensions;

// Register all extensions at once
FilePath employeeProfilePath = new("Artefacts/example-employee-payroll.yml");
client.WithAllExtensions(cache, employeeProfilePath);

Advanced Features

Activity Summaries

Aggregate time tracking data:

// Get timesheet activity for a user
TimesheetActivitySummary summary = await client.Timesheets.GetTimesheetActivityAsync(
 userId: "123",
 fromDate: "2024-01-01",
 toDate: "2024-01-31");

Console.WriteLine($"Total Hours: {summary.TotalHours}");
Console.WriteLine($"Total Projects: {summary.ProjectCount}");

// Get weekly timesheet activity
TimesheetActivitySummary weeklySummary = await client.Timesheets
 .GetWeeklyTimesheetActivityAsync("123", 2024, 42);

Weekly and Monthly Aggregations

// Get last week's timesheets
List<WeeklyTimesheet> lastWeek = await client.Timesheets.GetTimesheetsForLastWeekAsync();

foreach (WeeklyTimesheet timesheet in lastWeek)
{
 // Use extension members for calculations
 decimal hours = timesheet.CalculateHours();
 bool isValid = timesheet.IsValid(); // Validates against 40-hour week

 string userName = $"{timesheet.User?.FirstName} {timesheet.User?.LastName}";
 Console.WriteLine($"{userName}: {hours}h (Valid: {isValid})");

 // Access individual timeslips
 if (timesheet.Timeslips != null)
 {
 foreach (Timeslip slip in timesheet.Timeslips)
 {
 Console.WriteLine($" {slip.Project}: {slip.Hours}h");
 }
 }
}

// Get current month's timesheets
List<MonthlyTimesheet> currentMonth = await client.Timesheets
 .GetTimesheetsForCurrentMonthAsync();

foreach (MonthlyTimesheet monthly in currentMonth)
{
 decimal hours = monthly.CalculateHours();
 decimal target = monthly.TargetHours(); // MonthlyTimesheet has TargetHours() method
 bool isValid = monthly.IsValid();

 Console.WriteLine($"Month {monthly.MonthOfYear}: {hours}h / {target}h (Valid: {isValid})");
}

// Get full year timesheet
Timesheet yearlyTimesheet = await client.Timesheets.GetTimeslipsForYearAsync(2024);

Project Filtering Rules

The filtering system supports multiple rule types and actions:

// Available FilterRuleTypes:
// - Prefix: Matches if field starts with pattern
// - Suffix: Matches if field ends with pattern
// - Contains: Matches if field contains pattern
// - Exact: Matches if field exactly equals pattern
// - Regex: Matches using regular expression

// Available FilterActions:
// - Exclude: Exclude matching projects
// - Include: Include matching projects (stops processing further rules)
// - RequireExplicitInclusion: Only include if project ID is in explicit inclusion list

var advancedFilters = new ProjectFilterOptions
{
 Rules = new[]
 {
 // Exclude test projects
 new FilterRule(FilterField.ProjectName, FilterRuleType.Prefix, "TEST-", FilterAction.Exclude),

 // Require explicit inclusion for partner projects
 new FilterRule(FilterField.OrganizationName, FilterRuleType.Contains, "Partner",
 FilterAction.RequireExplicitInclusion)
 {
 ExplicitInclusions = new[] { "proj-123", "proj-456" }
 },

 // Include specific projects by exact name
 new FilterRule(FilterField.ProjectName, FilterRuleType.Exact, "Important Project",
 FilterAction.Include)
 },
 ExcludedProjectIds = new[] { "excluded-1", "excluded-2" },
 RequireContactEntry = true,
 RequireProjectName = true
};

IEnumerable<Project> projects = await client.Projects.GetIncludedActiveAsync(advancedFilters);

Loading Filter Configuration from JSON

You can also load filter rules from a JSON configuration file:

// Load from JSON configuration
string json = await File.ReadAllTextAsync("project-filters.json");
ProjectFilterConfiguration config = ProjectFilterConfiguration.LoadFromJson(json);
ProjectFilterOptions filterOptions = config.ToFilterOptions();

// Apply configured filters
IEnumerable<Project> projects = await client.Projects.GetIncludedActiveAsync(filterOptions);

Example project-filters.json:

{
 "rules": [
 {
 "field": "projectName",
 "type": "prefix",
 "pattern": "test",
 "action": "exclude",
 "isCaseSensitive": false
 },
 {
 "field": "organizationName",
 "type": "regex",
 "pattern": "^(Partner|Vendor)-",
 "action": "requireExplicitInclusion",
 "isCaseSensitive": true,
 "explicitInclusions": ["123", "456"]
 }
 ],
 "excludedProjectIds": ["999"],
 "requireContactEntry": true,
 "requireProjectName": true,
 "requireOrganizationName": false
}

Extension Members (C# 14)

This library leverages .NET 10's extension members feature for cleaner API design:

// Extension members provide direct access to extended functionality
client.Timesheets // Access Timesheets extension
client.ProjectsExtended // Access ProjectsExtended extension
client.UserSettings // Access UserSettingsService extension

// Check if extensions are loaded
bool hasTimesheets = client.HasTimesheets;
bool hasProjects = client.HasProjectsExtended;
bool hasUserSettings = client.HasUserSettings;

// Extension member properties on domain objects
WeeklyTimesheet weekly = /* ... */;
decimal hours = weekly.CalculateHours(); // Extension member method
bool valid = weekly.IsValid(); // Extension member method

UserSettings user = /* ... */;
string fullName = user.FullName; // Extension member property
bool active = user.IsActive; // Extension member property

Factory Methods

Multiple ways to create clients with extensions:

using Spectre.IO;

// Create FilePath for employee profile
FilePath employeeProfilePath = new("Artefacts/employee-payroll.yml");

// Create with Timesheets only
FreeAgentClient client1 = FreeAgentClient.CreateWithTimesheets(
 options, cache, httpClientFactory, loggerFactory,
 employeeProfilePath);

// Create with Projects only
FreeAgentClient client2 = FreeAgentClient.CreateWithProjectsExtended(
 options, cache, httpClientFactory, loggerFactory);

// Create with UserSettings only
FreeAgentClient client3 = FreeAgentClient.CreateWithUserSettings(
 options, cache, httpClientFactory, loggerFactory,
 employeeProfilePath);

// Create with selective extensions
FreeAgentClient client4 = FreeAgentClient.CreateWithExtensions(
 options, cache, httpClientFactory, loggerFactory,
 employeeProfilePath,
 includeTimesheets: true,
 includeProjectsExtended: true,
 includeUserSettings: false);

// Create with all extensions
FreeAgentClient client5 = FreeAgentClient.CreateFullyExtended(
 options, cache, httpClientFactory, loggerFactory,
 employeeProfilePath);

UserSettings YAML Configuration

The UserSettings service loads employee configuration from YAML:

# Artefacts/example-employee-payroll.yml
- id: "usr_12345"
 firstName: "Emma"
 lastName: "Thompson"
 salutation: "Dr"
 middleInitials: "J"
 address: "123 Main Street"
 payRef: "EMP001"
 isDirector: true
 startDate: 2020-01-15
 roles:
 - title: "Software Engineer"
 cost: 65000
 startDate: 2020-01-15
 endDate: 2022-06-30
 - title: "Senior Engineer"
 cost: 85000
 startDate: 2022-07-01

UserSettings properties:

  • Id - User identifier
  • FirstName - Employee first name
  • LastName - Employee last name
  • Salutation - Title (Dr, Mr, Ms, etc.)
  • MiddleInitials - Middle name initials
  • Address - Employee address
  • PayRef - Payroll reference
  • IsDirector - Whether employee is a director
  • StartDate - Employment start date
  • EndDate - Employment end date (if applicable)
  • Roles - List of employment roles with title, cost, start/end dates

Requirements

  • .NET 10.0 or later
  • Endjin.FreeAgent.Client
  • Endjin.FreeAgent.Domain

License

This project is licensed under the Apache License 2.0 - see the file for details.

Support

For support, please contact Endjin Limited or raise an issue on our GitHub repository.


Copyright (c) Endjin Limited. All rights reserved.

Product Versions Compatible and additional computed target framework versions.
.NET net10.0 net10.0 is compatible.  net10.0-android net10.0-android was computed.  net10.0-browser net10.0-browser was computed.  net10.0-ios net10.0-ios was computed.  net10.0-maccatalyst net10.0-maccatalyst was computed.  net10.0-macos net10.0-macos was computed.  net10.0-tvos net10.0-tvos was computed.  net10.0-windows net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.5 353 11/21/2025
1.0.4 271 11/16/2025
1.0.3 264 11/16/2025
1.0.2 264 11/16/2025
1.0.1 203 11/15/2025
1.0.0 323 11/13/2025
1.0.0-preview.2 182 9/23/2025