Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,7 @@ $RECYCLE.BIN/
!.vscode/extensions.json

appsettings.local*.json

# Claude Code configuration
CLAUDE.local.md
.claude
103 changes: 103 additions & 0 deletions src/TrueLayer/Common/UltimateCounterparty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System.Text.Json.Serialization;
using TrueLayer.Serialization;

namespace TrueLayer.Common
{
/// <summary>
/// Represents the ultimate counterparty details for sub-merchants
/// </summary>
public abstract record UltimateCounterparty
{
/// <summary>
/// Gets the type of the ultimate counterparty
/// </summary>
[JsonPropertyName("type")]
public abstract string Type { get; }
}

/// <summary>
/// Represents business client details for the ultimate counterparty
/// </summary>
[JsonDiscriminator("business_client")]
public record UltimateCounterpartyBusinessClient : UltimateCounterparty
{
/// <summary>
/// Creates a new <see cref="UltimateCounterpartyBusinessClient"/>
/// </summary>
/// <param name="commercialName">The commercial name of the business</param>
/// <param name="mcc">The merchant category code of the business</param>
/// <param name="address">The address of the business (required if registration_number is not provided)</param>
/// <param name="registrationNumber">The registration number of the business (required if address is not provided)</param>
public UltimateCounterpartyBusinessClient(
string commercialName,
string? mcc = null,
Address? address = null,
string? registrationNumber = null)
{
CommercialName = commercialName.NotNullOrWhiteSpace(nameof(commercialName));
Mcc = mcc;
Address = address;
RegistrationNumber = registrationNumber;
}

/// <inheritdoc />
public override string Type => "business_client";

/// <summary>
/// Gets the commercial name of the business
/// </summary>
[JsonPropertyName("commercial_name")]
public string CommercialName { get; }

/// <summary>
/// Gets the merchant category code of the business
/// </summary>
[JsonPropertyName("mcc")]
public string? Mcc { get; }

/// <summary>
/// Gets the address of the business
/// </summary>
[JsonPropertyName("address")]
public Address? Address { get; }

/// <summary>
/// Gets the registration number of the business
/// </summary>
[JsonPropertyName("registration_number")]
public string? RegistrationNumber { get; }
}

/// <summary>
/// Represents business division details for the ultimate counterparty
/// </summary>
[JsonDiscriminator("business_division")]
public record UltimateCounterpartyBusinessDivision : UltimateCounterparty
{
/// <summary>
/// Creates a new <see cref="UltimateCounterpartyBusinessDivision"/>
/// </summary>
/// <param name="id">The identifier of the business division</param>
/// <param name="name">The name of the business division</param>
public UltimateCounterpartyBusinessDivision(string id, string name)
{
Id = id.NotNullOrWhiteSpace(nameof(id));
Name = name.NotNullOrWhiteSpace(nameof(name));
}

/// <inheritdoc />
public override string Type => "business_division";

/// <summary>
/// Gets the identifier of the business division
/// </summary>
[JsonPropertyName("id")]
public string Id { get; }

/// <summary>
/// Gets the name of the business division
/// </summary>
[JsonPropertyName("name")]
public string Name { get; }
}
}
12 changes: 11 additions & 1 deletion src/TrueLayer/Payments/Model/CreatePaymentRequest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using OneOf;
using TrueLayer.Payments.Model.AuthorizationFlow;
using static TrueLayer.Payments.Model.PaymentMethod;
Expand All @@ -24,6 +25,7 @@ public class CreatePaymentRequest
/// If provided, the start authorization flow endpoint does not need to be called</param>
/// <param name="metadata">Add to the payment a list of custom key-value pairs as metadata</param>
/// <param name="riskAssessment">The risk assessment and the payment_creditable webhook configuration.</param>
/// <param name="subMerchants">The details related to any applicable sub-merchants</param>
public CreatePaymentRequest(
long amountInMinor,
string currency,
Expand All @@ -32,7 +34,8 @@ public CreatePaymentRequest(
RelatedProducts? relatedProducts = null,
StartAuthorizationFlowRequest? authorizationFlow = null,
Dictionary<string, string>? metadata = null,
RiskAssessment? riskAssessment = null)
RiskAssessment? riskAssessment = null,
PaymentSubMerchants? subMerchants = null)
{
AmountInMinor = amountInMinor.GreaterThan(0, nameof(amountInMinor));
Currency = currency.NotNullOrWhiteSpace(nameof(currency));
Expand All @@ -42,6 +45,7 @@ public CreatePaymentRequest(
AuthorizationFlow = authorizationFlow;
Metadata = metadata;
RiskAssessment = riskAssessment;
SubMerchants = subMerchants;
}

/// <summary>
Expand Down Expand Up @@ -84,5 +88,11 @@ public CreatePaymentRequest(
/// Gets the risk assessment configuration
/// </summary>
public RiskAssessment? RiskAssessment { get; }

/// <summary>
/// Gets the sub-merchants details
/// </summary>
[JsonPropertyName("sub_merchants")]
public PaymentSubMerchants? SubMerchants { get; }
}
}
7 changes: 7 additions & 0 deletions src/TrueLayer/Payments/Model/GetPaymentResponse.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using OneOf;
using TrueLayer.Serialization;
using static TrueLayer.Payments.Model.PaymentMethod;
Expand Down Expand Up @@ -60,6 +61,12 @@ public abstract record PaymentDetails
/// Gets the metadata added to the payment.
/// </summary>
public Dictionary<string, string>? Metadata { get; init; } = null;

/// <summary>
/// Gets the sub-merchants details
/// </summary>
[JsonPropertyName("sub_merchants")]
public PaymentSubMerchants? SubMerchants { get; init; } = null;
}

/// <summary>
Expand Down
29 changes: 29 additions & 0 deletions src/TrueLayer/Payments/Model/SubMerchants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Text.Json.Serialization;
using OneOf;
using TrueLayer.Common;

namespace TrueLayer.Payments.Model
{
using PaymentUltimateCounterpartyUnion = OneOf<UltimateCounterpartyBusinessClient, UltimateCounterpartyBusinessDivision>;

/// <summary>
/// Represents sub-merchant details for payments
/// </summary>
public record PaymentSubMerchants
{
/// <summary>
/// Creates a new <see cref="PaymentSubMerchants"/>
/// </summary>
/// <param name="ultimateCounterparty">The ultimate counterparty details</param>
public PaymentSubMerchants(PaymentUltimateCounterpartyUnion ultimateCounterparty)
{
UltimateCounterparty = ultimateCounterparty;
}

/// <summary>
/// Gets the ultimate counterparty details
/// </summary>
[JsonPropertyName("ultimate_counterparty")]
public PaymentUltimateCounterpartyUnion UltimateCounterparty { get; }
}
}
12 changes: 11 additions & 1 deletion src/TrueLayer/Payouts/Model/CreatePayoutRequest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using OneOf;
using static TrueLayer.Payouts.Model.Beneficiary;

Expand All @@ -21,20 +22,23 @@ public record CreatePayoutRequest
/// <param name="beneficiary">The payout beneficiary details</param>
/// <param name="metadata">Metadata</param>
/// <param name="schemeSelection">Metadata</param>
/// <param name="subMerchants">The details related to any applicable sub-merchants</param>
public CreatePayoutRequest(
string merchantAccountId,
long amountInMinor,
string currency,
BeneficiaryUnion beneficiary,
Dictionary<string, string>? metadata = null,
SchemeSelectionUnion? schemeSelection = null)
SchemeSelectionUnion? schemeSelection = null,
PayoutSubMerchants? subMerchants = null)
{
MerchantAccountId = merchantAccountId;
AmountInMinor = amountInMinor.GreaterThan(0, nameof(amountInMinor));
Currency = currency.NotNullOrWhiteSpace(nameof(currency));
Beneficiary = beneficiary;
Metadata = metadata;
SchemeSelection = schemeSelection;
SubMerchants = subMerchants;
}

/// <summary>
Expand Down Expand Up @@ -67,5 +71,11 @@ public CreatePayoutRequest(
/// Gets the scheme selection
/// </summary>
public SchemeSelectionUnion? SchemeSelection { get; }

/// <summary>
/// Gets the sub-merchants details
/// </summary>
[JsonPropertyName("sub_merchants")]
public PayoutSubMerchants? SubMerchants { get; }
}
}
7 changes: 7 additions & 0 deletions src/TrueLayer/Payouts/Model/GetPayoutsResponse.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using OneOf;
using TrueLayer.Serialization;
using static TrueLayer.Payouts.Model.Beneficiary;
Expand Down Expand Up @@ -66,6 +67,12 @@ public record PayoutDetails
/// Gets metadata of the payout
/// </summary>
public Dictionary<string, string>? Metadata { get; init; }

/// <summary>
/// Gets the sub-merchants details
/// </summary>
[JsonPropertyName("sub_merchants")]
public PayoutSubMerchants? SubMerchants { get; init; }
}

/// <summary>
Expand Down
26 changes: 26 additions & 0 deletions src/TrueLayer/Payouts/Model/SubMerchants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Text.Json.Serialization;
using TrueLayer.Common;

namespace TrueLayer.Payouts.Model
{
/// <summary>
/// Represents sub-merchant details for payouts
/// </summary>
public record PayoutSubMerchants
{
/// <summary>
/// Creates a new <see cref="PayoutSubMerchants"/>
/// </summary>
/// <param name="ultimateCounterparty">The ultimate counterparty details (optional for payouts)</param>
public PayoutSubMerchants(UltimateCounterpartyBusinessClient? ultimateCounterparty = null)
{
UltimateCounterparty = ultimateCounterparty;
}

/// <summary>
/// Gets the ultimate counterparty details (only business_client is supported for payouts)
/// </summary>
[JsonPropertyName("ultimate_counterparty")]
public UltimateCounterpartyBusinessClient? UltimateCounterparty { get; }
}
}
Loading
Loading