This commit is contained in:
JiriUhlir
2026-06-18 11:05:46 +02:00
parent f44ffae9fc
commit 09db30a3ca
84 changed files with 3952 additions and 15 deletions
+91
View File
@@ -0,0 +1,91 @@
using System.Text.Json.Nodes;
namespace Csob.Models;
// Reusable building blocks shared by the typed PISP request bodies. Field names follow the COBS
// JSON contract (camelCase via System.Text.Json web defaults). Deeply variable sub-trees (party
// identification, structured remittance) are typed as JsonNode so any valid COBS payload passes
// through unchanged.
/// <summary>Monetary amount with ISO 4217 currency.</summary>
public sealed class Amount
{
public decimal Value { get; set; }
public string Currency { get; set; } = "CZK";
}
/// <summary>Wrapper matching the <c>amount</c> object whose <c>instructedAmount</c> holds the value/currency.</summary>
public sealed class AmountContainer
{
public Amount InstructedAmount { get; set; } = new();
}
/// <summary>Account number identification. For domestic/SEPA writes only <c>iban</c> is required.</summary>
public sealed class AccountIdentification
{
public string? Iban { get; set; }
public string? Other { get; set; }
}
/// <summary>Account reference with optional currency (<c>debtorAccount</c>/<c>creditorAccount</c>).</summary>
public sealed class AccountReference
{
public AccountIdentification Identification { get; set; } = new();
public string? Currency { get; set; }
}
public sealed class ServiceLevel
{
/// <summary>Payment scheme: DMCT (domestic), ESCT (SEPA), XBCT (cross-border), EXCT, NXCT.</summary>
public string? Code { get; set; }
}
public sealed class PaymentTypeInformation
{
/// <summary>NORM (default), HIGH (express) or INST (instant).</summary>
public string? InstructionPriority { get; set; }
public ServiceLevel? ServiceLevel { get; set; }
}
public sealed class FinancialInstitutionIdentification
{
public string? Bic { get; set; }
}
public sealed class Agent
{
public FinancialInstitutionIdentification? FinancialInstitutionIdentification { get; set; }
}
public sealed class PostalAddress
{
public string? StreetName { get; set; }
public string? BuildingNumber { get; set; }
public string? PostCode { get; set; }
public string? TownName { get; set; }
public string? Country { get; set; }
}
/// <summary>A party (debtor/creditor/ultimate*). Identification is variable, so kept as raw JSON.</summary>
public sealed class Party
{
public string? Name { get; set; }
public PostalAddress? PostalAddress { get; set; }
public JsonNode? Identification { get; set; }
}
/// <summary>
/// Remittance information. <c>unstructured</c> is free text (Czech symbols may be encoded as
/// <c>/VS/.../SS/.../KS/...</c>); <c>structured</c> varies (its <c>reference</c> may be a string or
/// an array) so it is passed through as raw JSON.
/// </summary>
public sealed class RemittanceInformation
{
public string? Unstructured { get; set; }
public JsonNode? Structured { get; set; }
}
public sealed class Purpose
{
public string? Proprietary { get; set; }
}
+25
View File
@@ -0,0 +1,25 @@
namespace Csob.Models;
/// <summary>Body for <c>POST /oauth/token</c> (Authorization Code grant). Secrets travel in headers.</summary>
public sealed class TokenExchangeRequest
{
/// <summary>Authorization code returned to the redirect URI after PSU consent.</summary>
public string Code { get; set; } = string.Empty;
/// <summary>Redirect URI registered for the TPP app; must match the one used to obtain the code.</summary>
public string RedirectUri { get; set; } = string.Empty;
}
/// <summary>Body for <c>POST /oauth/refresh</c> (Refresh Token grant).</summary>
public sealed class TokenRefreshRequest
{
public string RefreshToken { get; set; } = string.Empty;
}
/// <summary>Response of <c>GET /oauth/authorization-url</c>.</summary>
public sealed class AuthorizationUrlResponse
{
/// <summary>Fully-built ČSOB authorization URL to which the PSU must be redirected.</summary>
public string AuthorizationUrl { get; set; } = string.Empty;
/// <summary>The opaque <c>state</c> value echoed back on the redirect (CSRF protection).</summary>
public string? State { get; set; }
}
+38
View File
@@ -0,0 +1,38 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Csob.Models;
public sealed class PaymentIdentification
{
/// <summary>Unique instruction id assigned by the TPP (idempotency key). Max 35 chars.</summary>
public string? InstructionIdentification { get; set; }
public string? EndToEndIdentification { get; set; }
}
/// <summary>
/// Payment initiation request (<c>POST /my/payments</c>). Covers domestic (DMCT) and SEPA (ESCT)
/// payments — SEPA-only fields (creditor address, agent, ultimate parties, purpose) are optional.
/// Any additional COBS field not modelled here is preserved via <see cref="AdditionalData"/>.
/// </summary>
public sealed class PaymentInitiationRequest
{
public PaymentIdentification? PaymentIdentification { get; set; }
public PaymentTypeInformation? PaymentTypeInformation { get; set; }
public AmountContainer Amount { get; set; } = new();
public string? RequestedExecutionDate { get; set; }
public Party? UltimateDebtor { get; set; }
public AccountReference DebtorAccount { get; set; } = new();
public Agent? CreditorAgent { get; set; }
public Party? Creditor { get; set; }
public AccountReference CreditorAccount { get; set; } = new();
public Party? UltimateCreditor { get; set; }
public RemittanceInformation? RemittanceInformation { get; set; }
public Purpose? Purpose { get; set; }
/// <summary>Any COBS fields not explicitly modelled are forwarded to ČSOB unchanged.</summary>
[JsonExtensionData]
public Dictionary<string, JsonElement>? AdditionalData { get; set; }
}
+48
View File
@@ -0,0 +1,48 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace Csob.Models;
public sealed class StandingOrderIdentification
{
public string? InstructionIdentification { get; set; }
public string? TransactionIdentification { get; set; }
}
public sealed class StandingOrderExecution
{
/// <summary>DAILY, WEEKLY, MONTHLY, BI_MONTHLY, QUARTERLY, HALFYEARLY, YEARLY, SINGLE, IRREGULAR.</summary>
public string? Interval { get; set; }
/// <summary>Day within the interval (e.g. day-of-month "25").</summary>
public string? IntervalDue { get; set; }
/// <summary>e.g. MAX_AMOUNT_EXCEEDED, UNTIL_CANCELLATION.</summary>
public string? Mode { get; set; }
public string? ModeDue { get; set; }
}
public sealed class StandingOrderDetail
{
public string? Alias { get; set; }
public StandingOrderExecution? Execution { get; set; }
/// <summary>Optional <c>exceptions</c> block (stoppages/breaks); shape varies, kept as raw JSON.</summary>
public JsonNode? Exceptions { get; set; }
/// <summary>Optional <c>validity</c> block (lastExecutionDate/maxAmount); kept as raw JSON.</summary>
public JsonNode? Validity { get; set; }
}
/// <summary>Standing-order initiation request (<c>POST /my/standingorders</c>).</summary>
public sealed class StandingOrderInitiationRequest
{
public StandingOrderIdentification? StandingOrderIdentification { get; set; }
public PaymentTypeInformation? PaymentTypeInformation { get; set; }
public AmountContainer Amount { get; set; } = new();
public string? RequestedExecutionDate { get; set; }
public StandingOrderDetail? StandingOrder { get; set; }
public AccountReference DebtorAccount { get; set; } = new();
public AccountReference CreditorAccount { get; set; } = new();
public RemittanceInformation? RemittanceInformation { get; set; }
[JsonExtensionData]
public Dictionary<string, JsonElement>? AdditionalData { get; set; }
}