Compare commits
2 Commits
develop
...
trial-impl
| Author | SHA1 | Date | |
|---|---|---|---|
| 27e2572ded | |||
| 67ab05055c |
Binary file not shown.
@ -215,13 +215,8 @@ public class ABTProductsPUTGenerator {
|
|||||||
}
|
}
|
||||||
case "paymentMoment" -> {
|
case "paymentMoment" -> {
|
||||||
LOGGER.info("Rewriting paymentMoment to paymentMomentId...");
|
LOGGER.info("Rewriting paymentMoment to paymentMomentId...");
|
||||||
if (jsonField.getValue().get("paymentMomentId").isNull()) {
|
Long paymentMomentId = jsonField.getValue().get("paymentMomentId").asLong();
|
||||||
LOGGER.info("Rewriting null paymentMomentId...");
|
((ObjectNode)newJsonNode).put("paymentMomentId", paymentMomentId);
|
||||||
((ObjectNode)newJsonNode).putRawValue("paymentMomentId", null);
|
|
||||||
} else {
|
|
||||||
Long paymentMomentId = jsonField.getValue().get("paymentMomentId").asLong();
|
|
||||||
((ObjectNode)newJsonNode).put("paymentMomentId", paymentMomentId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case "requiredCustomerLevel" -> {
|
case "requiredCustomerLevel" -> {
|
||||||
LOGGER.info("Rewriting requiredCustomerLevel to requiredCustomerLevelId...");
|
LOGGER.info("Rewriting requiredCustomerLevel to requiredCustomerLevelId...");
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,417 +0,0 @@
|
|||||||
openapi: 3.0.3
|
|
||||||
info:
|
|
||||||
title: Integration layer APIs for token storage for ABT
|
|
||||||
description: >-
|
|
||||||
APIs that give business processes access to the security and authorization state of a token within the scope of HTM. In the backend this is connected to a container which handles the accessToken en refreshToken management for an OVpas as given by GBO.
|
|
||||||
version: "1.0"
|
|
||||||
servers:
|
|
||||||
- url: https://services.acc.api.htm.nl/abt/containertokens/1.0
|
|
||||||
security:
|
|
||||||
- oAuthSample: [profile]
|
|
||||||
tags:
|
|
||||||
- name: securitytokens
|
|
||||||
paths:
|
|
||||||
/securitytokens:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- securitytokens
|
|
||||||
summary: Create a new security token entry in the vault
|
|
||||||
description: Create a new security token entry in the vault, if the customerProfileId has been supplied create in the customerToken DB otherwise in the AnonymousToken DB
|
|
||||||
requestBody:
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/CreateSecurityTokenBody"
|
|
||||||
examples:
|
|
||||||
token details:
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"xTat": "cf694905-7f76-4799-b0bc-490716921323",
|
|
||||||
"otpKey": "123456789123456789123456789abcde",
|
|
||||||
"customerProfileId": 12314
|
|
||||||
}
|
|
||||||
responses:
|
|
||||||
"201":
|
|
||||||
description: Created
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Missing Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Missing Mandatory Parameter
|
|
||||||
detail: Required parameter {0} is missing.
|
|
||||||
Invalid Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Invalid Parameter
|
|
||||||
detail: Required parameter {0} is invalid.
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Unauthorized:
|
|
||||||
value:
|
|
||||||
status: 401
|
|
||||||
title: Unauthorized
|
|
||||||
detail: Invalid Access Token
|
|
||||||
"404":
|
|
||||||
description: Not found
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
TAT not found:
|
|
||||||
value:
|
|
||||||
status: 404
|
|
||||||
title: Not Found
|
|
||||||
detail: TAT Account Not Found
|
|
||||||
"409":
|
|
||||||
description: Conflict
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
TAT already exists:
|
|
||||||
value:
|
|
||||||
status: 409
|
|
||||||
title: Conflict
|
|
||||||
detail: Security Token already exists
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Internal Server Error:
|
|
||||||
value:
|
|
||||||
status: 500
|
|
||||||
title: Internal Server Error
|
|
||||||
detail: An unknown error has occurred
|
|
||||||
/securitytokens/{xTat}/status:
|
|
||||||
parameters:
|
|
||||||
- name: xTat
|
|
||||||
in: path
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: 85dbeacc-b9aa-4d5b-bdec-9319010c597f
|
|
||||||
required: true
|
|
||||||
description: The xTat of the OVpastoken for which the status needs to be checked
|
|
||||||
- name: customerProfileId
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 323
|
|
||||||
required: false
|
|
||||||
description: The id of the customer Profile for which the request is being done, if customer has identified themselves
|
|
||||||
get:
|
|
||||||
tags:
|
|
||||||
- securitytokens
|
|
||||||
summary: Request the security and authorization status of an OV pas token
|
|
||||||
description: Request the security and authorization status of an OV pas token, if the customerProfileId has been supplied look in the customerToken DB otherwise check the AnonymousToken DB.
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/SecurityTokenStatusResponse"
|
|
||||||
examples:
|
|
||||||
Not secured and not authorized :
|
|
||||||
summary: Not secured, not authorized
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"isAuthorized": false,
|
|
||||||
"isSecured": false
|
|
||||||
}
|
|
||||||
Secured and not authorized :
|
|
||||||
summary: Secured, not authorized
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"isAuthorized": false,
|
|
||||||
"isSecured": true
|
|
||||||
}
|
|
||||||
Secured and authorized :
|
|
||||||
summary: Secured and authorized
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"isAuthorized": true,
|
|
||||||
"isSecured": true
|
|
||||||
}
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Missing Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Missing Mandatory Parameter
|
|
||||||
detail: Required parameter {0} is missing.
|
|
||||||
Invalid Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Invalid Parameter
|
|
||||||
detail: Required parameter {0} is invalid.
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Unauthorized:
|
|
||||||
value:
|
|
||||||
status: 401
|
|
||||||
title: Unauthorized
|
|
||||||
detail: Invalid Access Token
|
|
||||||
"404":
|
|
||||||
description: Not found
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
TAT not found:
|
|
||||||
value:
|
|
||||||
status: 404
|
|
||||||
title: Not Found
|
|
||||||
detail: TAT Account Not Found
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Internal Server Error:
|
|
||||||
value:
|
|
||||||
status: 500
|
|
||||||
title: Internal Server Error
|
|
||||||
detail: An unknown error has occurred
|
|
||||||
/securitytokens/{xTat}:
|
|
||||||
parameters:
|
|
||||||
- name: xTat
|
|
||||||
in: path
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: uuid
|
|
||||||
required: true
|
|
||||||
description: The xTat of the ovPastoken for which the status needs to be checked
|
|
||||||
- name: customerProfileId
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 323
|
|
||||||
required: false
|
|
||||||
description: The id of the customer Profile for which the request is being done, if customer has identified themselves
|
|
||||||
patch:
|
|
||||||
tags:
|
|
||||||
- securitytokens
|
|
||||||
summary: Validate the supplied OTP and secure and/or authorize the token
|
|
||||||
description: Validate the supplied OTP and secure and/or authorize the token if the customerProfileId has been supplied look in the customerToken DB otherwise check the AnonymousToken DB.
|
|
||||||
requestBody:
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/SecurityValidateTokenBody"
|
|
||||||
examples:
|
|
||||||
token:
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"otp": "123456"
|
|
||||||
}
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/SecurityTokenStatusResponse"
|
|
||||||
examples:
|
|
||||||
Not secured and not authorized :
|
|
||||||
summary: Not secured, not authorized
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"isAuthorized": false,
|
|
||||||
"isSecured": false
|
|
||||||
}
|
|
||||||
Secured and not authorized :
|
|
||||||
summary: Secured, not authorized
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"isAuthorized": false,
|
|
||||||
"isSecured": true
|
|
||||||
}
|
|
||||||
Secured and authorized :
|
|
||||||
summary: Secured and authorized
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"isAuthorized": true,
|
|
||||||
"isSecured": true
|
|
||||||
}
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Missing Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Missing Mandatory Parameter
|
|
||||||
detail: Required parameter {0} is missing.
|
|
||||||
Invalid Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Invalid Parameter
|
|
||||||
detail: Required parameter {0} is invalid.
|
|
||||||
"422":
|
|
||||||
description: Unprocessable Entity
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Validation failed:
|
|
||||||
value:
|
|
||||||
status: 422
|
|
||||||
title: OTP validation failed
|
|
||||||
detail: The supplied OTP could not be validated
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Unauthorized:
|
|
||||||
value:
|
|
||||||
status: 401
|
|
||||||
title: Unauthorized
|
|
||||||
detail: Invalid Access Token
|
|
||||||
"404":
|
|
||||||
description: Not found
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
TAT not found:
|
|
||||||
value:
|
|
||||||
status: 404
|
|
||||||
title: Not Found
|
|
||||||
detail: TAT Account Not Found
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Internal Server Error:
|
|
||||||
value:
|
|
||||||
status: 500
|
|
||||||
title: Internal Server Error
|
|
||||||
detail: An unknown error has occurred
|
|
||||||
delete:
|
|
||||||
tags:
|
|
||||||
- securitytokens
|
|
||||||
summary: Delete the authorization for HTM for an ovpaytoken
|
|
||||||
description: Delete the authorization for HTM for an ovpaytoken if the customerProfileId has been supplied look in the customerToken DB otherwise check the AnonymousToken DB.
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/SecurityTokenStatusResponse"
|
|
||||||
example:
|
|
||||||
{}
|
|
||||||
components:
|
|
||||||
securitySchemes:
|
|
||||||
oAuthSample:
|
|
||||||
type: oauth2
|
|
||||||
description: This API uses OAuth 2 with the clientCredentials flow. [More info](https://api.example.com/docs/auth)
|
|
||||||
flows:
|
|
||||||
clientCredentials: # <---- OAuth flow( clientCredentials)
|
|
||||||
tokenUrl: https://identity.{env}.api.htm.nl/oauth2/token
|
|
||||||
scopes:
|
|
||||||
profile: "Access user profile"
|
|
||||||
schemas:
|
|
||||||
ErrorResponse:
|
|
||||||
description: Default response when an invalid request has been sent
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
status:
|
|
||||||
type: integer
|
|
||||||
description: >-
|
|
||||||
A status IS An integer that represents the HTTP status code of the
|
|
||||||
response.
|
|
||||||
example: 400
|
|
||||||
title:
|
|
||||||
type: string
|
|
||||||
description: A title IS A string that provides a brief summary of the error.
|
|
||||||
detail:
|
|
||||||
type: string
|
|
||||||
description: A detail IS A string that provides more details about the error.
|
|
||||||
CreateSecurityTokenBody:
|
|
||||||
description: Body for when the a new security token entry is created
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- xTat
|
|
||||||
- otpKey
|
|
||||||
properties:
|
|
||||||
xTat:
|
|
||||||
type : string
|
|
||||||
description: >-
|
|
||||||
Unique identifier for the GBO transit account
|
|
||||||
example: 03071794-482a-4168-b60f-84669a9e6a76
|
|
||||||
otpKey:
|
|
||||||
type : string
|
|
||||||
description: >-
|
|
||||||
Key used to validate the OTP at GBO
|
|
||||||
example: 123456789123456789123456789abcde
|
|
||||||
customerProfileId:
|
|
||||||
type : integer
|
|
||||||
description: >-
|
|
||||||
CustomerProfileId of the account requesting security or giving authorization
|
|
||||||
example: 123456
|
|
||||||
SecurityTokenStatusResponse:
|
|
||||||
description: Response for when the status of a token is requested
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
isSecured:
|
|
||||||
type: boolean
|
|
||||||
description: >-
|
|
||||||
Is the OVpas secured according to the GBO
|
|
||||||
example: false
|
|
||||||
isAuthorized:
|
|
||||||
type: boolean
|
|
||||||
description: >-
|
|
||||||
Does HTM have the authorization to access the secured the data of the OVpas
|
|
||||||
example: false
|
|
||||||
SecurityValidateTokenBody:
|
|
||||||
description: Body for when the a token entry is validated
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- otp
|
|
||||||
properties:
|
|
||||||
otp:
|
|
||||||
type : string
|
|
||||||
description: >-
|
|
||||||
OTP to be used to secure the token and retrieve the JWT at GBO
|
|
||||||
example: 123456
|
|
||||||
@ -45,36 +45,12 @@ paths:
|
|||||||
"contractStatus":
|
"contractStatus":
|
||||||
{ "contractStatusId": 2, "name": "active" },
|
{ "contractStatusId": 2, "name": "active" },
|
||||||
"productId": 1,
|
"productId": 1,
|
||||||
"productName": "HTM Maand 20% korting doorlopend",
|
"productName": "HTM Maand 20% korting",
|
||||||
"termDuration": "P1M",
|
"termDuration": "P0Y1M0D",
|
||||||
"billingDay": 15,
|
"billingDay": 15,
|
||||||
"highestInvoiceTerm": 1,
|
"highestInvoiceTerm": 1,
|
||||||
"created": "2024-08-01T15:01:00.000Z",
|
"created": "2024-08-01 15:01:00.000",
|
||||||
"ovPayTokenId": 1337,
|
"ovPayTokenId": 1337,
|
||||||
"contractVersions": [
|
|
||||||
{
|
|
||||||
"contractVersionId": 1,
|
|
||||||
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
|
||||||
"productId": 1,
|
|
||||||
"productName": "HTM Maand 20% korting doorlopend",
|
|
||||||
"taxCode": "V9",
|
|
||||||
"taxPercentage": 9,
|
|
||||||
"termAmountInclTax": 400,
|
|
||||||
"start": "2024-08-01T15:01:00.000Z",
|
|
||||||
"end": "2025-01-01T03:00:00.000Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contractVersionId": 2,
|
|
||||||
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
|
||||||
"productId": 1,
|
|
||||||
"productName": "HTM Maand 20% korting doorlopend",
|
|
||||||
"taxCode": "V9",
|
|
||||||
"taxPercentage": 9,
|
|
||||||
"termAmountInclTax": 500,
|
|
||||||
"start": "2025-01-01T03:00:00.000Z",
|
|
||||||
"end": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"get_token":
|
"get_token":
|
||||||
@ -92,38 +68,14 @@ paths:
|
|||||||
"orderLineId": "42f68042-908f-41f4-9d9b-4cab843ff0e8",
|
"orderLineId": "42f68042-908f-41f4-9d9b-4cab843ff0e8",
|
||||||
"touchpointId": 2,
|
"touchpointId": 2,
|
||||||
"contractStatus":
|
"contractStatus":
|
||||||
{ "contractStatusId": 6, "name": "pending cancellation" },
|
{ "contractStatusId": 1, "name": "new" },
|
||||||
"productId": 1,
|
"productId": 1,
|
||||||
"productName": "HTM 20% Korting doorlopend",
|
"productName": "HTM Maand 20% korting",
|
||||||
"termDuration": "P1M",
|
"termDuration": "P0Y1M0D",
|
||||||
"billingDay": 15,
|
"billingDay": 15,
|
||||||
"highestInvoiceTerm": 1,
|
"highestInvoiceTerm": 1,
|
||||||
"created": "2024-08-01T15:01:00.000Z",
|
"created": "2024-08-01 15:01:00.000",
|
||||||
"ovPayTokenId": 1338,
|
"ovPayTokenId": 1338,
|
||||||
"contractVersions": [
|
|
||||||
{
|
|
||||||
"contractVersionId": 1,
|
|
||||||
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
|
||||||
"productId": 1,
|
|
||||||
"productName": "HTM 20% Korting doorlopend",
|
|
||||||
"taxCode": "V9",
|
|
||||||
"taxPercentage": 9,
|
|
||||||
"termAmountInclTax": 400,
|
|
||||||
"start": "2024-08-01T15:01:00.000Z",
|
|
||||||
"end": "2025-01-01T03:00:00.000Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contractVersionId": 2,
|
|
||||||
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
|
||||||
"productId": 1,
|
|
||||||
"productName": "HTM 20% Korting doorlopend",
|
|
||||||
"taxCode": "V9",
|
|
||||||
"taxPercentage": 9,
|
|
||||||
"termAmountInclTax": 500,
|
|
||||||
"start": "2025-01-01T03:00:00.000Z",
|
|
||||||
"end": "2025-02-01T03:00:00.000Z"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"get_token":
|
"get_token":
|
||||||
@ -202,8 +154,8 @@ paths:
|
|||||||
"contractStatus":
|
"contractStatus":
|
||||||
{ "contractStatusId": 2, "name": "active" },
|
{ "contractStatusId": 2, "name": "active" },
|
||||||
"productId": 1,
|
"productId": 1,
|
||||||
"productName": "HTM 20% Korting doorlopend",
|
"productName": "HTM Maand 20% korting",
|
||||||
"termDuration": "P1M",
|
"termDuration": "P0Y1M0D",
|
||||||
"billingDay": 15,
|
"billingDay": 15,
|
||||||
"highestInvoiceTerm": 1,
|
"highestInvoiceTerm": 1,
|
||||||
"ovPayTokenId": 1337,
|
"ovPayTokenId": 1337,
|
||||||
@ -213,22 +165,22 @@ paths:
|
|||||||
"contractVersionId": 1,
|
"contractVersionId": 1,
|
||||||
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
||||||
"productId": 1,
|
"productId": 1,
|
||||||
"productName": "HTM 20% Korting doorlopend",
|
"productName": "HTM Maand 20% korting",
|
||||||
"taxCode": "V9",
|
"taxCode": "V9",
|
||||||
"taxPercentage": 9.0,
|
"taxPercentage": 9.0,
|
||||||
"termAmountInclTax": 400,
|
"termAmountInclTax": 400,
|
||||||
"start": "2024-08-01T15:01:00.000Z",
|
"start": "2024-07-04 15:01:00.000",
|
||||||
"end": "2025-01-01T03:00:00.000Z",
|
"end": "2024-12-31 15:01:00.000",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contractVersionId": 2,
|
"contractVersionId": 2,
|
||||||
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
|
||||||
"productId": 1,
|
"productId": 1,
|
||||||
"productName": "HTM 20% Korting doorlopend",
|
"productName": "HTM Maand 20% korting",
|
||||||
"taxCode": "V9",
|
"taxCode": "V9",
|
||||||
"taxPercentage": 9.0,
|
"taxPercentage": 9.0,
|
||||||
"termAmountInclTax": 400,
|
"termAmountInclTax": 400,
|
||||||
"start": "2025-01-01T03:00:00.000Z",
|
"start": "2025-01-01 15:01:00.000",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"contractActions":
|
"contractActions":
|
||||||
@ -238,7 +190,7 @@ paths:
|
|||||||
"actionType":
|
"actionType":
|
||||||
{ "actionTypeId": 1, "name": "create" },
|
{ "actionTypeId": 1, "name": "create" },
|
||||||
"user": "subid123456",
|
"user": "subid123456",
|
||||||
"timestamp": "2024-07-02T15:01:00.000Z",
|
"timestamp": "2024-07-02 15:01:00.000",
|
||||||
"details": "Contract created",
|
"details": "Contract created",
|
||||||
"correlationId": "976e7a4c-bf24-43d2-b444-55817556e7ee",
|
"correlationId": "976e7a4c-bf24-43d2-b444-55817556e7ee",
|
||||||
},
|
},
|
||||||
@ -247,7 +199,7 @@ paths:
|
|||||||
"actionType":
|
"actionType":
|
||||||
{ "actionTypeId": 2, "name": "change" },
|
{ "actionTypeId": 2, "name": "change" },
|
||||||
"user": "subid123456",
|
"user": "subid123456",
|
||||||
"timestamp": "2024-07-03T15:01:00.000Z",
|
"timestamp": "2024-07-03 15:01:00.000",
|
||||||
"details": "Contract changed",
|
"details": "Contract changed",
|
||||||
"correlationId": "e2462347-6749-4841-b42a-cf8de19ec727",
|
"correlationId": "e2462347-6749-4841-b42a-cf8de19ec727",
|
||||||
},
|
},
|
||||||
@ -259,8 +211,8 @@ paths:
|
|||||||
"externalReference": "F2024-0001",
|
"externalReference": "F2024-0001",
|
||||||
"term": 1,
|
"term": 1,
|
||||||
"invoiceDate": "2024-07-02",
|
"invoiceDate": "2024-07-02",
|
||||||
"created": "2024-07-02T15:01:00.000Z",
|
"created": "2024-07-02 15:01:00.000",
|
||||||
"updated": "2024-07-02T15:01:00.000Z",
|
"updated": "2024-07-02 15:01:00.000",
|
||||||
"state": "invoice_created",
|
"state": "invoice_created",
|
||||||
"data": "{json}",
|
"data": "{json}",
|
||||||
"isCredit": false,
|
"isCredit": false,
|
||||||
@ -318,8 +270,8 @@ paths:
|
|||||||
"externalReference": "F2024-0001",
|
"externalReference": "F2024-0001",
|
||||||
"term": 1,
|
"term": 1,
|
||||||
"invoiceDate": "2024-07-02",
|
"invoiceDate": "2024-07-02",
|
||||||
"created": "2024-07-02T15:01:34.000Z",
|
"created": "2024-07-02 15:01:34.000",
|
||||||
"updated": "2024-07-04T00:04:56.000Z",
|
"updated": "2024-07-04 00:04:56.000",
|
||||||
"state": "invoice_created",
|
"state": "invoice_created",
|
||||||
"public_link": "http://mijnfactuurinzien.nl/F2024-0001",
|
"public_link": "http://mijnfactuurinzien.nl/F2024-0001",
|
||||||
"isCredit": false,
|
"isCredit": false,
|
||||||
@ -330,8 +282,8 @@ paths:
|
|||||||
"externalReference": "F2024-0002",
|
"externalReference": "F2024-0002",
|
||||||
"term": 2,
|
"term": 2,
|
||||||
"invoiceDate": "2024-08-02",
|
"invoiceDate": "2024-08-02",
|
||||||
"created": "2024-08-02T15:01:34.000Z",
|
"created": "2024-08-02 15:01:34.000",
|
||||||
"updated": "2024-08-04T00:04:56.000Z",
|
"updated": "2024-08-04 00:04:56.000",
|
||||||
"state": "invoice_created",
|
"state": "invoice_created",
|
||||||
"public_link": "http://mijnfactuurinzien.nl/F2024-0002",
|
"public_link": "http://mijnfactuurinzien.nl/F2024-0002",
|
||||||
"isCredit": false,
|
"isCredit": false,
|
||||||
@ -376,8 +328,8 @@ paths:
|
|||||||
"cancellationMoment": "termBound",
|
"cancellationMoment": "termBound",
|
||||||
"termDuration": "P1M",
|
"termDuration": "P1M",
|
||||||
"billingDay": 18,
|
"billingDay": 18,
|
||||||
"cancellationFrom": "2024-08-10T00:00:00Z",
|
"cancellationFrom": "2024-08-10T00:00:00",
|
||||||
"cancellationUntil": "2026-08-10T00:00:00Z",
|
"cancellationUntil": "2026-08-10T00:00:00",
|
||||||
}
|
}
|
||||||
/contracts/{contractId}/cancellationvalidation:
|
/contracts/{contractId}/cancellationvalidation:
|
||||||
parameters:
|
parameters:
|
||||||
@ -430,7 +382,7 @@ paths:
|
|||||||
{
|
{
|
||||||
"validationResult": true,
|
"validationResult": true,
|
||||||
"validationMessage": "",
|
"validationMessage": "",
|
||||||
"end": "2024-08-10T03:59:59Z",
|
"end": "2024-08-10T03:59:59",
|
||||||
"refundAmount": 2489,
|
"refundAmount": 2489,
|
||||||
"refundMethods": ["creditInvoice", "iDeal"],
|
"refundMethods": ["creditInvoice", "iDeal"],
|
||||||
}
|
}
|
||||||
@ -499,7 +451,7 @@ paths:
|
|||||||
the refund amount and refund method.
|
the refund amount and refund method.
|
||||||
value:
|
value:
|
||||||
{
|
{
|
||||||
"end": "2024-08-10T03:59:59Z",
|
"end": "2024-08-10T03:59:59",
|
||||||
"refundAmount": 2489,
|
"refundAmount": 2489,
|
||||||
"refundMethod": "creditInvoice",
|
"refundMethod": "creditInvoice",
|
||||||
}
|
}
|
||||||
@ -564,8 +516,8 @@ paths:
|
|||||||
"taxCode": "V9",
|
"taxCode": "V9",
|
||||||
"taxPercentage": 9.0,
|
"taxPercentage": 9.0,
|
||||||
"termAmountInclTax": 400,
|
"termAmountInclTax": 400,
|
||||||
"start": "2024-07-04T15:01:00.000Z",
|
"start": "2024-07-04 15:01:00.000",
|
||||||
"end": "2024-12-31T15:01:00.000Z",
|
"end": "2024-12-31 15:01:00.000",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"contractVersionId": 2,
|
"contractVersionId": 2,
|
||||||
@ -575,8 +527,7 @@ paths:
|
|||||||
"taxCode": "V9",
|
"taxCode": "V9",
|
||||||
"taxPercentage": 9.0,
|
"taxPercentage": 9.0,
|
||||||
"termAmountInclTax": 400,
|
"termAmountInclTax": 400,
|
||||||
"start": "2025-01-01T15:01:00.000Z",
|
"start": "2025-01-01 15:01:00.000",
|
||||||
"end": null
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"contractActions":
|
"contractActions":
|
||||||
@ -586,7 +537,7 @@ paths:
|
|||||||
"actionType":
|
"actionType":
|
||||||
{ "actionTypeId": 1, "name": "create" },
|
{ "actionTypeId": 1, "name": "create" },
|
||||||
"user": "subid123456",
|
"user": "subid123456",
|
||||||
"timestamp": "2024-07-02T15:01:00.000Z",
|
"timestamp": "2024-07-02 15:01:00.000",
|
||||||
"details": "Contract created",
|
"details": "Contract created",
|
||||||
"correlationId": "976e7a4c-bf24-43d2-b444-55817556e7ee",
|
"correlationId": "976e7a4c-bf24-43d2-b444-55817556e7ee",
|
||||||
},
|
},
|
||||||
@ -595,7 +546,7 @@ paths:
|
|||||||
"actionType":
|
"actionType":
|
||||||
{ "actionTypeId": 2, "name": "change" },
|
{ "actionTypeId": 2, "name": "change" },
|
||||||
"user": "subid123456",
|
"user": "subid123456",
|
||||||
"timestamp": "2024-07-03T15:01:00.000Z",
|
"timestamp": "2024-07-03 15:01:00.000",
|
||||||
"details": "Contract changed",
|
"details": "Contract changed",
|
||||||
"correlationId": "e2462347-6749-4841-b42a-cf8de19ec727",
|
"correlationId": "e2462347-6749-4841-b42a-cf8de19ec727",
|
||||||
},
|
},
|
||||||
@ -607,8 +558,8 @@ paths:
|
|||||||
"externalReference": "F2024-0001",
|
"externalReference": "F2024-0001",
|
||||||
"term": 1,
|
"term": 1,
|
||||||
"invoiceDate": "2024-07-02",
|
"invoiceDate": "2024-07-02",
|
||||||
"created": "2024-07-02T15:01:00.000Z",
|
"created": "2024-07-02 15:01:00.000",
|
||||||
"updated": "2024-07-02T15:01:00.000Z",
|
"updated": "2024-07-02 15:01:00.000",
|
||||||
"state": "invoice_created",
|
"state": "invoice_created",
|
||||||
"data": "{json}",
|
"data": "{json}",
|
||||||
"isCredit": false,
|
"isCredit": false,
|
||||||
@ -731,7 +682,7 @@ paths:
|
|||||||
"termDuration": "P0Y1M0D",
|
"termDuration": "P0Y1M0D",
|
||||||
"billingDay": 15,
|
"billingDay": 15,
|
||||||
"highestInvoiceTerm": 1,
|
"highestInvoiceTerm": 1,
|
||||||
"created": "2024-08-01T15:01:00.000Z",
|
"created": "2024-08-01 15:01:00.000",
|
||||||
"ovPayTokenId": 1337,
|
"ovPayTokenId": 1337,
|
||||||
"contractVersions":
|
"contractVersions":
|
||||||
[
|
[
|
||||||
@ -830,7 +781,7 @@ paths:
|
|||||||
"termDuration": "P0Y1M0D",
|
"termDuration": "P0Y1M0D",
|
||||||
"billingDay": 15,
|
"billingDay": 15,
|
||||||
"highestInvoiceTerm": 1,
|
"highestInvoiceTerm": 1,
|
||||||
"created": "2024-08-01T15:01:00.000Z",
|
"created": "2024-08-01 15:01:00.000",
|
||||||
"ovPayTokenId": 1337,
|
"ovPayTokenId": 1337,
|
||||||
"contractVersions":
|
"contractVersions":
|
||||||
[
|
[
|
||||||
|
|||||||
@ -1081,10 +1081,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -1134,9 +1130,9 @@ paths:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
OV pas without PAD, without AGO:
|
OV pas without PAD:
|
||||||
summary: OV pas without PAD, without AGO
|
summary: OV pas without PAD
|
||||||
description: OV pas without PAD, without AGO
|
description: OV pas without PAD
|
||||||
value:
|
value:
|
||||||
{
|
{
|
||||||
"ovPayTokens":
|
"ovPayTokens":
|
||||||
@ -1168,10 +1164,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": false,
|
|
||||||
"isAuthorized": false,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -1209,10 +1201,6 @@ paths:
|
|||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens/51compare",
|
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens/51compare",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
},
|
},
|
||||||
"secure": {
|
|
||||||
"href": "/tokens/securetoken",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1225,9 +1213,9 @@ paths:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
OV pas with PAD, with autoReload, with AGO:
|
OV pas with PAD and autoReload:
|
||||||
summary: OV pas with PAD, with autoReload, with AGO
|
summary: OV pas with PAD and autoReload
|
||||||
description: OV pas with PAD, with autoReload, with AGO
|
description: OV pas with PAD and autoReload
|
||||||
value:
|
value:
|
||||||
{
|
{
|
||||||
"ovPayTokens":
|
"ovPayTokens":
|
||||||
@ -1299,10 +1287,6 @@ paths:
|
|||||||
"ageFromInclusive": 4,
|
"ageFromInclusive": 4,
|
||||||
"ageToInclusive": 11,
|
"ageToInclusive": 11,
|
||||||
},
|
},
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -1401,10 +1385,6 @@ paths:
|
|||||||
"ageFromInclusive": 4,
|
"ageFromInclusive": 4,
|
||||||
"ageToInclusive": 11,
|
"ageToInclusive": 11,
|
||||||
},
|
},
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -1521,10 +1501,6 @@ paths:
|
|||||||
"ageFromInclusive": 4,
|
"ageFromInclusive": 4,
|
||||||
"ageToInclusive": 11,
|
"ageToInclusive": 11,
|
||||||
},
|
},
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -1601,22 +1577,6 @@ paths:
|
|||||||
"birthdate": null,
|
"birthdate": null,
|
||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": false,
|
|
||||||
},
|
|
||||||
"_links":{
|
|
||||||
"self":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPaytokenId=1",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
"authorize":
|
|
||||||
{
|
|
||||||
"href": "/tokens/authorizetoken",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"customerProfileId": 1,
|
"customerProfileId": 1,
|
||||||
@ -1639,17 +1599,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":{
|
|
||||||
"self":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPaytokenId=1",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"customerProfileId": 18,
|
"customerProfileId": 18,
|
||||||
@ -1672,17 +1621,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":{
|
|
||||||
"self":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPaytokenId=1",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"customerProfileId": 132,
|
"customerProfileId": 132,
|
||||||
@ -1705,17 +1643,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":{
|
|
||||||
"self":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPaytokenId=1",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"customerProfileId": 166,
|
"customerProfileId": 166,
|
||||||
@ -1741,22 +1668,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": false,
|
|
||||||
"isAuthorized": false,
|
|
||||||
},
|
|
||||||
"_links":{
|
|
||||||
"self":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPaytokenId=1",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
"secure":
|
|
||||||
{
|
|
||||||
"href": "/tokens/securetoken",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"customerProfileId": 166,
|
"customerProfileId": 166,
|
||||||
@ -1779,17 +1690,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":{
|
|
||||||
"self":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPaytokenId=1",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"customerProfileId": 1,
|
"customerProfileId": 1,
|
||||||
@ -1812,17 +1712,6 @@ paths:
|
|||||||
"photo": null,
|
"photo": null,
|
||||||
},
|
},
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":{
|
|
||||||
"self":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPaytokenId=1",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
_links:
|
_links:
|
||||||
@ -1923,10 +1812,6 @@ paths:
|
|||||||
"personalAccountData":
|
"personalAccountData":
|
||||||
{ "name": null, "birthdate": null, "photo": null },
|
{ "name": null, "birthdate": null, "photo": null },
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -2005,10 +1890,6 @@ paths:
|
|||||||
"personalAccountData":
|
"personalAccountData":
|
||||||
{ "name": null, "birthdate": null, "photo": null },
|
{ "name": null, "birthdate": null, "photo": null },
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": false,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -2046,12 +1927,6 @@ paths:
|
|||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens/1/compare",
|
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens/1/compare",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
},
|
},
|
||||||
"authorize":{
|
|
||||||
{
|
|
||||||
"href": "/tokens/authorizetoken",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"_links":
|
"_links":
|
||||||
@ -2211,10 +2086,6 @@ paths:
|
|||||||
"personalAccountData":
|
"personalAccountData":
|
||||||
{ "name": null, "birthdate": null, "photo": null },
|
{ "name": null, "birthdate": null, "photo": null },
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -2278,10 +2149,6 @@ paths:
|
|||||||
"personalAccountData":
|
"personalAccountData":
|
||||||
{ "name": null, "birthdate": null, "photo": null },
|
{ "name": null, "birthdate": null, "photo": null },
|
||||||
"gboAgeProfile": null,
|
"gboAgeProfile": null,
|
||||||
"tatSecurity": {
|
|
||||||
"isSecured": true,
|
|
||||||
"isAuthorized": true,
|
|
||||||
},
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"self":
|
"self":
|
||||||
@ -3769,6 +3636,7 @@ paths:
|
|||||||
"vouchers": []
|
"vouchers": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/customers/devices:
|
/customers/devices:
|
||||||
post:
|
post:
|
||||||
summary: Add a new device to a customer profile.
|
summary: Add a new device to a customer profile.
|
||||||
@ -4735,3 +4603,4 @@ components:
|
|||||||
customerDataItem:
|
customerDataItem:
|
||||||
type: string
|
type: string
|
||||||
example: emailAddress
|
example: emailAddress
|
||||||
|
|
||||||
@ -1,617 +0,0 @@
|
|||||||
openapi: 3.0.1
|
|
||||||
info:
|
|
||||||
title: Service Engine APIs for TAT security
|
|
||||||
description: >-
|
|
||||||
Service Engine APIs for TAT security. These are NOT the raw GBO APIs to access TAT security at GBO directly.
|
|
||||||
To be used by touch points to get secure a TAT.
|
|
||||||
version: "2.0"
|
|
||||||
servers:
|
|
||||||
- url: https://services.acc.api.htm.nl/abt/touchpoint/2.0
|
|
||||||
tags:
|
|
||||||
- name: TAT Security
|
|
||||||
paths:
|
|
||||||
/tokens/status:
|
|
||||||
parameters:
|
|
||||||
- name: X-HTM-JWT-AUTH-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
|
||||||
required: false
|
|
||||||
description: The JWT of a customer in case of touchpoint were customer logs in themselves
|
|
||||||
- name: X-HTM-CUSTOMER-PROFILE-ID-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 323
|
|
||||||
required: false
|
|
||||||
description: The id of the customer Profile
|
|
||||||
- name: X-HTM-ROLE-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: Customer
|
|
||||||
required: false
|
|
||||||
description: The role of the HTM employee in the case of the SMP
|
|
||||||
- name: xTat
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format : uuid
|
|
||||||
example: 5c4cba83-1ecd-46a4-b712-a8de0dcb7bbf
|
|
||||||
required: false
|
|
||||||
description: The xtat of the customerToken
|
|
||||||
- name: ovPayTokenId
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 1
|
|
||||||
required: false
|
|
||||||
description: The ovpay token id of a specific customer token
|
|
||||||
- name: serviceReferenceId
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: NLOV1234567ABCDEFG
|
|
||||||
required: false
|
|
||||||
description: The serviceReferencId found on the bankstatement for a given trip with a bankcard, required for an unknown EMV card
|
|
||||||
- name: amount
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 0
|
|
||||||
required: false
|
|
||||||
description: The amount of the value of the bankstatement in cents, required for an unknown EMV card
|
|
||||||
- name: ovpasNumber
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: OV34567
|
|
||||||
required: false
|
|
||||||
description: The number of the ovpas, required for an unknown Ovpas card
|
|
||||||
- name: verificationCode
|
|
||||||
in: query
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: HL78
|
|
||||||
required: false
|
|
||||||
description: The 4 digit verificationCode found on the backside of the Ovpas, required for an unknown Ovpas card
|
|
||||||
get:
|
|
||||||
tags:
|
|
||||||
- TAT Security
|
|
||||||
summary: Check the status of the security and authorization status of the given token
|
|
||||||
description: Check the status of the security and authorization status of the given token, check anonymous tokenDB if no customer headers are supplied otherwise check customer tokenDB
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/TokenStatusResponse"
|
|
||||||
examples:
|
|
||||||
isSecuredandnotAuthorized:
|
|
||||||
summary: Token is secured but HTM is not authorized
|
|
||||||
description: Token is secured but HTM is not authorized
|
|
||||||
value:
|
|
||||||
isSecured: true
|
|
||||||
isAuthorized: false
|
|
||||||
xTat: 12da8f2a-6390-408a-94eb-a6701b5daf27
|
|
||||||
_links: {
|
|
||||||
"authorize": {
|
|
||||||
"href": "/tokens/authorizetoken",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notSecuredandnotAuthorized:
|
|
||||||
summary: Token is not secured but HTM is not authorized
|
|
||||||
description: Token is not secured but HTM is not authorized
|
|
||||||
value:
|
|
||||||
isSecured: false
|
|
||||||
isAuthorized: false
|
|
||||||
xTat: 12da8f2a-6390-408a-94eb-a6701b5daf27
|
|
||||||
_links: {
|
|
||||||
"secure": {
|
|
||||||
"href": "/tokens/securetoken",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Missing Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Missing Mandatory Parameter
|
|
||||||
detail: Required parameter {0} is missing.
|
|
||||||
Invalid Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Invalid Parameter
|
|
||||||
detail: Required parameter {0} is invalid.
|
|
||||||
"404":
|
|
||||||
description: Not found
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
TAT not found:
|
|
||||||
value:
|
|
||||||
status: 404
|
|
||||||
title: Not Found
|
|
||||||
detail: XTAT Account Not Found
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
example:
|
|
||||||
error: An unknown error has occurred
|
|
||||||
/tokens/securetoken:
|
|
||||||
parameters:
|
|
||||||
- name: X-HTM-JWT-AUTH-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
|
||||||
required: false
|
|
||||||
description: The JWT of a customer in case of touchpoint were customer logs in themselves
|
|
||||||
- name: X-HTM-CUSTOMER-PROFILE-ID-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 323
|
|
||||||
required: false
|
|
||||||
description: The id of the customer Profile
|
|
||||||
- name: X-HTM-ROLE-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: Customer
|
|
||||||
required: false
|
|
||||||
description: The role of the HTM employee in the case of the SMP
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- TAT Security
|
|
||||||
summary: Request additional OV-pas security for a token either in profile or anonymous.
|
|
||||||
description: Request additional OV-pas security for a token either in profile or anonymous
|
|
||||||
requestBody:
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/SecureTokenRequest"
|
|
||||||
examples:
|
|
||||||
With customer account:
|
|
||||||
value:
|
|
||||||
ovPayTokenId: 42
|
|
||||||
emailAddress: stasjo@htm.nl
|
|
||||||
Without customer account:
|
|
||||||
value:
|
|
||||||
xTat: 62914b49-2c7f-437f-b4b0-2ad61a9f902d
|
|
||||||
emailAddress: stasjo@htm.nl
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/EmailNotPreApprovedResponse"
|
|
||||||
example:
|
|
||||||
recipient: xxxxxx.user@gmail.com
|
|
||||||
description: OTP Sent
|
|
||||||
_links: {
|
|
||||||
"verifyotp": {
|
|
||||||
"href": "/tokens/verifyotp",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Missing Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Missing Mandatory Parameter
|
|
||||||
detail: Required parameter {0} is missing.
|
|
||||||
Invalid Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Invalid Parameter
|
|
||||||
detail: Required parameter {0} is invalid.
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Unauthorized:
|
|
||||||
value:
|
|
||||||
status: 401
|
|
||||||
title: Unauthorized
|
|
||||||
detail: Invalid Access Token
|
|
||||||
"404":
|
|
||||||
description: Not found
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
TAT not found:
|
|
||||||
value:
|
|
||||||
status: 404
|
|
||||||
title: Not Found
|
|
||||||
detail: TAT Account Not Found
|
|
||||||
"409":
|
|
||||||
description: Conflict
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/ErrorResponse'
|
|
||||||
examples:
|
|
||||||
TAT Already Secured:
|
|
||||||
value:
|
|
||||||
status: 409
|
|
||||||
title: Conflict
|
|
||||||
detail: TAT Already Secured
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
example:
|
|
||||||
error: An unknown error has occurred
|
|
||||||
/tokens/authorizetoken:
|
|
||||||
parameters:
|
|
||||||
- name: X-HTM-JWT-AUTH-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
|
||||||
required: false
|
|
||||||
description: The JWT of a customer in case of touchpoint were customer logs in themselves
|
|
||||||
- name: X-HTM-CUSTOMER-PROFILE-ID-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 323
|
|
||||||
required: false
|
|
||||||
description: The id of the customer Profile
|
|
||||||
- name: X-HTM-ROLE-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: Customer
|
|
||||||
required: false
|
|
||||||
description: The role of the HTM employee in the case of the SMP
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- TAT Authorization
|
|
||||||
summary: Request authorization for HTM to access the data secured by additional OV-pas security for a token either in profile or anonymous.
|
|
||||||
description: Request authorization for HTM to access the data secured by additional OV-pas security for a token either in profile or anonymous.
|
|
||||||
requestBody:
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/AuthorizeTokenRequest"
|
|
||||||
examples:
|
|
||||||
With customer account:
|
|
||||||
value:
|
|
||||||
ovPayTokenId: 42
|
|
||||||
Without customer account:
|
|
||||||
value:
|
|
||||||
xTat: 62914b49-2c7f-437f-b4b0-2ad61a9f902d
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/EmailNotPreApprovedResponse"
|
|
||||||
example:
|
|
||||||
recipient: xxxxxx.user@gmail.com
|
|
||||||
description: OTP Sent
|
|
||||||
_links: {
|
|
||||||
"verifyotp": {
|
|
||||||
"href": "/tokens/verifyotp",
|
|
||||||
"method": "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Missing Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Missing Mandatory Parameter
|
|
||||||
detail: Required parameter {0} is missing.
|
|
||||||
Invalid Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Invalid Parameter
|
|
||||||
detail: Required parameter {0} is invalid.
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Unauthorized:
|
|
||||||
value:
|
|
||||||
status: 401
|
|
||||||
title: Unauthorized
|
|
||||||
detail: Invalid Access Token
|
|
||||||
"404":
|
|
||||||
description: Not found
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
TAT not found:
|
|
||||||
value:
|
|
||||||
status: 404
|
|
||||||
title: Not Found
|
|
||||||
detail: TAT Account Not Found
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
example:
|
|
||||||
error: An unknown error has occurred
|
|
||||||
/tokens/verifyotp:
|
|
||||||
parameters:
|
|
||||||
- name: X-HTM-JWT-AUTH-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
|
||||||
required: false
|
|
||||||
description: The JWT of a customer in case of touchpoint were customer logs in themselves
|
|
||||||
- name: X-HTM-CUSTOMER-PROFILE-ID-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 323
|
|
||||||
required: false
|
|
||||||
description: The id of the customer Profile
|
|
||||||
- name: X-HTM-ROLE-HEADER
|
|
||||||
in: header
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: Customer
|
|
||||||
required: false
|
|
||||||
description: The role of the HTM employee in the case of the SMP
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- TAT Verification
|
|
||||||
summary: Submit an OTP for a triggered OTP flow.
|
|
||||||
description: |
|
|
||||||
Submit an OTP for a triggered OTP flow. This can either be result of an AGO activation, or
|
|
||||||
result of an AGO authorization flow. Since the backoffice behaves slightly different depending
|
|
||||||
on which use case is executed, the calling TP needs to provide an `action` in the request body.
|
|
||||||
requestBody:
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/VerifyOtpRequest"
|
|
||||||
examples:
|
|
||||||
OTP verification for TAT security activation for token in customer account:
|
|
||||||
value:
|
|
||||||
ovPayTokenId: 42
|
|
||||||
otp: 123456
|
|
||||||
action: secure
|
|
||||||
OTP verification for TAT security authorization for anonymous token:
|
|
||||||
value:
|
|
||||||
xTat: 0f0defe8-828c-48e5-97e5-26d1d0179ef0
|
|
||||||
otp: 123456
|
|
||||||
action: authorize
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/VerifyOtpResponse'
|
|
||||||
examples:
|
|
||||||
Tat Secured:
|
|
||||||
value:
|
|
||||||
status: Success
|
|
||||||
description: TAT Secured
|
|
||||||
Tat Unsecured:
|
|
||||||
value:
|
|
||||||
status: Success
|
|
||||||
description: TAT Unsecured
|
|
||||||
Tat Authorized:
|
|
||||||
value:
|
|
||||||
status: Success
|
|
||||||
description: TAT Authorized
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Missing Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Missing Mandatory Parameter
|
|
||||||
detail: Required parameter {0} is missing.
|
|
||||||
Invalid Parameters:
|
|
||||||
value:
|
|
||||||
status: 400
|
|
||||||
title: Invalid Parameter
|
|
||||||
detail: Required parameter {0} is invalid.
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
examples:
|
|
||||||
Unauthorized:
|
|
||||||
value:
|
|
||||||
status: 401
|
|
||||||
title: Unauthorized
|
|
||||||
detail: Invalid Access Token
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/ErrorResponse"
|
|
||||||
example:
|
|
||||||
error: An unknown error has occurred
|
|
||||||
components:
|
|
||||||
schemas:
|
|
||||||
unavailable:
|
|
||||||
type: object
|
|
||||||
GenerateTatOutput:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
uid:
|
|
||||||
type: string
|
|
||||||
description: >-
|
|
||||||
An uid IS A unique identifier THAT is associated with the
|
|
||||||
user.
|
|
||||||
recipient:
|
|
||||||
type: string
|
|
||||||
description: >-
|
|
||||||
A recipient IS A unique identifier THAT is associated with the
|
|
||||||
TAT owner.
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
description: >-
|
|
||||||
A key IS a 32 character string THAT uniquely identifies the
|
|
||||||
OTP session.
|
|
||||||
EmailNotPreApprovedResponse:
|
|
||||||
type: object
|
|
||||||
description: >-
|
|
||||||
EmailNotPreApprovedResponse IS AN object THAT represents the response of
|
|
||||||
email pre-approval check.
|
|
||||||
properties:
|
|
||||||
recipient:
|
|
||||||
type: string
|
|
||||||
description: >-
|
|
||||||
A recipient IS A unique identifier THAT is associated with the TAT
|
|
||||||
owner.
|
|
||||||
example: xxxxxx.user@gmail.com
|
|
||||||
description:
|
|
||||||
type: string
|
|
||||||
description: >-
|
|
||||||
A description IS A string THAT describes the reason why the email is
|
|
||||||
not pre-approved.
|
|
||||||
example: OTP Sent
|
|
||||||
SecureTokenRequest:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
ovPayTokenId:
|
|
||||||
type: integer
|
|
||||||
example: 42
|
|
||||||
xTat:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 6134db53-9ae5-41d1-a343-36656b60b510
|
|
||||||
emailAddress:
|
|
||||||
type: string
|
|
||||||
format: email
|
|
||||||
example: stasjo@htm.nl
|
|
||||||
required:
|
|
||||||
- emailAddress
|
|
||||||
AuthorizeTokenRequest:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
ovPayTokenId:
|
|
||||||
type: integer
|
|
||||||
example: 42
|
|
||||||
xTat:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 6134db53-9ae5-41d1-a343-36656b60b510
|
|
||||||
VerifyOtpRequest:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
ovPayTokenId:
|
|
||||||
type: integer
|
|
||||||
example: 42
|
|
||||||
xTat:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: f3474452-e1d4-428c-b366-e5ad5965eb8c
|
|
||||||
otp:
|
|
||||||
type: string
|
|
||||||
example: 123456
|
|
||||||
action:
|
|
||||||
type: string
|
|
||||||
example: secure
|
|
||||||
required:
|
|
||||||
- otp
|
|
||||||
- action
|
|
||||||
VerifyOtpResponse:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
example: Success
|
|
||||||
description:
|
|
||||||
type: string
|
|
||||||
example: TAT Secured
|
|
||||||
ErrorResponse:
|
|
||||||
description: Default response when an invalid request has been sent
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
status:
|
|
||||||
type: integer
|
|
||||||
description: >-
|
|
||||||
A status IS An integer that represents the HTTP status code of the
|
|
||||||
response.
|
|
||||||
example: 400
|
|
||||||
title:
|
|
||||||
type: string
|
|
||||||
description: A title IS A string that provides a brief summary of the error.
|
|
||||||
detail:
|
|
||||||
type: string
|
|
||||||
description: A detail IS A string that provides more details about the error.
|
|
||||||
TokenStatusResponse:
|
|
||||||
type: object
|
|
||||||
description: >-
|
|
||||||
TokenStatusResponse IS AN object THAT represents the current state of the token in relation to the AGO security and authorization status of HTM.
|
|
||||||
required:
|
|
||||||
- isSecured
|
|
||||||
- isAuthorized
|
|
||||||
properties:
|
|
||||||
isSecured:
|
|
||||||
type: boolean
|
|
||||||
description: >-
|
|
||||||
Is the token secured in the national database (GBO)
|
|
||||||
example: false
|
|
||||||
isAuthorized:
|
|
||||||
type: boolean
|
|
||||||
description: >-
|
|
||||||
Does HTM have the authorization to access the secured data for this token, only applicable when isSecured equals True.
|
|
||||||
example: false
|
|
||||||
xTat:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
description: >-
|
|
||||||
The xtat of the customerToken given when token is unknown for the customer
|
|
||||||
example: 883674e5-54c7-47d6-a3e3-8781f0d3ffea
|
|
||||||
|
|
||||||
@ -243,7 +243,7 @@ paths:
|
|||||||
suffix: PhD
|
suffix: PhD
|
||||||
dateOfBirth: "2002-10-29"
|
dateOfBirth: "2002-10-29"
|
||||||
emailAddresses: TEST@HTM.NL
|
emailAddresses: TEST@HTM.NL
|
||||||
isEmailVerified: false
|
isEmailVerified: True
|
||||||
addresses:
|
addresses:
|
||||||
- addressId: 1
|
- addressId: 1
|
||||||
street: mystreet
|
street: mystreet
|
||||||
@ -332,6 +332,14 @@ paths:
|
|||||||
user: user
|
user: user
|
||||||
timestamp: "2023-10-20T17:05:52.000+02:00"
|
timestamp: "2023-10-20T17:05:52.000+02:00"
|
||||||
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
||||||
|
_links:
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?customerProfileId=1",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
- customerProfileId: 12
|
- customerProfileId: 12
|
||||||
customerNumber: 1000002
|
customerNumber: 1000002
|
||||||
debtorNumber: DB100121
|
debtorNumber: DB100121
|
||||||
@ -369,7 +377,7 @@ paths:
|
|||||||
suffix: PhD
|
suffix: PhD
|
||||||
dateOfBirth: "2002-10-29"
|
dateOfBirth: "2002-10-29"
|
||||||
emailAddresses: TEST@HTM.NL
|
emailAddresses: TEST@HTM.NL
|
||||||
isEmailVerified: false
|
isEmailVerified: False
|
||||||
address:
|
address:
|
||||||
- addressId: 1
|
- addressId: 1
|
||||||
street: mystreet
|
street: mystreet
|
||||||
@ -459,7 +467,32 @@ paths:
|
|||||||
user: user
|
user: user
|
||||||
timestamp: "2023-10-20T17:05:52.000+02:00"
|
timestamp: "2023-10-20T17:05:52.000+02:00"
|
||||||
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
||||||
href: "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?offset=20&limit=20"
|
_links:
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?customerProfileId=12",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_links:
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?offset=20",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
"prev":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
"next":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?offset=40",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
getCustomerActive:
|
getCustomerActive:
|
||||||
summary: getCustomerActive
|
summary: getCustomerActive
|
||||||
description: >-
|
description: >-
|
||||||
@ -493,7 +526,7 @@ paths:
|
|||||||
suffix: PhD
|
suffix: PhD
|
||||||
dateOfBirth: "2002-10-29"
|
dateOfBirth: "2002-10-29"
|
||||||
emailAddresses: TEST@HTM.NL
|
emailAddresses: TEST@HTM.NL
|
||||||
isEmailVerified: false
|
isEmailVerified: False
|
||||||
addresses:
|
addresses:
|
||||||
- addressId: 1
|
- addressId: 1
|
||||||
street: mystreet
|
street: mystreet
|
||||||
@ -582,7 +615,22 @@ paths:
|
|||||||
user: user
|
user: user
|
||||||
timestamp: "2023-10-20T17:05:52.000+02:00"
|
timestamp: "2023-10-20T17:05:52.000+02:00"
|
||||||
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
||||||
href: https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?offset=20&limit=20
|
_links:
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?customerProfileId=1",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_links:
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
getCustomerBlocked:
|
getCustomerBlocked:
|
||||||
summary: getCustomerBlocked
|
summary: getCustomerBlocked
|
||||||
description: >-
|
description: >-
|
||||||
@ -621,7 +669,7 @@ paths:
|
|||||||
suffix: PhD
|
suffix: PhD
|
||||||
dateOfBirth: "2002-10-29"
|
dateOfBirth: "2002-10-29"
|
||||||
emailAddresses: TEST@HTM.NL
|
emailAddresses: TEST@HTM.NL
|
||||||
isEmailVerified: false
|
isEmailVerified: True
|
||||||
addresses:
|
addresses:
|
||||||
- addressId: 1
|
- addressId: 1
|
||||||
street: mystreet
|
street: mystreet
|
||||||
@ -710,7 +758,22 @@ paths:
|
|||||||
user: user
|
user: user
|
||||||
timestamp: "2023-10-20T17:05:52.000+02:00"
|
timestamp: "2023-10-20T17:05:52.000+02:00"
|
||||||
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
correlationId: 01c6d8b4-1cd3-4f9b-85ea-c9adca53ce95
|
||||||
href: https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?offset=20&limit=20
|
_links:
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers?customerProfileId=1",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_links:
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/customers",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
400:
|
400:
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
content:
|
content:
|
||||||
@ -772,7 +835,7 @@ paths:
|
|||||||
suffix: jr
|
suffix: jr
|
||||||
dateOfBirth: "1970-01-01"
|
dateOfBirth: "1970-01-01"
|
||||||
emailAddress: j.jansen@hatseflats.nl
|
emailAddress: j.jansen@hatseflats.nl
|
||||||
isEmailVerified: false
|
isEmailVerified: False
|
||||||
addresses:
|
addresses:
|
||||||
- street: Laan van Meerdervoort
|
- street: Laan van Meerdervoort
|
||||||
houseNumber: 5
|
houseNumber: 5
|
||||||
@ -871,7 +934,7 @@ paths:
|
|||||||
suffix: "jr",
|
suffix: "jr",
|
||||||
dateOfBirth: "1970-01-01",
|
dateOfBirth: "1970-01-01",
|
||||||
emailAddress: "TEST@TEST1.NL",
|
emailAddress: "TEST@TEST1.NL",
|
||||||
isEmailVerified: false
|
isEmailVerified: False
|
||||||
}
|
}
|
||||||
updateCompleteEntity:
|
updateCompleteEntity:
|
||||||
value:
|
value:
|
||||||
@ -883,7 +946,7 @@ paths:
|
|||||||
suffix: "jr",
|
suffix: "jr",
|
||||||
dateOfBirth: "1970-01-01",
|
dateOfBirth: "1970-01-01",
|
||||||
emailAddress: "TEST@TEST1.NL",
|
emailAddress: "TEST@TEST1.NL",
|
||||||
isEmailVerified: false
|
isEmailVerified: True
|
||||||
}
|
}
|
||||||
required: true
|
required: true
|
||||||
responses:
|
responses:
|
||||||
@ -1375,7 +1438,13 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/patchDeviceResponse"
|
$ref: "#/components/schemas/getDevices"
|
||||||
|
examples:
|
||||||
|
updateDeviceResponse:
|
||||||
|
value:
|
||||||
|
deviceId: "5bedce29-af0c-4f3c-b182-2caa8a1f9377"
|
||||||
|
externalDeviceId: "7122a988-a00a-417d-a5b4-da2d91354976"
|
||||||
|
alias: "iPhone zakelijk"
|
||||||
|
|
||||||
security:
|
security:
|
||||||
- default: []
|
- default: []
|
||||||
@ -1538,7 +1607,24 @@ paths:
|
|||||||
"replacedByTokenId": 12,
|
"replacedByTokenId": 12,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/ovPayTokens?offset=20&limit=20"
|
"_links":
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/ovPayTokens?offset=20",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
"prev":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/ovPayTokens",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
"next":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/ovPayTokens?offset=40",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
/customers/{customerProfileId}/ovpaytokens:
|
/customers/{customerProfileId}/ovpaytokens:
|
||||||
post:
|
post:
|
||||||
@ -1857,10 +1943,9 @@ paths:
|
|||||||
"created": "2024-10-20T17:05:52.000",
|
"created": "2024-10-20T17:05:52.000",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/billingInformations?offset=20&limit=20"
|
|
||||||
}
|
}
|
||||||
getBillingInformationSingleSpecificCustomer:
|
getBillingInformationSingleSpecificCustomer:
|
||||||
summary: Get single billing information entity for a specific customers
|
summary: Get singel billing information entity for a specific customers
|
||||||
description: >-
|
description: >-
|
||||||
Found one billing information matching the search parameters
|
Found one billing information matching the search parameters
|
||||||
value:
|
value:
|
||||||
@ -2050,7 +2135,59 @@ paths:
|
|||||||
"updateTimestamp": "2024-03-22T08:55:00",
|
"updateTimestamp": "2024-03-22T08:55:00",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/directdebitmandates?offset=20&limit=20"
|
"_links":
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/directdebitmandates",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
"next":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/directdebitmandates?offset=20",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
getDirectDebitMandateWithNextPageandPreviousPage:
|
||||||
|
value:
|
||||||
|
{
|
||||||
|
"directDebitMandates":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"directDebitMandateId": 71,
|
||||||
|
"customerProfileId": 12,
|
||||||
|
"billingInformationId": 51,
|
||||||
|
"directDebitMandateType":
|
||||||
|
{
|
||||||
|
"directDebitMandateTypeId": 1,
|
||||||
|
"name": "import",
|
||||||
|
"description": "import",
|
||||||
|
},
|
||||||
|
"created": "2024-03-22T08:55:00",
|
||||||
|
"mandateReference": "CORE01",
|
||||||
|
"mandateState": "SIGNED",
|
||||||
|
"updateTimestamp": "2024-03-22T08:55:00",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"_links":
|
||||||
|
{
|
||||||
|
"self":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/directdebitmandates?offset=20",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
"prev":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/directdebitmandates",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
"next":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/abtcustomers/2.0/directdebitmandates?offset=40",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
/billingInformation/{billingInformationId}/directdebitmandates:
|
/billingInformation/{billingInformationId}/directdebitmandates:
|
||||||
post:
|
post:
|
||||||
@ -2706,7 +2843,7 @@ components:
|
|||||||
emailAddress:
|
emailAddress:
|
||||||
type: string
|
type: string
|
||||||
isEmailVerified:
|
isEmailVerified:
|
||||||
type: boolean
|
type: string
|
||||||
postOvPayTokenResponse:
|
postOvPayTokenResponse:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -2720,14 +2857,6 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/getDeviceEntity"
|
$ref: "#/components/schemas/getDeviceEntity"
|
||||||
patchDeviceResponse:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
deviceId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: "b2c8a8c6-3d1c-4b6b-8f8d-3a6a1b6a1b6a"
|
|
||||||
|
|
||||||
getDeviceEntity:
|
getDeviceEntity:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@ -49,8 +49,6 @@ paths:
|
|||||||
- status
|
- status
|
||||||
- aggregationReference
|
- aggregationReference
|
||||||
- accountingSystemReference
|
- accountingSystemReference
|
||||||
- createdOn
|
|
||||||
- lastUpdatedOn
|
|
||||||
- name: $select
|
- name: $select
|
||||||
in: query
|
in: query
|
||||||
description: Select properties to be returned
|
description: Select properties to be returned
|
||||||
@ -81,8 +79,6 @@ paths:
|
|||||||
- status
|
- status
|
||||||
- aggregationReference
|
- aggregationReference
|
||||||
- accountingSystemReference
|
- accountingSystemReference
|
||||||
- createdOn
|
|
||||||
- lastUpdatedOn
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
@ -122,8 +118,6 @@ paths:
|
|||||||
status: created
|
status: created
|
||||||
aggregationReference: null
|
aggregationReference: null
|
||||||
accountingSystemReference: null
|
accountingSystemReference: null
|
||||||
createdOn: 2024-11-04T00:00:00Z
|
|
||||||
lastUpdatedOn: 2024-11-04T04:00:00Z
|
|
||||||
- "@odata.etag": e671c8a1-b918-4867-bf12-5289822479c3
|
- "@odata.etag": e671c8a1-b918-4867-bf12-5289822479c3
|
||||||
transactionItemRowId: 3232
|
transactionItemRowId: 3232
|
||||||
transactionItemId: 1c1fc1c8-57f4-4336-9b43-a974eae5afbf
|
transactionItemId: 1c1fc1c8-57f4-4336-9b43-a974eae5afbf
|
||||||
@ -143,8 +137,6 @@ paths:
|
|||||||
status: failed
|
status: failed
|
||||||
aggregationReference: null
|
aggregationReference: null
|
||||||
accountingSystemReference: null
|
accountingSystemReference: null
|
||||||
createdOn: 2024-11-04T00:00:00Z
|
|
||||||
lastUpdatedOn: 2024-11-04T04:00:00Z
|
|
||||||
- "@odata.etag": be2715d4-4eff-4562-9bf3-5c43ad23e2c8
|
- "@odata.etag": be2715d4-4eff-4562-9bf3-5c43ad23e2c8
|
||||||
transactionItemRowId: 3233
|
transactionItemRowId: 3233
|
||||||
transactionItemId: 3f58441e-dc8f-4956-9bc5-c952312476db
|
transactionItemId: 3f58441e-dc8f-4956-9bc5-c952312476db
|
||||||
@ -164,8 +156,6 @@ paths:
|
|||||||
status: returned to src
|
status: returned to src
|
||||||
aggregationReference: FIKO-171f40609e
|
aggregationReference: FIKO-171f40609e
|
||||||
accountingSystemReference: null
|
accountingSystemReference: null
|
||||||
createdOn: 2024-11-04T00:00:00Z
|
|
||||||
lastUpdatedOn: 2024-11-04T04:00:00Z
|
|
||||||
- "@odata.etag": 52130c4d-e944-4454-a73e-8d55449a4bd1
|
- "@odata.etag": 52130c4d-e944-4454-a73e-8d55449a4bd1
|
||||||
transactionItemRowId: 3234
|
transactionItemRowId: 3234
|
||||||
transactionItemId: 4418825f-3f9b-45bc-b662-dc3cd4ce6599
|
transactionItemId: 4418825f-3f9b-45bc-b662-dc3cd4ce6599
|
||||||
@ -185,8 +175,6 @@ paths:
|
|||||||
status: returned to trx-db
|
status: returned to trx-db
|
||||||
aggregationReference: null
|
aggregationReference: null
|
||||||
accountingSystemReference: null
|
accountingSystemReference: null
|
||||||
createdOn: 2024-11-04T00:00:00Z
|
|
||||||
lastUpdatedOn: 2024-11-04T04:00:00Z
|
|
||||||
- "@odata.etag": 7da305e1-85cd-4250-ad77-8b54b2649cfb
|
- "@odata.etag": 7da305e1-85cd-4250-ad77-8b54b2649cfb
|
||||||
transactionItemRowId: 3235
|
transactionItemRowId: 3235
|
||||||
transactionItemId: 2ddc1831-cf7b-4a77-8aa1-11aaf8e98d9f
|
transactionItemId: 2ddc1831-cf7b-4a77-8aa1-11aaf8e98d9f
|
||||||
@ -206,8 +194,6 @@ paths:
|
|||||||
status: re-entered
|
status: re-entered
|
||||||
aggregationReference: null
|
aggregationReference: null
|
||||||
accountingSystemReference: null
|
accountingSystemReference: null
|
||||||
createdOn: 2024-11-04T00:00:00Z
|
|
||||||
lastUpdatedOn: 2024-11-04T04:00:00Z
|
|
||||||
- "@odata.etag": c3b17d21-0506-474d-b3d4-7ff654f368b9
|
- "@odata.etag": c3b17d21-0506-474d-b3d4-7ff654f368b9
|
||||||
transactionItemRowId: 3236
|
transactionItemRowId: 3236
|
||||||
transactionItemId: 5ab2513d-f334-4cf8-8895-4e7269374a4b
|
transactionItemId: 5ab2513d-f334-4cf8-8895-4e7269374a4b
|
||||||
@ -227,8 +213,6 @@ paths:
|
|||||||
status: succeeded
|
status: succeeded
|
||||||
aggregationReference: FIKO-6a4fca8cd6
|
aggregationReference: FIKO-6a4fca8cd6
|
||||||
accountingSystemReference: U4F-123456
|
accountingSystemReference: U4F-123456
|
||||||
createdOn: 2024-11-04T00:00:00Z
|
|
||||||
lastUpdatedOn: 2024-11-04T04:00:00Z
|
|
||||||
security:
|
security:
|
||||||
- default: []
|
- default: []
|
||||||
x-auth-type: Application & Application User
|
x-auth-type: Application & Application User
|
||||||
@ -450,7 +434,7 @@ paths:
|
|||||||
summary: Add a processing failure.
|
summary: Add a processing failure.
|
||||||
description: Add a processing failure.
|
description: Add a processing failure.
|
||||||
tags:
|
tags:
|
||||||
- Failures v2.3
|
- Failures v2.2
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -471,7 +455,6 @@ paths:
|
|||||||
reasonCode: "012"
|
reasonCode: "012"
|
||||||
reasonDescription: Transaction date is in the future.
|
reasonDescription: Transaction date is in the future.
|
||||||
resolved: false
|
resolved: false
|
||||||
journalEntryId: 0e53b984-16b2-4ef7-b669-29bcdad2a3ce
|
|
||||||
responses:
|
responses:
|
||||||
"201":
|
"201":
|
||||||
description: Created
|
description: Created
|
||||||
@ -489,6 +472,67 @@ paths:
|
|||||||
- default: []
|
- default: []
|
||||||
x-auth-type: Application & Application User
|
x-auth-type: Application & Application User
|
||||||
x-throttling-tier: Unlimited
|
x-throttling-tier: Unlimited
|
||||||
|
/transactionitems/{transactionItemId}/transactionaudittrails:
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: transactionItemId
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
example: 9834b346-d68c-438d-9bd5-6716422c2657
|
||||||
|
required: true
|
||||||
|
description: The id of the transaction item to process.
|
||||||
|
post:
|
||||||
|
summary: Add an audit trail entry.
|
||||||
|
description: Add an audit trail entry.
|
||||||
|
tags:
|
||||||
|
- Audit Trail v2.2
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/TransactionAuditTrailsPostRequestBody"
|
||||||
|
examples:
|
||||||
|
Add new transaction audit trail for created transaction item:
|
||||||
|
summary: Add new transaction audit trail for created transaction item
|
||||||
|
description: Add a new audit trail record for a newly created transaction item.
|
||||||
|
value:
|
||||||
|
user: fiko
|
||||||
|
timestamp: 2022-01-01 12:34:00
|
||||||
|
action: create
|
||||||
|
status: created
|
||||||
|
description: Transaction item created.
|
||||||
|
correlationId: null
|
||||||
|
Add new transaction audit trail for updated transaction item:
|
||||||
|
summary: Add new transaction audit trail for updated transaction item
|
||||||
|
description: Add a new audit trail record for an updated transaction item.
|
||||||
|
value:
|
||||||
|
user: ad.vogelaar
|
||||||
|
timestamp: 2022-01-02 12:34:00
|
||||||
|
action: update
|
||||||
|
status: return to src
|
||||||
|
description: Transaction item returned to source.
|
||||||
|
correlationId: 0dc216ea-58e7-4a5e-aa18-449f0304209c
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/TransactionAuditTrailsPostResponseBody"
|
||||||
|
examples:
|
||||||
|
Transaction audit trail record created:
|
||||||
|
summary: Transaction audit trail record created
|
||||||
|
description: |
|
||||||
|
A new audit trail record for this transaction item was successfully created.
|
||||||
|
The transactionAuditTrailId is returned as a reference for the consumer.
|
||||||
|
value:
|
||||||
|
transactionAuditTrailId: 37a8095b-19db-498f-9349-5f37d21c5bdf
|
||||||
|
security:
|
||||||
|
- default: []
|
||||||
|
x-auth-type: Application & Application User
|
||||||
|
x-throttling-tier: Unlimited
|
||||||
/Odata/TransactionAuditTrail:
|
/Odata/TransactionAuditTrail:
|
||||||
get:
|
get:
|
||||||
summary: Find audit trail entries.
|
summary: Find audit trail entries.
|
||||||
@ -520,7 +564,6 @@ paths:
|
|||||||
- action
|
- action
|
||||||
- status
|
- status
|
||||||
- correlationId
|
- correlationId
|
||||||
- journalEntryId
|
|
||||||
- name: $select
|
- name: $select
|
||||||
in: query
|
in: query
|
||||||
description: Select properties to be returned
|
description: Select properties to be returned
|
||||||
@ -541,7 +584,6 @@ paths:
|
|||||||
- action
|
- action
|
||||||
- status
|
- status
|
||||||
- correlationId
|
- correlationId
|
||||||
- journalEntryId
|
|
||||||
- name: $expand
|
- name: $expand
|
||||||
in: query
|
in: query
|
||||||
description: Expand related entities
|
description: Expand related entities
|
||||||
@ -555,7 +597,6 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- TransactionItem
|
- TransactionItem
|
||||||
- JournalEntry
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
@ -586,7 +627,6 @@ paths:
|
|||||||
status: created
|
status: created
|
||||||
description: Transaction created.
|
description: Transaction created.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": 1ce407d3-4725-46b8-92b2-47282ccd38f5
|
- "@odata.etag": 1ce407d3-4725-46b8-92b2-47282ccd38f5
|
||||||
transactionAuditTrailRowId: 8219
|
transactionAuditTrailRowId: 8219
|
||||||
transactionAuditTrailId: 1d234fc1-eb16-41d3-b2e0-e400e17b017f
|
transactionAuditTrailId: 1d234fc1-eb16-41d3-b2e0-e400e17b017f
|
||||||
@ -597,7 +637,6 @@ paths:
|
|||||||
status: created
|
status: created
|
||||||
description: Transaction created.
|
description: Transaction created.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": c8dec28b-bb85-4cb2-8a56-4a95fb2ed7bb
|
- "@odata.etag": c8dec28b-bb85-4cb2-8a56-4a95fb2ed7bb
|
||||||
transactionAuditTrailRowId: 8220
|
transactionAuditTrailRowId: 8220
|
||||||
transactionAuditTrailId: f4798a84-489d-4533-9dfe-42423c70f6b6
|
transactionAuditTrailId: f4798a84-489d-4533-9dfe-42423c70f6b6
|
||||||
@ -608,7 +647,6 @@ paths:
|
|||||||
status: return to src
|
status: return to src
|
||||||
description: Transaction retunred to source.
|
description: Transaction retunred to source.
|
||||||
correlationId: a3891560-3084-42cb-867c-f289e7cda47d
|
correlationId: a3891560-3084-42cb-867c-f289e7cda47d
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": 967ddfa0-835e-4954-a4af-2eb11de325dc
|
- "@odata.etag": 967ddfa0-835e-4954-a4af-2eb11de325dc
|
||||||
transactionAuditTrailRowId: 8221
|
transactionAuditTrailRowId: 8221
|
||||||
transactionAuditTrailId: cc80d58d-6ee7-409a-8c14-b1f807e67c10
|
transactionAuditTrailId: cc80d58d-6ee7-409a-8c14-b1f807e67c10
|
||||||
@ -619,7 +657,6 @@ paths:
|
|||||||
status: failed
|
status: failed
|
||||||
description: Validation XYZ failed.
|
description: Validation XYZ failed.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: a062f64f-f39e-48e7-9793-efbfa86d2827
|
|
||||||
List containing multiple transaction audit trails of one transaction item:
|
List containing multiple transaction audit trails of one transaction item:
|
||||||
summary: List containing multiple audit trails of one transaction item
|
summary: List containing multiple audit trails of one transaction item
|
||||||
description: List containing multiple audit trail records of one transaction item (with id `d667d293-aa82-4c9e-9b10-77cffc9058a1`).
|
description: List containing multiple audit trail records of one transaction item (with id `d667d293-aa82-4c9e-9b10-77cffc9058a1`).
|
||||||
@ -636,7 +673,6 @@ paths:
|
|||||||
status: re-entered
|
status: re-entered
|
||||||
description: Transaction re-entered.
|
description: Transaction re-entered.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": 1ce407d3-4725-46b8-92b2-47282ccd38f5
|
- "@odata.etag": 1ce407d3-4725-46b8-92b2-47282ccd38f5
|
||||||
transactionAuditTrailRowId: 8219
|
transactionAuditTrailRowId: 8219
|
||||||
transactionAuditTrailId: b2192e6c-ab79-4000-a04d-d8f4d574a82f
|
transactionAuditTrailId: b2192e6c-ab79-4000-a04d-d8f4d574a82f
|
||||||
@ -647,7 +683,6 @@ paths:
|
|||||||
status: return to src
|
status: return to src
|
||||||
description: Transaction retunred to source.
|
description: Transaction retunred to source.
|
||||||
correlationId: a3891560-3084-42cb-867c-f289e7cda47d
|
correlationId: a3891560-3084-42cb-867c-f289e7cda47d
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": c8dec28b-bb85-4cb2-8a56-4a95fb2ed7bb
|
- "@odata.etag": c8dec28b-bb85-4cb2-8a56-4a95fb2ed7bb
|
||||||
transactionAuditTrailRowId: 8220
|
transactionAuditTrailRowId: 8220
|
||||||
transactionAuditTrailId: 1d759985-7f1a-48bd-8dd1-efa30ce26423
|
transactionAuditTrailId: 1d759985-7f1a-48bd-8dd1-efa30ce26423
|
||||||
@ -658,7 +693,6 @@ paths:
|
|||||||
status: failed
|
status: failed
|
||||||
description: Validation XYZ failed.
|
description: Validation XYZ failed.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: b479507a-a65d-48b5-8476-87c88ba3c560
|
|
||||||
- "@odata.etag": 967ddfa0-835e-4954-a4af-2eb11de325dc
|
- "@odata.etag": 967ddfa0-835e-4954-a4af-2eb11de325dc
|
||||||
transactionAuditTrailRowId: 8221
|
transactionAuditTrailRowId: 8221
|
||||||
transactionAuditTrailId: afce35b2-1dff-4ace-98d0-4b9ac405c87d
|
transactionAuditTrailId: afce35b2-1dff-4ace-98d0-4b9ac405c87d
|
||||||
@ -669,7 +703,6 @@ paths:
|
|||||||
status: created
|
status: created
|
||||||
description: Transaction created.
|
description: Transaction created.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: null
|
|
||||||
List containing multiple audit trails of different failed transactions:
|
List containing multiple audit trails of different failed transactions:
|
||||||
summary: List containing multiple audit trails of different failed transactions
|
summary: List containing multiple audit trails of different failed transactions
|
||||||
description: List containing multiple audit trails of different failed transactions (status = failed).
|
description: List containing multiple audit trails of different failed transactions (status = failed).
|
||||||
@ -686,7 +719,6 @@ paths:
|
|||||||
status: failed
|
status: failed
|
||||||
description: Validation XYZ failed.
|
description: Validation XYZ failed.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": 1ce407d3-4725-46b8-92b2-47282ccd38f5
|
- "@odata.etag": 1ce407d3-4725-46b8-92b2-47282ccd38f5
|
||||||
transactionAuditTrailRowId: 8219
|
transactionAuditTrailRowId: 8219
|
||||||
transactionAuditTrailId: 1d234fc1-eb16-41d3-b2e0-e400e17b017f
|
transactionAuditTrailId: 1d234fc1-eb16-41d3-b2e0-e400e17b017f
|
||||||
@ -697,7 +729,6 @@ paths:
|
|||||||
status: failed
|
status: failed
|
||||||
description: Validation XYZ failed.
|
description: Validation XYZ failed.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: 43a98533-bb01-4aad-8d61-005051125969
|
|
||||||
- "@odata.etag": c8dec28b-bb85-4cb2-8a56-4a95fb2ed7bb
|
- "@odata.etag": c8dec28b-bb85-4cb2-8a56-4a95fb2ed7bb
|
||||||
transactionAuditTrailRowId: 8220
|
transactionAuditTrailRowId: 8220
|
||||||
transactionAuditTrailId: f4798a84-489d-4533-9dfe-42423c70f6b6
|
transactionAuditTrailId: f4798a84-489d-4533-9dfe-42423c70f6b6
|
||||||
@ -708,7 +739,6 @@ paths:
|
|||||||
status: failed
|
status: failed
|
||||||
description: Validation XYZ failed.
|
description: Validation XYZ failed.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": 967ddfa0-835e-4954-a4af-2eb11de325dc
|
- "@odata.etag": 967ddfa0-835e-4954-a4af-2eb11de325dc
|
||||||
transactionAuditTrailRowId: 8221
|
transactionAuditTrailRowId: 8221
|
||||||
transactionAuditTrailId: cc80d58d-6ee7-409a-8c14-b1f807e67c10
|
transactionAuditTrailId: cc80d58d-6ee7-409a-8c14-b1f807e67c10
|
||||||
@ -719,7 +749,6 @@ paths:
|
|||||||
status: failed
|
status: failed
|
||||||
description: Validation XYZ failed.
|
description: Validation XYZ failed.
|
||||||
correlationId: null
|
correlationId: null
|
||||||
journalEntryId: null
|
|
||||||
security:
|
security:
|
||||||
- default: []
|
- default: []
|
||||||
x-auth-type: Application & Application User
|
x-auth-type: Application & Application User
|
||||||
@ -757,7 +786,6 @@ paths:
|
|||||||
- reasonDescription
|
- reasonDescription
|
||||||
- resolved
|
- resolved
|
||||||
- change
|
- change
|
||||||
- journalEntryId
|
|
||||||
- name: $select
|
- name: $select
|
||||||
in: query
|
in: query
|
||||||
description: Select properties to be returned
|
description: Select properties to be returned
|
||||||
@ -780,7 +808,6 @@ paths:
|
|||||||
- reasonDescription
|
- reasonDescription
|
||||||
- resolved
|
- resolved
|
||||||
- change
|
- change
|
||||||
- journalEntryId
|
|
||||||
- name: $expand
|
- name: $expand
|
||||||
in: query
|
in: query
|
||||||
description: Expand related entities
|
description: Expand related entities
|
||||||
@ -794,7 +821,6 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- TransactionItem
|
- TransactionItem
|
||||||
- JournalEntry
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
@ -830,7 +856,6 @@ paths:
|
|||||||
reasonDescription: Cost type does not exist.
|
reasonDescription: Cost type does not exist.
|
||||||
resolved: false
|
resolved: false
|
||||||
change: null
|
change: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": ff49829d-a5de-4c1a-b331-15fd9c71dfe9
|
- "@odata.etag": ff49829d-a5de-4c1a-b331-15fd9c71dfe9
|
||||||
processingFailureRowId: 10
|
processingFailureRowId: 10
|
||||||
processingFailureId: ccc06dc9-956d-47d8-bde7-9644ddde2193
|
processingFailureId: ccc06dc9-956d-47d8-bde7-9644ddde2193
|
||||||
@ -842,7 +867,6 @@ paths:
|
|||||||
reasonDescription: Cost center does not exist.
|
reasonDescription: Cost center does not exist.
|
||||||
resolved: true
|
resolved: true
|
||||||
change: Adapt config
|
change: Adapt config
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": 5d5d3351-d3f1-49b2-905f-4dbbe1cc30e3
|
- "@odata.etag": 5d5d3351-d3f1-49b2-905f-4dbbe1cc30e3
|
||||||
processingFailureRowId: 11
|
processingFailureRowId: 11
|
||||||
processingFailureId: 96bf8d44-0030-4509-b24e-2d62299779c5
|
processingFailureId: 96bf8d44-0030-4509-b24e-2d62299779c5
|
||||||
@ -854,7 +878,6 @@ paths:
|
|||||||
reasonDescription: Department does not exist.
|
reasonDescription: Department does not exist.
|
||||||
resolved: true
|
resolved: true
|
||||||
change: Adapt config
|
change: Adapt config
|
||||||
journalEntryId: null
|
|
||||||
List of unfiltered processing failures:
|
List of unfiltered processing failures:
|
||||||
summary: List of unfiltered processing failures
|
summary: List of unfiltered processing failures
|
||||||
description: |
|
description: |
|
||||||
@ -874,7 +897,6 @@ paths:
|
|||||||
reasonDescription: Transaction date is in the future
|
reasonDescription: Transaction date is in the future
|
||||||
resolved: false
|
resolved: false
|
||||||
change: null
|
change: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": 584d3a8a-48bc-45f9-99be-8dd70399e6e4
|
- "@odata.etag": 584d3a8a-48bc-45f9-99be-8dd70399e6e4
|
||||||
processingFailureRowId: 10
|
processingFailureRowId: 10
|
||||||
processingFailureId: 76aa82e1-a10f-4664-a84f-1f30d60884b3
|
processingFailureId: 76aa82e1-a10f-4664-a84f-1f30d60884b3
|
||||||
@ -886,7 +908,6 @@ paths:
|
|||||||
reasonDescription: Cost center does not exist.
|
reasonDescription: Cost center does not exist.
|
||||||
resolved: false
|
resolved: false
|
||||||
change: null
|
change: null
|
||||||
journalEntryId: null
|
|
||||||
- "@odata.etag": df4ade9b-1bda-4d91-a5ba-4dbe067568a0
|
- "@odata.etag": df4ade9b-1bda-4d91-a5ba-4dbe067568a0
|
||||||
processingFailureRowId: 11
|
processingFailureRowId: 11
|
||||||
processingFailureId: 25d2dd6f-ae17-44a7-b7a5-43eaf6de78e1
|
processingFailureId: 25d2dd6f-ae17-44a7-b7a5-43eaf6de78e1
|
||||||
@ -898,7 +919,6 @@ paths:
|
|||||||
reasonDescription: Department does not exist.
|
reasonDescription: Department does not exist.
|
||||||
resolved: false
|
resolved: false
|
||||||
change: null
|
change: null
|
||||||
journalEntryId: null
|
|
||||||
security:
|
security:
|
||||||
- default: []
|
- default: []
|
||||||
x-auth-type: Application & Application User
|
x-auth-type: Application & Application User
|
||||||
@ -949,415 +969,6 @@ paths:
|
|||||||
- default: []
|
- default: []
|
||||||
x-auth-type: Application & Application User
|
x-auth-type: Application & Application User
|
||||||
x-throttling-tier: Unlimited
|
x-throttling-tier: Unlimited
|
||||||
/Odata/JournalEntries:
|
|
||||||
get:
|
|
||||||
summary: Find journalEntry.
|
|
||||||
description: Find journalEntry.
|
|
||||||
tags:
|
|
||||||
- Odata
|
|
||||||
parameters:
|
|
||||||
- $ref: "#/components/parameters/top"
|
|
||||||
- $ref: "#/components/parameters/skip"
|
|
||||||
- $ref: "#/components/parameters/filter"
|
|
||||||
- $ref: "#/components/parameters/count"
|
|
||||||
- name: $orderby
|
|
||||||
in: query
|
|
||||||
description: Order items by property values
|
|
||||||
required: false
|
|
||||||
style: form
|
|
||||||
explode: false
|
|
||||||
schema:
|
|
||||||
uniqueItems: true
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- journalEntryId
|
|
||||||
- aggregationReference
|
|
||||||
- accountingSystemReference
|
|
||||||
- name: $select
|
|
||||||
in: query
|
|
||||||
description: Select properties to be returned
|
|
||||||
required: false
|
|
||||||
style: form
|
|
||||||
explode: false
|
|
||||||
schema:
|
|
||||||
uniqueItems: true
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- journalEntryId
|
|
||||||
- aggregationReference
|
|
||||||
- accountingSystemReference
|
|
||||||
- data
|
|
||||||
- response
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/JournalEntryGetResponseBody"
|
|
||||||
examples:
|
|
||||||
List containing all journal entries:
|
|
||||||
summary: List containing all journal entries
|
|
||||||
description: Returns a list containing all journal entries (no filters applied).
|
|
||||||
value:
|
|
||||||
"@odata.context": "$metadata#JournalEntry"
|
|
||||||
value:
|
|
||||||
- "@odata.etag": 8f085711-eeae-44ed-bac1-06779bedb480
|
|
||||||
journalEntryId: e0af8c8f-d421-4567-a14e-48e2a1bb86fb
|
|
||||||
aggregationReference: FIKO-123456
|
|
||||||
accountingSystemReference: null
|
|
||||||
data: {
|
|
||||||
"transaction": {
|
|
||||||
"header": {
|
|
||||||
"key": {
|
|
||||||
"cmpCode": "1HTM",
|
|
||||||
"code": "OPBR-FIKO"
|
|
||||||
},
|
|
||||||
"timeStamp": 0,
|
|
||||||
"inputDate": "2026-07-20T00:00:00Z",
|
|
||||||
"period": "2026/6",
|
|
||||||
"curCode": "EUR",
|
|
||||||
"date": "2026-07-20T00:00:00Z",
|
|
||||||
"originalCompany": "1HTM",
|
|
||||||
"originalCode": "OPBR-FIKO",
|
|
||||||
"completionWorkflow": {
|
|
||||||
"completionStatus": "wfl_no_completion"
|
|
||||||
},
|
|
||||||
"salesInvoiceStatus": "salesinv_notyetinv"
|
|
||||||
},
|
|
||||||
"lines": {
|
|
||||||
"line": [
|
|
||||||
{
|
|
||||||
"number": 1,
|
|
||||||
"accountCode": "100.99999.D150000001",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"lineType": "summary",
|
|
||||||
"lineSense": "debit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"description": "test",
|
|
||||||
"extRef1": "99999991",
|
|
||||||
"extRef2": "99999",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 2,
|
|
||||||
"accountCode": "642.41236.609311",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"userStatus": "",
|
|
||||||
"lineType": "analysis",
|
|
||||||
"lineSense": "credit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response: {
|
|
||||||
"status": "failed",
|
|
||||||
"message": [
|
|
||||||
{
|
|
||||||
"code": "352",
|
|
||||||
"reason": "Documentregel 1 kan niet geboekt worden."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "159",
|
|
||||||
"reason": "Element 99999 (niveau 2) is niet toegestaan in linkerlijst van element D150000001 (niveau 3)."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"hints": [],
|
|
||||||
"paths": [
|
|
||||||
"/InputRequest/PostToBooks/Request/Transaction/Lines/Line[1]/AccountCode"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
- "@odata.etag": 66c033af-fc67-4eb2-9d17-d74a0166470f
|
|
||||||
journalEntryId: 36a34bd8-2b84-4c89-87a4-22e809f6ed4a
|
|
||||||
aggregationReference: FIKO-123457
|
|
||||||
accountingSystemReference: "OPBR-FIKO10000090"
|
|
||||||
data: {
|
|
||||||
"transaction": {
|
|
||||||
"header": {
|
|
||||||
"key": {
|
|
||||||
"cmpCode": "1HTM",
|
|
||||||
"code": "OPBR-FIKO"
|
|
||||||
},
|
|
||||||
"timeStamp": 0,
|
|
||||||
"inputDate": "2026-07-20T00:00:00Z",
|
|
||||||
"period": "2026/6",
|
|
||||||
"curCode": "EUR",
|
|
||||||
"date": "2026-07-20T00:00:00Z",
|
|
||||||
"originalCompany": "1HTM",
|
|
||||||
"originalCode": "OPBR-FIKO",
|
|
||||||
"completionWorkflow": {
|
|
||||||
"completionStatus": "wfl_no_completion"
|
|
||||||
},
|
|
||||||
"salesInvoiceStatus": "salesinv_notyetinv"
|
|
||||||
},
|
|
||||||
"lines": {
|
|
||||||
"line": [
|
|
||||||
{
|
|
||||||
"number": 1,
|
|
||||||
"accountCode": "100.99999.D150000001",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"lineType": "summary",
|
|
||||||
"lineSense": "debit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"description": "test",
|
|
||||||
"extRef1": "99999991",
|
|
||||||
"extRef2": "99999",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 2,
|
|
||||||
"accountCode": "642.41236.609311",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"userStatus": "",
|
|
||||||
"lineType": "analysis",
|
|
||||||
"lineSense": "credit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response: {
|
|
||||||
"key": {
|
|
||||||
"$type": "finance_transaction_txnKey",
|
|
||||||
"cmpCode": "1HTM",
|
|
||||||
"code": "OPBR-FIKO",
|
|
||||||
"number": " 10000090"
|
|
||||||
},
|
|
||||||
"suppliedNumber": ""
|
|
||||||
}
|
|
||||||
- "@odata.etag": 159f526c-3c88-48a1-93a0-e16430500bef
|
|
||||||
journalEntryId: 6097121f-f300-4c0b-ab8d-0a24685bda92
|
|
||||||
aggregationReference: FIKO-123458
|
|
||||||
accountingSystemReference: null
|
|
||||||
data: {
|
|
||||||
"transaction": {
|
|
||||||
"header": {
|
|
||||||
"key": {
|
|
||||||
"cmpCode": "1HTM",
|
|
||||||
"code": "OPBR-FIKO"
|
|
||||||
},
|
|
||||||
"timeStamp": 0,
|
|
||||||
"inputDate": "2026-07-20T00:00:00Z",
|
|
||||||
"period": "2026/6",
|
|
||||||
"curCode": "EUR",
|
|
||||||
"date": "2026-07-20T00:00:00Z",
|
|
||||||
"originalCompany": "1HTM",
|
|
||||||
"originalCode": "OPBR-FIKO",
|
|
||||||
"completionWorkflow": {
|
|
||||||
"completionStatus": "wfl_no_completion"
|
|
||||||
},
|
|
||||||
"salesInvoiceStatus": "salesinv_notyetinv"
|
|
||||||
},
|
|
||||||
"lines": {
|
|
||||||
"line": [
|
|
||||||
{
|
|
||||||
"number": 1,
|
|
||||||
"accountCode": "100.99999.D150000001",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"lineType": "summary",
|
|
||||||
"lineSense": "debit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"description": "test",
|
|
||||||
"extRef1": "99999991",
|
|
||||||
"extRef2": "99999",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 2,
|
|
||||||
"accountCode": "642.41236.609311",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"userStatus": "",
|
|
||||||
"lineType": "analysis",
|
|
||||||
"lineSense": "credit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response: null
|
|
||||||
security:
|
|
||||||
- default: []
|
|
||||||
x-auth-type: Application & Application User
|
|
||||||
x-throttling-tier: Unlimited
|
|
||||||
/journalEntries:
|
|
||||||
post:
|
|
||||||
summary: Add a journalEntry.
|
|
||||||
description: Add a journalEntry.
|
|
||||||
tags:
|
|
||||||
- journalEntries v1.0
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/JournalEntryPostRequestBody"
|
|
||||||
examples:
|
|
||||||
Add a new journalEntry:
|
|
||||||
summary: Add a new journalEntry
|
|
||||||
description: In this example we add a new journalEntry.
|
|
||||||
value:
|
|
||||||
aggregationReference: FIKO-123456
|
|
||||||
data: {
|
|
||||||
"transaction": {
|
|
||||||
"header": {
|
|
||||||
"key": {
|
|
||||||
"cmpCode": "1HTM",
|
|
||||||
"code": "OPBR-FIKO"
|
|
||||||
},
|
|
||||||
"timeStamp": 0,
|
|
||||||
"inputDate": "2026-07-20T00:00:00Z",
|
|
||||||
"period": "2026/6",
|
|
||||||
"curCode": "EUR",
|
|
||||||
"date": "2026-07-20T00:00:00Z",
|
|
||||||
"originalCompany": "1HTM",
|
|
||||||
"originalCode": "OPBR-FIKO",
|
|
||||||
"completionWorkflow": {
|
|
||||||
"completionStatus": "wfl_no_completion"
|
|
||||||
},
|
|
||||||
"salesInvoiceStatus": "salesinv_notyetinv"
|
|
||||||
},
|
|
||||||
"lines": {
|
|
||||||
"line": [
|
|
||||||
{
|
|
||||||
"number": 1,
|
|
||||||
"accountCode": "100.99999.D150000001",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"lineType": "summary",
|
|
||||||
"lineSense": "debit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"description": "test",
|
|
||||||
"extRef1": "99999991",
|
|
||||||
"extRef2": "99999",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 2,
|
|
||||||
"accountCode": "642.41236.609311",
|
|
||||||
"docValue": 100.00,
|
|
||||||
"userStatus": "",
|
|
||||||
"lineType": "analysis",
|
|
||||||
"lineSense": "credit",
|
|
||||||
"lineOrigin": "dl_orig_defined",
|
|
||||||
"sepaPaymentCategoryPurposeCode": "none",
|
|
||||||
"sepaPaymentPurposeCode": "none"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
responses:
|
|
||||||
"201":
|
|
||||||
description: Created
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/JournalEntryPostResponseBody"
|
|
||||||
examples:
|
|
||||||
Journalentry created successfully:
|
|
||||||
summary: Journalentry created successfully
|
|
||||||
description: TheJournalentry was successfully added to the database.
|
|
||||||
value:
|
|
||||||
journalEntryId: 6ce10520-9a73-4cb4-b8dd-39ee46ceb617
|
|
||||||
security:
|
|
||||||
- default: []
|
|
||||||
x-auth-type: Application & Application User
|
|
||||||
x-throttling-tier: Unlimited
|
|
||||||
/journalEntries/{journalEntryId}:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: journalEntryId
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 37a8095b-19db-498f-9349-5f37d21c5bdf
|
|
||||||
required: true
|
|
||||||
description: The id of the journalEntry.
|
|
||||||
patch:
|
|
||||||
summary: Update journalEntry.
|
|
||||||
description: Update journalEntry.
|
|
||||||
tags:
|
|
||||||
- journalEntries v1.0
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/JournalEntryPatchRequestBody"
|
|
||||||
examples:
|
|
||||||
Update an journalEntry after error:
|
|
||||||
summary: Update an journalEntry after error
|
|
||||||
description: Update an journalEntry after error by logging the response
|
|
||||||
value:
|
|
||||||
response: {
|
|
||||||
"status": "failed",
|
|
||||||
"message": [
|
|
||||||
{
|
|
||||||
"code": "352",
|
|
||||||
"reason": "Documentregel 1 kan niet geboekt worden."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "159",
|
|
||||||
"reason": "Element 99999 (niveau 2) is niet toegestaan in linkerlijst van element D150000001 (niveau 3)."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"hints": [],
|
|
||||||
"paths": [
|
|
||||||
"/InputRequest/PostToBooks/Request/Transaction/Lines/Line[1]/AccountCode"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Update an journalEntry after success:
|
|
||||||
summary: Update an journalEntry after succesfull call
|
|
||||||
description: Update an journalEntry after uccesfull call bij logging the response and the accountingSystemReference.
|
|
||||||
value:
|
|
||||||
accountingSystemReference: "OPBR-FIKO10000090"
|
|
||||||
response: {
|
|
||||||
"key": {
|
|
||||||
"$type": "finance_transaction_txnKey",
|
|
||||||
"cmpCode": "1HTM",
|
|
||||||
"code": "OPBR-FIKO",
|
|
||||||
"number": " 10000090"
|
|
||||||
},
|
|
||||||
"suppliedNumber": ""
|
|
||||||
}
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/JournalEntryPatchResponseBody"
|
|
||||||
examples:
|
|
||||||
JournalEntry updated successfully:
|
|
||||||
summary: JournalEntry updated successfully
|
|
||||||
description: The journalEntry was successfully updated in the database.
|
|
||||||
value:
|
|
||||||
journalEntryId: 5bbf5abc-4da5-4bb4-894e-a7f553789a20
|
|
||||||
security:
|
|
||||||
- default: []
|
|
||||||
x-auth-type: Application & Application User
|
|
||||||
x-throttling-tier: Unlimited
|
|
||||||
/Odata/BookingProcess:
|
/Odata/BookingProcess:
|
||||||
get:
|
get:
|
||||||
summary: Find booking processes.
|
summary: Find booking processes.
|
||||||
@ -3705,16 +3316,6 @@ components:
|
|||||||
- occurredOn
|
- occurredOn
|
||||||
- type
|
- type
|
||||||
- status
|
- status
|
||||||
createdOn:
|
|
||||||
type: string
|
|
||||||
nullable: false
|
|
||||||
format: datetime
|
|
||||||
example: "2026-07-20T00:00:00Z"
|
|
||||||
updatedOn:
|
|
||||||
type: string
|
|
||||||
nullable: false
|
|
||||||
format: datetime
|
|
||||||
example: "2026-07-25T00:00:00Z"
|
|
||||||
TransactionItemsBulkRequestBody:
|
TransactionItemsBulkRequestBody:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -3950,11 +3551,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
example: Adapt config
|
example: Adapt config
|
||||||
journalEntryId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: true
|
|
||||||
example: b51b377d-6c82-4c4f-9ed3-1068ab6e30c9
|
|
||||||
required:
|
required:
|
||||||
- timestamp
|
- timestamp
|
||||||
- element
|
- element
|
||||||
@ -4021,11 +3617,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
example: Adapt config
|
example: Adapt config
|
||||||
journalEntryId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: true
|
|
||||||
example: b51b377d-6c82-4c4f-9ed3-1068ab6e30c9
|
|
||||||
required:
|
required:
|
||||||
- processingFailureId
|
- processingFailureId
|
||||||
- transactionItemId
|
- transactionItemId
|
||||||
@ -4090,11 +3681,6 @@ components:
|
|||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
example: 37a8095b-19db-498f-9349-5f37d21c5bdf
|
example: 37a8095b-19db-498f-9349-5f37d21c5bdf
|
||||||
journalEntryId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: true
|
|
||||||
example: b51b377d-6c82-4c4f-9ed3-1068ab6e30c9
|
|
||||||
required:
|
required:
|
||||||
- user
|
- user
|
||||||
- timestamp
|
- timestamp
|
||||||
@ -4168,11 +3754,6 @@ components:
|
|||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
example: a3891560-3084-42cb-867c-f289e7cda47d
|
example: a3891560-3084-42cb-867c-f289e7cda47d
|
||||||
journalEntryId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: true
|
|
||||||
example: b51b377d-6c82-4c4f-9ed3-1068ab6e30c9
|
|
||||||
required:
|
required:
|
||||||
- transactionAuditTrailId
|
- transactionAuditTrailId
|
||||||
- transactionItemId
|
- transactionItemId
|
||||||
@ -4180,89 +3761,6 @@ components:
|
|||||||
- timestamp
|
- timestamp
|
||||||
- action
|
- action
|
||||||
- status
|
- status
|
||||||
JournalEntryGetResponseBody:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
"@odata.context":
|
|
||||||
type: string
|
|
||||||
example: $metadata#JournalEntry
|
|
||||||
value:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/components/schemas/JournalEntry"
|
|
||||||
JournalEntry:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
"@odata.etag":
|
|
||||||
type: string
|
|
||||||
example: 333d6b7d-b709-3b89-89e0-bcb3d5fdddfc
|
|
||||||
journalEntryId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 8871d779-512c-4d4d-9a8a-dee7c635179d
|
|
||||||
aggregationReference:
|
|
||||||
type: string
|
|
||||||
example: FIKO-123456
|
|
||||||
accountingSystemReference:
|
|
||||||
type: string
|
|
||||||
nullable: true
|
|
||||||
example: U4F-123456
|
|
||||||
data:
|
|
||||||
type: object
|
|
||||||
example: {}
|
|
||||||
responses:
|
|
||||||
type: object
|
|
||||||
nullable: true
|
|
||||||
example: {}
|
|
||||||
required:
|
|
||||||
- journalEntryId
|
|
||||||
- aggregationReference
|
|
||||||
- data
|
|
||||||
JournalEntryPostRequestBody:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
aggregationReference:
|
|
||||||
type: string
|
|
||||||
example: FIKO-123456
|
|
||||||
accountingSystemReference:
|
|
||||||
type: string
|
|
||||||
nullable: true
|
|
||||||
example: U4F-123456
|
|
||||||
data:
|
|
||||||
type: object
|
|
||||||
example: {}
|
|
||||||
responses:
|
|
||||||
type: object
|
|
||||||
nullable: true
|
|
||||||
example: {}
|
|
||||||
required:
|
|
||||||
- aggregationReference
|
|
||||||
- data
|
|
||||||
JournalEntryPostResponseBody:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
journalEntryId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: c97a8123-8d0e-41ea-9737-35843ebe2385
|
|
||||||
JournalEntryPatchRequestBody:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
accountingSystemReference:
|
|
||||||
type: string
|
|
||||||
nullable: true
|
|
||||||
example: U4F-123456
|
|
||||||
responses:
|
|
||||||
type: object
|
|
||||||
nullable: true
|
|
||||||
example: {}
|
|
||||||
JournalEntryPatchResponseBody:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
journalEntryId:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: c97a8123-8d0e-41ea-9737-35843ebe2385
|
|
||||||
BookingProcessesGetResponseBody:
|
BookingProcessesGetResponseBody:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@ -111,6 +111,14 @@ paths:
|
|||||||
explode: false
|
explode: false
|
||||||
required: false
|
required: false
|
||||||
description: Filter on most recent order status. 1 = concept, 2 = awaitingPayment, 3 = pendingPayment, 4 = paid, 5 = delivered, 6 = cancelled.
|
description: Filter on most recent order status. 1 = concept, 2 = awaitingPayment, 3 = pendingPayment, 4 = paid, 5 = delivered, 6 = cancelled.
|
||||||
|
- in: query
|
||||||
|
name: issuedVoucherId
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
example: "b0a9f3c9-9b92-4f8c-b78d-6129be7218a6"
|
||||||
|
required: false
|
||||||
|
description: Filter on applied issuedVoucherId for the order.
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
@ -769,13 +777,6 @@ paths:
|
|||||||
example: 9e3363c8-e776-4675-b108-99b8c2e38eb6
|
example: 9e3363c8-e776-4675-b108-99b8c2e38eb6
|
||||||
required: false
|
required: false
|
||||||
description: The id of the orderLine
|
description: The id of the orderLine
|
||||||
- in: query
|
|
||||||
name: issuedVoucherId
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: 9e3363c8-e776-4675-b108-99b8c2e38eb6
|
|
||||||
required: false
|
|
||||||
description: The id of the issuedVoucher
|
|
||||||
get:
|
get:
|
||||||
summary: Find vouchers on the order
|
summary: Find vouchers on the order
|
||||||
description: Find vouchers on the order
|
description: Find vouchers on the order
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -313,7 +313,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 24,
|
"productId": 24,
|
||||||
"parentProductId": null,
|
"parentProductId": null,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "30901",
|
"gboPackageTemplateId": "30901",
|
||||||
@ -430,7 +429,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 126,
|
"productId": 126,
|
||||||
"parentProductId": null,
|
"parentProductId": null,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 1,
|
"layerInfoId": 1,
|
||||||
"choiceKey": "isRenewable",
|
"choiceKey": "isRenewable",
|
||||||
@ -539,7 +537,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 119,
|
"productId": 119,
|
||||||
"parentProductId": 126,
|
"parentProductId": 126,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "30001",
|
"gboPackageTemplateId": "30001",
|
||||||
@ -655,7 +652,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 120,
|
"productId": 120,
|
||||||
"parentProductId": 126,
|
"parentProductId": 126,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "30001",
|
"gboPackageTemplateId": "30001",
|
||||||
@ -783,7 +779,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 49,
|
"productId": 49,
|
||||||
"parentProductId": null,
|
"parentProductId": null,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 2,
|
"layerInfoId": 2,
|
||||||
"choiceKey": "regio",
|
"choiceKey": "regio",
|
||||||
@ -931,7 +926,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 109,
|
"productId": 109,
|
||||||
"parentProductId": 49,
|
"parentProductId": 49,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 3,
|
"layerInfoId": 3,
|
||||||
"choiceKey": "allowedGboAgeProfiles",
|
"choiceKey": "allowedGboAgeProfiles",
|
||||||
@ -1082,7 +1076,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 114,
|
"productId": 114,
|
||||||
"parentProductId": 109,
|
"parentProductId": 109,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 1,
|
"layerInfoId": 1,
|
||||||
"choiceKey": "isRenewable",
|
"choiceKey": "isRenewable",
|
||||||
@ -1233,7 +1226,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 115,
|
"productId": 115,
|
||||||
"parentProductId": 109,
|
"parentProductId": 109,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 1,
|
"layerInfoId": 1,
|
||||||
"choiceKey": "isRenewable",
|
"choiceKey": "isRenewable",
|
||||||
@ -1385,7 +1377,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 116,
|
"productId": 116,
|
||||||
"parentProductId": 115,
|
"parentProductId": 115,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "33615",
|
"gboPackageTemplateId": "33615",
|
||||||
@ -1535,7 +1526,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 117,
|
"productId": 117,
|
||||||
"parentProductId": 115,
|
"parentProductId": 115,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "33615",
|
"gboPackageTemplateId": "33615",
|
||||||
@ -1689,7 +1679,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 112,
|
"productId": 112,
|
||||||
"parentProductId": 49,
|
"parentProductId": 49,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 3,
|
"layerInfoId": 3,
|
||||||
"choiceKey": "allowedGboAgeProfiles",
|
"choiceKey": "allowedGboAgeProfiles",
|
||||||
@ -2161,10 +2150,6 @@ components:
|
|||||||
parentProductId:
|
parentProductId:
|
||||||
type: integer
|
type: integer
|
||||||
example: 1
|
example: 1
|
||||||
needsVoucher:
|
|
||||||
type: boolean
|
|
||||||
description: Indicates if the product needs a voucher (with this productId as requiredProductId) to be bought - if false, this is optional, but still allowed
|
|
||||||
example: false
|
|
||||||
layerInfo:
|
layerInfo:
|
||||||
$ref: '#/components/schemas/LayerInfoResponse'
|
$ref: '#/components/schemas/LayerInfoResponse'
|
||||||
fikoArticleNumber:
|
fikoArticleNumber:
|
||||||
|
|||||||
@ -313,7 +313,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 24,
|
"productId": 24,
|
||||||
"parentProductId": null,
|
"parentProductId": null,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "30901",
|
"gboPackageTemplateId": "30901",
|
||||||
@ -430,7 +429,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 126,
|
"productId": 126,
|
||||||
"parentProductId": null,
|
"parentProductId": null,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 1,
|
"layerInfoId": 1,
|
||||||
"choiceKey": "isRenewable",
|
"choiceKey": "isRenewable",
|
||||||
@ -539,7 +537,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 119,
|
"productId": 119,
|
||||||
"parentProductId": 126,
|
"parentProductId": 126,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "30001",
|
"gboPackageTemplateId": "30001",
|
||||||
@ -655,7 +652,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 120,
|
"productId": 120,
|
||||||
"parentProductId": 126,
|
"parentProductId": 126,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "30001",
|
"gboPackageTemplateId": "30001",
|
||||||
@ -783,7 +779,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 49,
|
"productId": 49,
|
||||||
"parentProductId": null,
|
"parentProductId": null,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 2,
|
"layerInfoId": 2,
|
||||||
"choiceKey": "regio",
|
"choiceKey": "regio",
|
||||||
@ -931,7 +926,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 109,
|
"productId": 109,
|
||||||
"parentProductId": 49,
|
"parentProductId": 49,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 3,
|
"layerInfoId": 3,
|
||||||
"choiceKey": "allowedGboAgeProfiles",
|
"choiceKey": "allowedGboAgeProfiles",
|
||||||
@ -1082,7 +1076,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 114,
|
"productId": 114,
|
||||||
"parentProductId": 109,
|
"parentProductId": 109,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 1,
|
"layerInfoId": 1,
|
||||||
"choiceKey": "isRenewable",
|
"choiceKey": "isRenewable",
|
||||||
@ -1233,7 +1226,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 115,
|
"productId": 115,
|
||||||
"parentProductId": 109,
|
"parentProductId": 109,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 1,
|
"layerInfoId": 1,
|
||||||
"choiceKey": "isRenewable",
|
"choiceKey": "isRenewable",
|
||||||
@ -1385,7 +1377,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 116,
|
"productId": 116,
|
||||||
"parentProductId": 115,
|
"parentProductId": 115,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "33615",
|
"gboPackageTemplateId": "33615",
|
||||||
@ -1535,7 +1526,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 117,
|
"productId": 117,
|
||||||
"parentProductId": 115,
|
"parentProductId": 115,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": null,
|
"layerInfo": null,
|
||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"gboPackageTemplateId": "33615",
|
"gboPackageTemplateId": "33615",
|
||||||
@ -1689,7 +1679,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"productId": 112,
|
"productId": 112,
|
||||||
"parentProductId": 49,
|
"parentProductId": 49,
|
||||||
"needsVoucher": false,
|
|
||||||
"layerInfo": {
|
"layerInfo": {
|
||||||
"layerInfoId": 3,
|
"layerInfoId": 3,
|
||||||
"choiceKey": "allowedGboAgeProfiles",
|
"choiceKey": "allowedGboAgeProfiles",
|
||||||
@ -2161,10 +2150,6 @@ components:
|
|||||||
parentProductId:
|
parentProductId:
|
||||||
type: integer
|
type: integer
|
||||||
example: 1
|
example: 1
|
||||||
needsVoucher:
|
|
||||||
type: boolean
|
|
||||||
description: Indicates if the product needs a voucher (with this productId as requiredProductId) to be bought - if false, this is optional, but still allowed
|
|
||||||
example: false
|
|
||||||
layerInfo:
|
layerInfo:
|
||||||
$ref: '#/components/schemas/LayerInfoResponse'
|
$ref: '#/components/schemas/LayerInfoResponse'
|
||||||
fikoArticleNumber:
|
fikoArticleNumber:
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
openapi: 3.0.1
|
openapi: 3.0.1
|
||||||
info:
|
info:
|
||||||
title: Service Engine APIs for HTM voucher for sales Touchpoint
|
title: Service Engine APIs for HTM voucher for sales Touchpint
|
||||||
description: Service Engine APIs for HTM vouchers. These are NOT the CRUD APIs to the data hub. These ARE the APIs for sales touchpoints.
|
description: Service Engine APIs for HTM vouchers. These are NOT the CRUD APIs to the data hub. These ARE the api's for sales touchpoints.
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
servers:
|
servers:
|
||||||
- url: https://services.acc.api.htm.nl/abt/abtvouchersTouchpoint/1.0
|
- url: https://services.acc.api.htm.nl/abt/abtvouchersTouchpoint/1.0
|
||||||
paths:
|
paths:
|
||||||
/issuedvouchers/{voucherCode}:
|
/issuedvouchers/{voucherCode}:
|
||||||
get:
|
get:
|
||||||
summary: Get details of a voucher, that was issued for a specific touchpoint
|
summary: Get details of a voucher, that was issued for a specific touch point
|
||||||
description:
|
description:
|
||||||
Get details of an issued voucher for a specific touchpoint. This means that only products that the calling touchpoint is allowed to see or sell
|
Get details of an issued voucher for a specific touch point. This means that only products that the calling touch point is allowed to see or sell
|
||||||
(i.e. has active sellingPeriods for touchPointId of the calling touchpoint) are returned.
|
(i.e. has active sellingPeriods for touchPointId of the calling touch point) are returned.
|
||||||
parameters:
|
parameters:
|
||||||
- name: voucherCode
|
- name: voucherCode
|
||||||
in: path
|
in: path
|
||||||
@ -28,132 +28,98 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/salesTouchpointIssuedVoucherResponse"
|
$ref: "#/components/schemas/unavailable"
|
||||||
examples:
|
examples:
|
||||||
Voucher that grants a voucher-only product for free:
|
Voucher for a product with required attributes:
|
||||||
summary: Voucher that grants a voucher-only product for free
|
summary: Voucher for a single product with required attributes
|
||||||
description: |-
|
|
||||||
Voucher that grants a product (that can only be acquired via a voucher) for free.
|
|
||||||
In this case, the voucher has an amountInclTax of 0. If the requiredProduct has a
|
|
||||||
non-zero sellingPrice (amountInclTax), the difference between sellingPrice and
|
|
||||||
voucher amountInclTax represents the granted discount. If the requiredProduct has
|
|
||||||
a sellingPrice of 0, no "discount" is shown; just the voucher's amountInclTax.
|
|
||||||
value:
|
value:
|
||||||
{
|
{
|
||||||
"issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
|
"issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
|
||||||
"voucherCode": "HTM-A7J-128-PYT",
|
"voucherCode": "VOUCHER123",
|
||||||
"fromInclusive": "2024-10-04T00:00:00.000",
|
"fromInclusive": "2024-10-04T00:00:00.000",
|
||||||
"untilInclusive": "2024-11-04T00:00:00.000",
|
"untilInclusive": "2024-11-04T00:00:00.000",
|
||||||
"voucherStatus": { "voucherStatusId": 2, "name": "issued" },
|
"voucherStatus": { "voucherStatusId": 1, "name": "New" },
|
||||||
"product":
|
"product":
|
||||||
{
|
{
|
||||||
"productId": 263,
|
"productId": 263,
|
||||||
"productName": "Voucher Ooievaarspas-product AOW",
|
"productName": "HTM-80001",
|
||||||
"productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden voor het product \"Ooievaarspas voor AOW-ers in Den Haag\"",
|
"productDescription": "10 euro korting op Regiovrij maand.",
|
||||||
"amountInclTax": 0,
|
"productCategory":
|
||||||
|
{
|
||||||
|
"productCategoryId": 9,
|
||||||
|
"isTravelProduct": false,
|
||||||
|
"name": "Voucher",
|
||||||
|
},
|
||||||
|
"amountInclTax": -1000,
|
||||||
"requiredProducts":
|
"requiredProducts":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"productId": 982,
|
"productId": 126,
|
||||||
"productName": "Ooievaarspas voor AOW-ers in Den Haag",
|
"productName": "HTM-30001",
|
||||||
"productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.",
|
"productDescription": "Regiovrij maand.",
|
||||||
"productCategory":
|
|
||||||
{
|
|
||||||
"productCategoryId": 2,
|
|
||||||
"isTravelProduct": true,
|
|
||||||
"name": "Afgekocht reisrecht",
|
|
||||||
},
|
|
||||||
"amountInclTax": 0,
|
|
||||||
"_links":
|
"_links":
|
||||||
{
|
{
|
||||||
"get_details":
|
"get_details":
|
||||||
{
|
{
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/982",
|
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/126",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
|
"_links":
|
||||||
|
{
|
||||||
|
"get_details":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"mandatoryCustomerDataItems":
|
"mandatoryCustomerDataItems":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"mandatoryCustomerDataItemId": 8,
|
"mandatoryCustomerDataItemId": 8,
|
||||||
"customerDataItem": "padBirthDate"
|
"customerDataItem": "padBirthDate",
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
"mandatoryCustomerDataItemId": 4,
|
||||||
|
"customerDataItem": "emailAddress",
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
Voucher that grants a hybrid product for a reduced price:
|
Voucher for a whole order:
|
||||||
summary: Voucher that grants a hybrid product for a reduced price
|
summary: Voucher for a whole order
|
||||||
description: |-
|
|
||||||
Voucher that grants a hybrid product (that can be acquired via voucher or via ordinary order flow)
|
|
||||||
for a reduced price. In this case, the voucher has an amountInclTax > 0, which dictates the (modified)
|
|
||||||
total amount that needs to be paid for said product. If the requiredProduct has a
|
|
||||||
non-zero sellingPrice (amountInclTax), the difference between sellingPrice and
|
|
||||||
voucher amountInclTax represents the granted discount. If the requiredProduct has
|
|
||||||
a sellingPrice of 0, no "discount" is shown; just the voucher's amountInclTax./
|
|
||||||
Specifically, in this example, the product "HTM 20% Korting" can be purchased for 1 euro instead of 5 euro.
|
|
||||||
value:
|
value:
|
||||||
{
|
{
|
||||||
"issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
|
"issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
|
||||||
"voucherCode": "HTM-A7J-128-PYT",
|
"voucherCode": "VOUCHER123",
|
||||||
"fromInclusive": "2024-10-04T00:00:00.000",
|
"fromInclusive": "2024-10-04T00:00:00.000",
|
||||||
"untilInclusive": "2024-11-04T00:00:00.000",
|
"untilInclusive": "2024-11-04T00:00:00.000",
|
||||||
"voucherStatus": { "voucherStatusId": 2, "name": "issued" },
|
"voucherStatus": { "voucherStatusId": 1, "name": "New" },
|
||||||
"product":
|
"product":
|
||||||
{
|
{
|
||||||
"productId": 264,
|
"productId": 263,
|
||||||
"productName": "Kortingsvoucher HTM 20% Korting ",
|
"productName": "HTM-80002",
|
||||||
"productDescription": "Voucher waarmee het product \"HTM 20% Korting\" voor een lagere prijs kan worden aangeschaft.",
|
"productDescription": "10 euro korting op je gehele winkelmand.",
|
||||||
"amountInclTax": 100,
|
"productCategory":
|
||||||
"requiredProducts":
|
{
|
||||||
[
|
"productCategoryId": 9,
|
||||||
{
|
"isTravelProduct": false,
|
||||||
"productId": 984,
|
"name": "Voucher",
|
||||||
"productName": "HTM 20% Korting",
|
},
|
||||||
"productDescription": "Reis met 20% korting op je betaalpas bij HTM.",
|
|
||||||
"productCategory":
|
|
||||||
{
|
|
||||||
"productCategoryId": 1,
|
|
||||||
"isTravelProduct": true,
|
|
||||||
"name": "Kortingsabonnement",
|
|
||||||
},
|
|
||||||
"amountInclTax": 500,
|
|
||||||
"_links":
|
|
||||||
{
|
|
||||||
"get_details":
|
|
||||||
{
|
|
||||||
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/984",
|
|
||||||
"method": "GET",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mandatoryCustomerDataItems": []
|
|
||||||
}
|
|
||||||
Voucher that grants a discount for a whole order:
|
|
||||||
summary: Voucher that grants a discount for a whole order
|
|
||||||
description: |-
|
|
||||||
Voucher that grants a discount for a whole order. In this case, no requiredProduct is specified, and
|
|
||||||
the voucher has an amountInclTax < 0. The (negative) amountInclTax dictates the value of the voucher,
|
|
||||||
that is subtracted from the total order value as a discount (with a minimum order total of 0).
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
|
|
||||||
"voucherCode": "HTM-A7J-128-PYT",
|
|
||||||
"fromInclusive": "2024-10-04T00:00:00.000",
|
|
||||||
"untilInclusive": "2024-11-04T00:00:00.000",
|
|
||||||
"voucherStatus": { "voucherStatusId": 2, "name": "issued" },
|
|
||||||
"product":
|
|
||||||
{
|
|
||||||
"productId": 265,
|
|
||||||
"productName": "Voucher 10 euro korting",
|
|
||||||
"productDescription": "Voucher die 10 euro korting geeft op je gehele winkelmand.",
|
|
||||||
"amountInclTax": -1000,
|
"amountInclTax": -1000,
|
||||||
"requiredProducts": []
|
"requiredProducts": [],
|
||||||
|
"_links":
|
||||||
|
{
|
||||||
|
"get_details":
|
||||||
|
{
|
||||||
|
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263",
|
||||||
|
"method": "GET",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"mandatoryCustomerDataItems": []
|
"mandatoryCustomerDataItems": [],
|
||||||
}
|
}
|
||||||
"403":
|
"403":
|
||||||
description: Forbidden
|
description: Forbidden
|
||||||
@ -171,20 +137,20 @@ paths:
|
|||||||
"detail": "You do not have permission to access this resource.",
|
"detail": "You do not have permission to access this resource.",
|
||||||
"instance": "/issuedvouchers",
|
"instance": "/issuedvouchers",
|
||||||
}
|
}
|
||||||
"400":
|
"404":
|
||||||
description: Bad request
|
description: Not found
|
||||||
content:
|
content:
|
||||||
application/problem+json:
|
application/problem+json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/rfc9457"
|
$ref: "#/components/schemas/rfc9457"
|
||||||
examples:
|
examples:
|
||||||
Invalid voucher code:
|
Voucher not found:
|
||||||
summary: Invalid voucher code
|
summary: Voucher not found
|
||||||
value:
|
value:
|
||||||
{
|
{
|
||||||
"type": "https://example.com/probs/bad-request",
|
"type": "https://example.com/probs/not-found",
|
||||||
"title": "Invalid voucher code",
|
"title": "Voucher not found",
|
||||||
"detail": "No valid voucher found for code VOUCHER123.",
|
"detail": "The voucher with code VOUCHER123 does not exist.",
|
||||||
"instance": "/issuedvouchers",
|
"instance": "/issuedvouchers",
|
||||||
}
|
}
|
||||||
"500":
|
"500":
|
||||||
@ -210,166 +176,6 @@ components:
|
|||||||
scheme: bearer
|
scheme: bearer
|
||||||
bearerFormat: JWT
|
bearerFormat: JWT
|
||||||
schemas:
|
schemas:
|
||||||
salesTouchpointIssuedVoucherResponse:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- issuedVoucherId
|
|
||||||
- voucherCode
|
|
||||||
- fromInclusive
|
|
||||||
- untilInclusive
|
|
||||||
- voucherStatus
|
|
||||||
- product
|
|
||||||
- mandatoryCustomerDataItems
|
|
||||||
properties:
|
|
||||||
issuedVoucherId:
|
|
||||||
type: string
|
|
||||||
description: The unique (technical) identifier of the issued voucher instance.
|
|
||||||
example: "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90"
|
|
||||||
voucherCode:
|
|
||||||
type: string
|
|
||||||
description: The voucher code that is shared with the customer and uniquely identifies this voucher.
|
|
||||||
example: "HTM-A7J-128-PYT"
|
|
||||||
fromInclusive:
|
|
||||||
type: string
|
|
||||||
format: date-time-offset
|
|
||||||
description: |-
|
|
||||||
The date and time the voucher becomes valid for redemption. This has nothing to do with
|
|
||||||
the allowed start date of a requiredProduct (for this, the existing order flow logic is applied).
|
|
||||||
example: "2024-10-04T00:00:00.000+02:00"
|
|
||||||
untilInclusive:
|
|
||||||
type: string
|
|
||||||
format: date-time-offset
|
|
||||||
description: |-
|
|
||||||
The date and time the voucher becomes invalid for redemption. This has nothing to do with
|
|
||||||
the maximum allowed start date of a requiredProduct (for this, the existing order flow logic is applied).
|
|
||||||
example: "2024-11-04T00:00:00.000+01:00"
|
|
||||||
voucherStatus:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- voucherStatusId
|
|
||||||
- name
|
|
||||||
description: |-
|
|
||||||
The current status of the voucher. Can be any of the following:
|
|
||||||
- 1 = new
|
|
||||||
- 2 = issued
|
|
||||||
- 3 = redeemed
|
|
||||||
- 4 = revoked
|
|
||||||
- 5 = expired
|
|
||||||
- 6 = pendingRedemption
|
|
||||||
properties:
|
|
||||||
voucherStatusId:
|
|
||||||
type: integer
|
|
||||||
example: 2
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
example: "issued"
|
|
||||||
product:
|
|
||||||
type: object
|
|
||||||
description: The "product" referencing the voucher definition that this voucher instance is based on
|
|
||||||
required:
|
|
||||||
- productId
|
|
||||||
- productName
|
|
||||||
- productDescription
|
|
||||||
- amountInclTax
|
|
||||||
properties:
|
|
||||||
productId:
|
|
||||||
type: integer
|
|
||||||
example: 263
|
|
||||||
productName:
|
|
||||||
type: string
|
|
||||||
example: Voucher Ooievaarspas-product AOW
|
|
||||||
productDescription:
|
|
||||||
type: string
|
|
||||||
example: |-
|
|
||||||
Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden
|
|
||||||
voor het product "Ooievaarspas voor AOW-ers in Den Haag".
|
|
||||||
amountInclTax:
|
|
||||||
type: integer
|
|
||||||
description: |-
|
|
||||||
When combined with a requiredProduct, the (positive or zero) amountInclTax dictates
|
|
||||||
the (modified) total amount that needs to be paid for said product. When the requiredProduct
|
|
||||||
has a sellingPrice > 0, the difference between sellingPrice and voucher amountInclTax
|
|
||||||
represents the granted discount.
|
|
||||||
When not combined with a required product, the (negative) amountInclTax dictates
|
|
||||||
the value of the voucher, that is subtracted from the total order value as a discount
|
|
||||||
(with a minimum order total of 0).
|
|
||||||
example: 0
|
|
||||||
requiredProducts:
|
|
||||||
type: array
|
|
||||||
description: |-
|
|
||||||
Currently, only one requiredProduct is supported and thus, this array can contain at
|
|
||||||
most one element.
|
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- productId
|
|
||||||
properties:
|
|
||||||
productId:
|
|
||||||
type: integer
|
|
||||||
example: 892
|
|
||||||
productName:
|
|
||||||
type: string
|
|
||||||
example: "Ooievaarspas voor AOW-ers in Den Haag"
|
|
||||||
productDescription:
|
|
||||||
type: string
|
|
||||||
example: "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas."
|
|
||||||
productCategory:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- productCategoryId
|
|
||||||
- isTravelProduct
|
|
||||||
- name
|
|
||||||
properties:
|
|
||||||
productCategoryId:
|
|
||||||
type: integer
|
|
||||||
example: 2
|
|
||||||
isTravelProduct:
|
|
||||||
type: boolean
|
|
||||||
example: true
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
example: "Afgekocht reisrecht"
|
|
||||||
amountInclTax:
|
|
||||||
type: integer
|
|
||||||
description: |-
|
|
||||||
Selling price of the product in cents (including tax, if applicable) that is
|
|
||||||
currently active for the calling touchpoint. When 0, the product is free of charge.
|
|
||||||
example: 0
|
|
||||||
imageReference:
|
|
||||||
type: string
|
|
||||||
description: Can be a URL or a base64 encoded image
|
|
||||||
example: https://www.htm.nl/nog-onbekende-productafbeelding
|
|
||||||
_links:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
get_details:
|
|
||||||
type: object
|
|
||||||
description: Link to get more details for the product that this voucher instance applies to
|
|
||||||
properties:
|
|
||||||
href:
|
|
||||||
type: string
|
|
||||||
example: https://api.integratielaag.nl/abt/touchpoint/1.0/products/982
|
|
||||||
method:
|
|
||||||
type: string
|
|
||||||
example: GET
|
|
||||||
mandatoryCustomerDataItems:
|
|
||||||
type: array
|
|
||||||
description: |-
|
|
||||||
List of mandatory customer data items that are required to redeem this voucher.\
|
|
||||||
The values provided for these data items may be checked against allowed values as provided by the voucher issuer.
|
|
||||||
items:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- mandatoryCustomerDataItemId
|
|
||||||
- customerDataItem
|
|
||||||
properties:
|
|
||||||
mandatoryCustomerDataItemId:
|
|
||||||
type: integer
|
|
||||||
example: 8
|
|
||||||
customerDataItem:
|
|
||||||
type: string
|
|
||||||
example: padBirthdate
|
|
||||||
|
|
||||||
unavailable:
|
unavailable:
|
||||||
type: object
|
type: object
|
||||||
rfc9457:
|
rfc9457:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1553,9 +1553,6 @@ components:
|
|||||||
- productCategoryId: 8
|
- productCategoryId: 8
|
||||||
name: Saldo
|
name: Saldo
|
||||||
isTravelProduct: true
|
isTravelProduct: true
|
||||||
- productCategoryId: 9
|
|
||||||
name: Voucher
|
|
||||||
isTravelProduct: false
|
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/productCategoryGetEntity'
|
$ref: '#/components/schemas/productCategoryGetEntity'
|
||||||
@ -1814,7 +1811,7 @@ components:
|
|||||||
- mandatoryCustomerDataItemId: 5
|
- mandatoryCustomerDataItemId: 5
|
||||||
customerDataItem: address
|
customerDataItem: address
|
||||||
- mandatoryCustomerDataItemId: 6
|
- mandatoryCustomerDataItemId: 6
|
||||||
customerDataItem: voucher
|
customerDataItem: phone
|
||||||
- mandatoryCustomerDataItemId: 7
|
- mandatoryCustomerDataItemId: 7
|
||||||
customerDataItem: ovPayToken
|
customerDataItem: ovPayToken
|
||||||
- mandatoryCustomerDataItemId: 8
|
- mandatoryCustomerDataItemId: 8
|
||||||
|
|||||||
@ -46,13 +46,6 @@ paths:
|
|||||||
when false, return only non-archived products (isArchived = false).
|
when false, return only non-archived products (isArchived = false).
|
||||||
schema:
|
schema:
|
||||||
type: boolean
|
type: boolean
|
||||||
- name: onlyVouchers
|
|
||||||
in: query
|
|
||||||
required: false
|
|
||||||
description: |-
|
|
||||||
When omitted, defaults to false (i.e. return all normal products that are NOT voucher definitions); when true, return only voucher definitions
|
|
||||||
schema:
|
|
||||||
type: boolean
|
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: OK
|
description: OK
|
||||||
@ -394,7 +387,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": "30901",
|
"gboPackageTemplateId": "30901",
|
||||||
"productName": "HTM pilot 90% korting",
|
"productName": "HTM pilot 90% korting",
|
||||||
"productDescription": "Reis met 90% korting gedurende de eerste F&F pilot!",
|
"productDescription": "Reis met 90% korting gedurende de eerste F&F pilot!",
|
||||||
@ -482,7 +474,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": "30901",
|
"gboPackageTemplateId": "30901",
|
||||||
"productName": "HTM pilot 90% korting",
|
"productName": "HTM pilot 90% korting",
|
||||||
"productDescription": "Reis met 90% korting gedurende de eerste F&F pilot!",
|
"productDescription": "Reis met 90% korting gedurende de eerste F&F pilot!",
|
||||||
@ -569,7 +560,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": "30901",
|
"gboPackageTemplateId": "30901",
|
||||||
"productName": "HTM pilot 90% korting",
|
"productName": "HTM pilot 90% korting",
|
||||||
"productDescription": "Reis met 90% korting gedurende de eerste F&F pilot!",
|
"productDescription": "Reis met 90% korting gedurende de eerste F&F pilot!",
|
||||||
@ -690,7 +680,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": "33610",
|
"gboPackageTemplateId": "33610",
|
||||||
"productName": "HTM Regio Vrij DH73",
|
"productName": "HTM Regio Vrij DH73",
|
||||||
"productDescription": "Voor een vast bedrag onbeperkt reizen met EBS, HTM en RET in het gekozen gebied in de regio Rotterdam Den Haag.",
|
"productDescription": "Voor een vast bedrag onbeperkt reizen met EBS, HTM en RET in het gekozen gebied in de regio Rotterdam Den Haag.",
|
||||||
@ -877,7 +866,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": "30901",
|
"gboPackageTemplateId": "30901",
|
||||||
"tapConnectProductCode": null,
|
"tapConnectProductCode": null,
|
||||||
"productName": "HTM pilot 90% korting",
|
"productName": "HTM pilot 90% korting",
|
||||||
@ -1040,7 +1028,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": "30901",
|
"gboPackageTemplateId": "30901",
|
||||||
"tapConnectProductCode": null,
|
"tapConnectProductCode": null,
|
||||||
"productName": "HTM pilot 90% korting",
|
"productName": "HTM pilot 90% korting",
|
||||||
@ -1283,7 +1270,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": "33610",
|
"gboPackageTemplateId": "33610",
|
||||||
"tapConnectProductCode": null,
|
"tapConnectProductCode": null,
|
||||||
"productName": "HTM Regio Vrij DH73",
|
"productName": "HTM Regio Vrij DH73",
|
||||||
@ -1489,7 +1475,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": null,
|
"gboPackageTemplateId": null,
|
||||||
"tapConnectProductCode": null,
|
"tapConnectProductCode": null,
|
||||||
"productName": "IBAN wijzigen functioneel product",
|
"productName": "IBAN wijzigen functioneel product",
|
||||||
@ -1687,7 +1672,6 @@ paths:
|
|||||||
"fikoArticleNumber": "1234",
|
"fikoArticleNumber": "1234",
|
||||||
"isValid": true,
|
"isValid": true,
|
||||||
"isArchived": false,
|
"isArchived": false,
|
||||||
"needsVoucher": false,
|
|
||||||
"gboPackageTemplateId": null,
|
"gboPackageTemplateId": null,
|
||||||
"tapConnectProductCode": null,
|
"tapConnectProductCode": null,
|
||||||
"productName": "OV-pas saldo (1 eurocent)",
|
"productName": "OV-pas saldo (1 eurocent)",
|
||||||
@ -2791,10 +2775,6 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: Indicates if the product is archived - if true, the Service Engine will prevent touchpoints from seeing this product
|
description: Indicates if the product is archived - if true, the Service Engine will prevent touchpoints from seeing this product
|
||||||
example: false
|
example: false
|
||||||
needsVoucher:
|
|
||||||
type: boolean
|
|
||||||
description: Indicates if the product needs a voucher (with this productId as requiredProductId) to be bought - if false, this is optional, but still allowed
|
|
||||||
example: false
|
|
||||||
gboPackageTemplateId:
|
gboPackageTemplateId:
|
||||||
type: string
|
type: string
|
||||||
example: '30901'
|
example: '30901'
|
||||||
@ -3152,10 +3132,6 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: Indicates if the product is archived - if true, the Service Engine will prevent touchpoints from seeing this product
|
description: Indicates if the product is archived - if true, the Service Engine will prevent touchpoints from seeing this product
|
||||||
example: false
|
example: false
|
||||||
needsVoucher:
|
|
||||||
type: boolean
|
|
||||||
description: Indicates if the product needs a voucher (with this productId as requiredProductId) to be bought - if false, this is optional, but still allowed
|
|
||||||
example: false
|
|
||||||
gboPackageTemplateId:
|
gboPackageTemplateId:
|
||||||
type: string
|
type: string
|
||||||
description: >-
|
description: >-
|
||||||
@ -3527,10 +3503,6 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: Indicates if the product is archived - if true, the Service Engine will prevent touchpoints from seeing this product
|
description: Indicates if the product is archived - if true, the Service Engine will prevent touchpoints from seeing this product
|
||||||
example: false
|
example: false
|
||||||
needsVoucher:
|
|
||||||
type: boolean
|
|
||||||
description: Indicates if the product needs a voucher (with this productId as requiredProductId) to be bought - if false, this is optional, but still allowed
|
|
||||||
example: false
|
|
||||||
gboPackageTemplateId:
|
gboPackageTemplateId:
|
||||||
type: string
|
type: string
|
||||||
description: >-
|
description: >-
|
||||||
|
|||||||
@ -209,12 +209,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"issuedVoucherId": "e1f2g3h4-i5j6-k7l8-m9n0-o1p2q3r4s5t6",
|
"issuedVoucherId": "e1f2g3h4-i5j6-k7l8-m9n0-o1p2q3r4s5t6",
|
||||||
"voucherCode": "VOUCHER12345",
|
"voucherCode": "VOUCHER12345",
|
||||||
"touchPointId": 23,
|
|
||||||
"metadata1": null,
|
|
||||||
"metadata2": null,
|
|
||||||
"metadata3": null,
|
|
||||||
"metadata4": null,
|
|
||||||
"metadata5": null,
|
|
||||||
"voucherStatusInstances":
|
"voucherStatusInstances":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -225,7 +219,6 @@ paths:
|
|||||||
"name": "New",
|
"name": "New",
|
||||||
},
|
},
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
"createdOn": "2024-10-04T12:34:56.000",
|
||||||
"reason": null,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"voucherStatusInstanceId": "b01412e6-70fb-4c05-9bef-e65bf2747ca1",
|
"voucherStatusInstanceId": "b01412e6-70fb-4c05-9bef-e65bf2747ca1",
|
||||||
@ -235,7 +228,6 @@ paths:
|
|||||||
"name": "Issued",
|
"name": "Issued",
|
||||||
},
|
},
|
||||||
"createdOn": "2024-10-04T12:37:14.000",
|
"createdOn": "2024-10-04T12:37:14.000",
|
||||||
"reason": "test reason"
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"voucherClaims":
|
"voucherClaims":
|
||||||
@ -256,155 +248,6 @@ paths:
|
|||||||
],
|
],
|
||||||
"href": null,
|
"href": null,
|
||||||
}
|
}
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- Purchased Product
|
|
||||||
summary: Create a new purchased product.
|
|
||||||
description: Create a new purchased product. Only one single instance of `purchasedGboProducts`, `purchasedTapconnectTickets` or `issuedVouchers` can be specified at once.
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/unavailable"
|
|
||||||
examples:
|
|
||||||
Create Purchased GBO Product:
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"productId": 11,
|
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
|
||||||
"lastUpdatedOn": "2024-10-04T12:34:56.000",
|
|
||||||
"purchasedProductResources":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"resourceNameId": 1,
|
|
||||||
"resourceIdentifier": "408eefa9-b393-4bb3-8439-b2e51833abc7",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"resourceNameId": 2,
|
|
||||||
"resourceIdentifier": "f809a6e1-1c8d-4f8e-8a6e-0d0b1e1e1e1e",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"purchasedGboProducts":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"salesTimestamp": "2024-10-04T12:34:56.000",
|
|
||||||
"refundTimestamp": "2024-10-04T12:34:56.000",
|
|
||||||
"fromInclusive": "2024-10-04T12:34:56.000",
|
|
||||||
"untilInclusive": "2024-10-04T12:34:56.000",
|
|
||||||
"packageTemplateId": "30003",
|
|
||||||
"xBot": "f15efe6f-7353-4968-b134-60ba6fc2da8b",
|
|
||||||
"xTat": "42efebf7-132e-4ee0-9cbb-4037a9a54ad8",
|
|
||||||
"xSpit": "d67b2f72-918a-4e6c-957d-a39ed9c9e16b",
|
|
||||||
"customerTokenId": "b6492322-c458-4857-9ac3-a109c1887b9f",
|
|
||||||
"ovPayTokenId": 13,
|
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
|
||||||
"lastUpdatedOn": "2024-10-04T12:34:56.000",
|
|
||||||
"createdBy": "someuser",
|
|
||||||
"lastUpdatedBy": null
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"purchasedTapconnectTickets": [],
|
|
||||||
"issuedVouchers": [],
|
|
||||||
}
|
|
||||||
Create Purchased TapConnect Ticket:
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"productId": 11,
|
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
|
||||||
"lastUpdatedOn": "2024-10-04T12:34:56.000",
|
|
||||||
"purchasedProductResources":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"resourceNameId": 1,
|
|
||||||
"resourceIdentifier": "408eefa9-b393-4bb3-8439-b2e51833abc7",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"resourceNameId": 2,
|
|
||||||
"resourceIdentifier": "f809a6e1-1c8d-4f8e-8a6e-0d0b1e1e1e1e",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"purchasedGboProducts": [],
|
|
||||||
"purchasedTapconnectTickets":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"issuedAt": "2024-10-04T12:34:56.000",
|
|
||||||
"activatedAt": "2024-10-04T12:34:56.000",
|
|
||||||
"cancelledAt": "2024-10-04T12:34:56.000",
|
|
||||||
"ticketReference": "KJj43nejhbTxhr897287",
|
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
|
||||||
"lastUpdatedOn": "2024-10-04T12:34:56.000",
|
|
||||||
"createdBy": "John Doe",
|
|
||||||
"lastUpdatedBy": "John Doe",
|
|
||||||
"externalDeviceId": "c5545584-04af-4c60-a955-d6a70baab848",
|
|
||||||
"serviceId": "HTM-1234-7654-8945",
|
|
||||||
"activateBefore": "2024-10-08",
|
|
||||||
"validityStart": "2024-10-05T12:34:56.000",
|
|
||||||
"validityEnd": "2024-10-06T12:34:56.000"
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"issuedVouchers": [],
|
|
||||||
}
|
|
||||||
Create Issued Voucher:
|
|
||||||
value:
|
|
||||||
{
|
|
||||||
"productId": 11,
|
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
|
||||||
"lastUpdatedOn": "2024-10-04T12:34:56.000",
|
|
||||||
"purchasedProductResources":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"resourceNameId": 1,
|
|
||||||
"resourceIdentifier": "408eefa9-b393-4bb3-8439-b2e51833abc7",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"resourceNameId": 2,
|
|
||||||
"resourceIdentifier": "f809a6e1-1c8d-4f8e-8a6e-0d0b1e1e1e1e",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"purchasedGboProducts": [],
|
|
||||||
"purchasedTapconnectTickets": [],
|
|
||||||
"issuedVouchers":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"voucherCode": "VOUCHER123",
|
|
||||||
"touchPointId": 23,
|
|
||||||
"metadata1": null,
|
|
||||||
"metadata2": null,
|
|
||||||
"metadata3": null,
|
|
||||||
"metadata4": null,
|
|
||||||
"metadata5": null,
|
|
||||||
"voucherStatusInstances": [
|
|
||||||
{
|
|
||||||
"voucherStatusId": 1,
|
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
|
||||||
"reason": "test reason"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"voucherClaims": [
|
|
||||||
{
|
|
||||||
"mandatoryCustomerDataItemId": 8,
|
|
||||||
"value": "1999-12-31"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mandatoryCustomerDataItemId": 4,
|
|
||||||
"value": "john.doe@example.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"fromInclusive": "2024-10-04T12:34:56.000",
|
|
||||||
"untilInclusive": "2025-10-04T12:34:56.000"
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
responses:
|
|
||||||
"201":
|
|
||||||
description: Created
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/unavailable"
|
|
||||||
example:
|
|
||||||
{ "purchasedProductId": "a9b3dea5-fb8a-4b1e-9fe6-90cad31c0cfd" }
|
|
||||||
/purchasedproducts/{purchasedProductId}:
|
/purchasedproducts/{purchasedProductId}:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
@ -539,12 +382,6 @@ paths:
|
|||||||
{
|
{
|
||||||
"issuedVoucherId": "e1f2g3h4-i5j6-k7l8-m9n0-o1p2q3r4s5t6",
|
"issuedVoucherId": "e1f2g3h4-i5j6-k7l8-m9n0-o1p2q3r4s5t6",
|
||||||
"voucherCode": "VOUCHER12345",
|
"voucherCode": "VOUCHER12345",
|
||||||
"touchPointId": 23,
|
|
||||||
"metadata1": null,
|
|
||||||
"metadata2": null,
|
|
||||||
"metadata3": null,
|
|
||||||
"metadata4": null,
|
|
||||||
"metadata5": null,
|
|
||||||
"voucherStatusInstances":
|
"voucherStatusInstances":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -552,14 +389,12 @@ paths:
|
|||||||
"voucherStatus":
|
"voucherStatus":
|
||||||
{ "voucherStatusId": 1, "name": "New" },
|
{ "voucherStatusId": 1, "name": "New" },
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
"createdOn": "2024-10-04T12:34:56.000",
|
||||||
"reason": null,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"voucherStatusInstanceId": "b01412e6-70fb-4c05-9bef-e65bf2747ca1",
|
"voucherStatusInstanceId": "b01412e6-70fb-4c05-9bef-e65bf2747ca1",
|
||||||
"voucherStatus":
|
"voucherStatus":
|
||||||
{ "voucherStatusId": 2, "name": "Issued" },
|
{ "voucherStatusId": 2, "name": "Issued" },
|
||||||
"createdOn": "2024-10-04T12:37:14.000",
|
"createdOn": "2024-10-04T12:37:14.000",
|
||||||
"reason": "test reason"
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"voucherClaims":
|
"voucherClaims":
|
||||||
@ -1219,18 +1054,11 @@ paths:
|
|||||||
example:
|
example:
|
||||||
{
|
{
|
||||||
"voucherCode": "VOUCHER123",
|
"voucherCode": "VOUCHER123",
|
||||||
"touchPointId": 23,
|
|
||||||
"metadata1": null,
|
|
||||||
"metadata2": null,
|
|
||||||
"metadata3": null,
|
|
||||||
"metadata4": null,
|
|
||||||
"metadata5": null,
|
|
||||||
"voucherStatusInstances":
|
"voucherStatusInstances":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"voucherStatusId": 1,
|
"voucherStatusId": 1,
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
"createdOn": "2024-10-04T12:34:56.000",
|
||||||
"reason": "test reason"
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"voucherClaims":
|
"voucherClaims":
|
||||||
@ -1238,7 +1066,7 @@ paths:
|
|||||||
{ "mandatoryCustomerDataItemId": 8, "value": "1999-12-31" },
|
{ "mandatoryCustomerDataItemId": 8, "value": "1999-12-31" },
|
||||||
{
|
{
|
||||||
"mandatoryCustomerDataItemId": 4,
|
"mandatoryCustomerDataItemId": 4,
|
||||||
"value": "john.doe@example.com",
|
"value": "vlad.harkonnen@househarkonnen.net",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"fromInclusive": "2024-10-04T12:34:56.000",
|
"fromInclusive": "2024-10-04T12:34:56.000",
|
||||||
@ -1274,20 +1102,6 @@ paths:
|
|||||||
format: uuid
|
format: uuid
|
||||||
example: 058a1af7-897f-45d5-b691-9cc9161e387f
|
example: 058a1af7-897f-45d5-b691-9cc9161e387f
|
||||||
description: The id of the purchased product.
|
description: The id of the purchased product.
|
||||||
- in: query
|
|
||||||
name: statusChangedAfter
|
|
||||||
required: false
|
|
||||||
description: Return only issued vouchers that have had their status changed after the given date and time.
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: date-time-offset
|
|
||||||
example: "2024-10-04T00:00:00.000Z"
|
|
||||||
- in: query
|
|
||||||
name: productId
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 1
|
|
||||||
description: The id of the product and the issuedVouchers related to it
|
|
||||||
- in: query
|
- in: query
|
||||||
name: voucherCode
|
name: voucherCode
|
||||||
schema:
|
schema:
|
||||||
@ -1303,14 +1117,6 @@ paths:
|
|||||||
explode: false
|
explode: false
|
||||||
required: false
|
required: false
|
||||||
description: The moest recent status id of the voucher.
|
description: The moest recent status id of the voucher.
|
||||||
- in: query
|
|
||||||
name: orderBy
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
enum: [PurchasedProductCreatedOn, PurchasedProductLastUpdatedOn]
|
|
||||||
explode: false
|
|
||||||
required: false
|
|
||||||
description: The ordering of the issuedVouchers in the list
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
@ -1326,13 +1132,6 @@ paths:
|
|||||||
"issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
|
"issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
|
||||||
"purchasedProductId": "058a1af7-897f-45d5-b691-9cc9161e387f",
|
"purchasedProductId": "058a1af7-897f-45d5-b691-9cc9161e387f",
|
||||||
"voucherCode": "VOUCHER123",
|
"voucherCode": "VOUCHER123",
|
||||||
"productId": 888,
|
|
||||||
"touchPointId": 23,
|
|
||||||
"metadata1": null,
|
|
||||||
"metadata2": null,
|
|
||||||
"metadata3": null,
|
|
||||||
"metadata4": null,
|
|
||||||
"metadata5": null,
|
|
||||||
"voucherStatusInstances":
|
"voucherStatusInstances":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -1340,14 +1139,12 @@ paths:
|
|||||||
"voucherStatus":
|
"voucherStatus":
|
||||||
{ "voucherStatusId": 1, "name": "New" },
|
{ "voucherStatusId": 1, "name": "New" },
|
||||||
"createdOn": "2024-10-04T12:34:56.000",
|
"createdOn": "2024-10-04T12:34:56.000",
|
||||||
"reason": null,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"voucherStatusInstanceId": "b01412e6-70fb-4c05-9bef-e65bf2747ca1",
|
"voucherStatusInstanceId": "b01412e6-70fb-4c05-9bef-e65bf2747ca1",
|
||||||
"voucherStatus":
|
"voucherStatus":
|
||||||
{ "voucherStatusId": 2, "name": "Issued" },
|
{ "voucherStatusId": 2, "name": "Issued" },
|
||||||
"createdOn": "2024-10-04T12:37:14.000",
|
"createdOn": "2024-10-04T12:37:14.000",
|
||||||
"reason": "test reason",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"voucherClaims":
|
"voucherClaims":
|
||||||
@ -1366,7 +1163,7 @@ paths:
|
|||||||
"mandatoryCustomerDataItemId": 4,
|
"mandatoryCustomerDataItemId": 4,
|
||||||
"customerDataItem": "emailAddress",
|
"customerDataItem": "emailAddress",
|
||||||
},
|
},
|
||||||
"value": "john.doe@example.com",
|
"value": "vlad.harkonnen@househarkonnen.net",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"fromInclusive": "2024-10-04T12:34:56.000",
|
"fromInclusive": "2024-10-04T12:34:56.000",
|
||||||
@ -1394,16 +1191,9 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/PostIssuedVoucherStatusInstanceRequest"
|
$ref: "#/components/schemas/unavailable"
|
||||||
examples:
|
example:
|
||||||
newToIssued:
|
{ "voucherStatusId": 2, "createdOn": "2024-10-04T12:34:56.000" }
|
||||||
summary: Mark a voucher as issued
|
|
||||||
value:
|
|
||||||
{ "voucherStatusId": 2, "createdOn": "2024-10-04T12:34:56.000" }
|
|
||||||
issuedToRevokedWithReason:
|
|
||||||
summary: Mark a voucher as revoked with reason
|
|
||||||
value:
|
|
||||||
{ "voucherStatusId": 4, "createdOn": "2024-10-04T12:34:56.000", "reason": "Voucher revoked because it was redeemed by an unauthorized user." }
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
@ -1437,7 +1227,6 @@ paths:
|
|||||||
{ "voucherStatusId": 3, "name": "Redeemed" },
|
{ "voucherStatusId": 3, "name": "Redeemed" },
|
||||||
{ "voucherStatusId": 4, "name": "Revoked" },
|
{ "voucherStatusId": 4, "name": "Revoked" },
|
||||||
{ "voucherStatusId": 5, "name": "Expired" },
|
{ "voucherStatusId": 5, "name": "Expired" },
|
||||||
{ "voucherStatusId": 6, "name": "PendingRedemption" },
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
components:
|
components:
|
||||||
@ -1449,22 +1238,6 @@ components:
|
|||||||
schemas:
|
schemas:
|
||||||
unavailable:
|
unavailable:
|
||||||
type: object
|
type: object
|
||||||
PostIssuedVoucherStatusInstanceRequest:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- voucherStatusId
|
|
||||||
- createdOn
|
|
||||||
properties:
|
|
||||||
voucherStatusId:
|
|
||||||
type: integer
|
|
||||||
example: 4
|
|
||||||
createdOn:
|
|
||||||
type: string
|
|
||||||
format: date-time
|
|
||||||
example: 2024-10-04T12:34:56.000
|
|
||||||
reason:
|
|
||||||
type: string
|
|
||||||
example: "Voucher revoked because it was redeemed by an unauthorized user."
|
|
||||||
PostPurchasedTapConnectTicketRequest:
|
PostPurchasedTapConnectTicketRequest:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
@ -1526,6 +1299,56 @@ components:
|
|||||||
format: date-time
|
format: date-time
|
||||||
description: The date-time at which the ticket will become invalid for traveling. The ticket will not be valid after this date/time.
|
description: The date-time at which the ticket will become invalid for traveling. The ticket will not be valid after this date/time.
|
||||||
example: 2024-10-06T12:34:56.000
|
example: 2024-10-06T12:34:56.000
|
||||||
|
BulkResponseBody:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
startTime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
example: 2025-02-14T05:32:47.0672237Z
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: Running
|
||||||
|
clientTrackingId:
|
||||||
|
type: string
|
||||||
|
example: 08584620957189579629541919368CU00
|
||||||
|
callbackurl:
|
||||||
|
type: string
|
||||||
|
format: uri
|
||||||
|
example: https://services.api.htm.nl/purchasedproducts/responsestatus/runtime/webhooks/workflow/scaleUnits/prod-00/workflows/6fd466916c
|
||||||
|
retryAfter:
|
||||||
|
type: integer
|
||||||
|
example: 10
|
||||||
|
summary:
|
||||||
|
$ref: "#/components/schemas/summaryBody"
|
||||||
|
required:
|
||||||
|
- startTime
|
||||||
|
- status
|
||||||
|
- clientTrackingId
|
||||||
|
- callbackurl
|
||||||
|
- retryAfter
|
||||||
|
- summary
|
||||||
|
summaryBody:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
summary:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
created:
|
||||||
|
type: integer
|
||||||
|
example: 15
|
||||||
|
updated:
|
||||||
|
type: integer
|
||||||
|
example: 2
|
||||||
|
total:
|
||||||
|
type: integer
|
||||||
|
example: 17
|
||||||
|
required:
|
||||||
|
- created
|
||||||
|
- total
|
||||||
|
- updated
|
||||||
|
required:
|
||||||
|
- summary
|
||||||
rfc9457:
|
rfc9457:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@ -0,0 +1,121 @@
|
|||||||
|
# Notification preferences transformation service - Python example
|
||||||
|
|
||||||
|
Reference implementation for the Service Engine `GET /customers/notificationpreferences` endpoint. It composes raw CRUD API data into the frontend-friendly response model from `SE-notifications.yaml`.
|
||||||
|
|
||||||
|
## Supplied contracts used
|
||||||
|
|
||||||
|
- `notifications-crud.yaml`
|
||||||
|
- `GET /notificationsubscriptions?customerProfileId={id}&expand=eventTypeChannel`
|
||||||
|
- `GET /notificationcategories?notificationCategoryId={id}&expand=eventTypeChannel`
|
||||||
|
- `customers-crud-v2.yaml`
|
||||||
|
- `GET /ovpaytokens?ovPayTokenId={id}`
|
||||||
|
- `GET /devices?customerProfileId={id}`
|
||||||
|
- `GET /customers?customerProfileId={id}` for person/email resource data
|
||||||
|
- `SE-notifications.yaml`
|
||||||
|
- `GET /customers/notificationpreferences`
|
||||||
|
|
||||||
|
## Runtime options
|
||||||
|
|
||||||
|
### Local FastAPI with real CRUD APIs
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
|
||||||
|
$env:NOTIFICATIONS_CRUD_BASE_URL="https://your-notifications-crud-api.example.nl"
|
||||||
|
$env:CUSTOMERS_CRUD_BASE_URL="https://your-customers-crud-api.example.nl"
|
||||||
|
.\.venv\Scripts\python.exe -m uvicorn app.entrypoints.fastapi_app:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Call:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-RestMethod `
|
||||||
|
-Uri "http://127.0.0.1:8000/customers/notificationpreferences?deviceId=device-1" `
|
||||||
|
-Headers @{"X-HTM-CUSTOMER-PROFILE-ID-HEADER"="42"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Local FastAPI with mock data
|
||||||
|
|
||||||
|
Use mock mode when you want to demo or test the transformation without live CRUD APIs.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:USE_MOCK_DATA="true"
|
||||||
|
$env:MOCK_SCENARIO="mixed"
|
||||||
|
.\.venv\Scripts\python.exe -m uvicorn app.entrypoints.fastapi_app:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Open:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://127.0.0.1:8000/docs
|
||||||
|
```
|
||||||
|
|
||||||
|
Health check:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://127.0.0.1:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
Available mock scenarios:
|
||||||
|
|
||||||
|
| Scenario | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `mixed` | Default-on push, default-off email, plus customer deviations |
|
||||||
|
| `defaults_only` | No customer preferences, so only defaults are applied |
|
||||||
|
| `global_override` | Preference with `resourceIdentifier = null` applies to all resources |
|
||||||
|
| `inactive_subscription` | Subscription is returned but marked inactive |
|
||||||
|
|
||||||
|
### Azure Function
|
||||||
|
|
||||||
|
Use `app/entrypoints/azure_function.py` as the HTTP-trigger body. Keep the `app/services` and `app/domain` modules unchanged.
|
||||||
|
|
||||||
|
## Running automated tests
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\.venv\Scripts\python.exe -m pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
The tests cover:
|
||||||
|
|
||||||
|
- default-on channel without preference -> active
|
||||||
|
- default-on channel with preference -> inactive deviation
|
||||||
|
- default-off channel without preference -> inactive
|
||||||
|
- default-off channel with preference -> active deviation
|
||||||
|
- global preference where `resourceIdentifier = null`
|
||||||
|
- device filtering via `deviceId`
|
||||||
|
- inactive subscription still returned as inactive
|
||||||
|
|
||||||
|
## Design choice
|
||||||
|
|
||||||
|
The implementation deliberately separates:
|
||||||
|
|
||||||
|
- HTTP entrypoints: request/response only
|
||||||
|
- CRUD client: raw REST calls only
|
||||||
|
- Mock CRUD client: deterministic local/demo data
|
||||||
|
- Service layer: composition and transformation logic
|
||||||
|
- Domain models: frontend/SE response shape
|
||||||
|
|
||||||
|
This makes the same transformation reusable in Azure Functions, Container Apps, and tests.
|
||||||
|
|
||||||
|
## Business rule interpretation
|
||||||
|
|
||||||
|
For each customer subscription:
|
||||||
|
|
||||||
|
1. Load customer `NotificationSubscriptions` with `NotificationPreferences` expanded to `EventTypeChannel`.
|
||||||
|
2. Load the default category definition with all `EventTypes` and `EventTypeChannels`.
|
||||||
|
3. Load customer resources for each channel resource type:
|
||||||
|
- `resourceNameId = 8` -> `GET /devices?customerProfileId={id}`
|
||||||
|
- `resourceNameId = 4` -> `GET /customers?customerProfileId={id}` and use the embedded `person` email data
|
||||||
|
4. For every default `EventTypeChannel`, write out resources explicitly.
|
||||||
|
5. If the channel is default-on and no preference exists, resource is active.
|
||||||
|
6. If the channel is default-off and no preference exists, resource is inactive.
|
||||||
|
7. A `NotificationPreference` row is interpreted as a deviation:
|
||||||
|
- default-on + preference -> inactive unless explicit `isActive` says otherwise
|
||||||
|
- default-off + preference -> active unless explicit `isActive` says otherwise
|
||||||
|
8. A null `resourceIdentifier` applies to all resources for that EventTypeChannel.
|
||||||
|
|
||||||
|
## Production hardening points
|
||||||
|
|
||||||
|
- Add authentication propagation from the SE API to both CRUD APIs.
|
||||||
|
- Decide whether category defaults should be cached across requests.
|
||||||
|
- Decide whether missing category defaults should become `502 Bad Gateway`, partial data, or an empty category.
|
||||||
|
- Confirm whether the real `NotificationPreference` has explicit `isActive`; this example supports it, but also works when preference existence alone means deviation.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,89 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from typing import Any, Optional
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
|
||||||
|
class CrudApiClient:
|
||||||
|
"""Thin async client around the ABT CRUD APIs.
|
||||||
|
|
||||||
|
Keep business/transformation logic out of this class. The client only knows how
|
||||||
|
to call the source endpoints and unwrap the collection names from the CRUD
|
||||||
|
contracts.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
notifications_base_url: str,
|
||||||
|
customers_base_url: str,
|
||||||
|
timeout_seconds: float = 10.0,
|
||||||
|
):
|
||||||
|
self.notifications_base_url = notifications_base_url.rstrip("/")
|
||||||
|
self.customers_base_url = customers_base_url.rstrip("/")
|
||||||
|
self.timeout_seconds = timeout_seconds
|
||||||
|
|
||||||
|
async def _get(
|
||||||
|
self,
|
||||||
|
base_url: str,
|
||||||
|
path: str,
|
||||||
|
params: Optional[dict[str, Any]] = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
async with httpx.AsyncClient(base_url=base_url, timeout=self.timeout_seconds) as client:
|
||||||
|
response = await client.get(path, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
# notifications-crud.yaml
|
||||||
|
async def get_notification_subscriptions(self, customer_profile_id: int) -> list[dict[str, Any]]:
|
||||||
|
payload = await self._get(
|
||||||
|
self.notifications_base_url,
|
||||||
|
"/notificationsubscriptions",
|
||||||
|
params={"customerProfileId": customer_profile_id, "expand": "eventTypeChannel"},
|
||||||
|
)
|
||||||
|
return payload.get("notificationSubscriptions", [])
|
||||||
|
|
||||||
|
async def get_notification_category_defaults(self, notification_category_id: int) -> Optional[dict[str, Any]]:
|
||||||
|
payload = await self._get(
|
||||||
|
self.notifications_base_url,
|
||||||
|
"/notificationcategories",
|
||||||
|
params={"notificationCategoryId": notification_category_id, "expand": "eventTypeChannel"},
|
||||||
|
)
|
||||||
|
categories = payload.get("notificationCategories", [])
|
||||||
|
return categories[0] if categories else None
|
||||||
|
|
||||||
|
# customers-crud-v2.yaml
|
||||||
|
async def get_ovpay_token(self, ovpay_token_id: Optional[int]) -> Optional[dict[str, Any]]:
|
||||||
|
if ovpay_token_id is None:
|
||||||
|
return None
|
||||||
|
payload = await self._get(
|
||||||
|
self.customers_base_url,
|
||||||
|
"/ovpaytokens",
|
||||||
|
params={"ovPayTokenId": ovpay_token_id},
|
||||||
|
)
|
||||||
|
tokens = payload.get("ovPayTokens", [])
|
||||||
|
return tokens[0] if tokens else None
|
||||||
|
|
||||||
|
async def get_devices(self, customer_profile_id: int) -> list[dict[str, Any]]:
|
||||||
|
payload = await self._get(
|
||||||
|
self.customers_base_url,
|
||||||
|
"/devices",
|
||||||
|
params={"customerProfileId": customer_profile_id},
|
||||||
|
)
|
||||||
|
return payload.get("devices", [])
|
||||||
|
|
||||||
|
async def get_persons(self, customer_profile_id: int) -> list[dict[str, Any]]:
|
||||||
|
"""Return customer/person resources used for email-like channels.
|
||||||
|
|
||||||
|
customers-crud-v2.yaml exposes person details through GET /customers,
|
||||||
|
filtered by customerProfileId. For the transformation service we normalize
|
||||||
|
the matching customer profile into one resource with the customer's email.
|
||||||
|
"""
|
||||||
|
payload = await self._get(
|
||||||
|
self.customers_base_url,
|
||||||
|
"/customers",
|
||||||
|
params={"customerProfileId": customer_profile_id},
|
||||||
|
)
|
||||||
|
return payload.get("customers", [])
|
||||||
|
|
||||||
|
|
||||||
|
# Backwards-compatible alias used by the service type hints.
|
||||||
|
NotificationsCrudClient = CrudApiClient
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from copy import deepcopy
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
|
||||||
|
class MockCrudClient:
|
||||||
|
"""Deterministic in-memory CRUD client for local demos and tests.
|
||||||
|
|
||||||
|
It implements the same methods as CrudApiClient, so the service layer does
|
||||||
|
not know whether data comes from real CRUD APIs or from mock fixtures.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, scenario: str = "mixed"):
|
||||||
|
self.scenario = scenario
|
||||||
|
|
||||||
|
async def get_notification_subscriptions(self, customer_profile_id: int) -> list[dict[str, Any]]:
|
||||||
|
subscriptions = deepcopy(MOCK_SUBSCRIPTIONS.get(self.scenario, MOCK_SUBSCRIPTIONS["mixed"]))
|
||||||
|
for subscription in subscriptions:
|
||||||
|
subscription["customerProfileId"] = customer_profile_id
|
||||||
|
return subscriptions
|
||||||
|
|
||||||
|
async def get_notification_category_defaults(self, notification_category_id: int) -> Optional[dict[str, Any]]:
|
||||||
|
return deepcopy(MOCK_CATEGORIES.get(notification_category_id))
|
||||||
|
|
||||||
|
async def get_ovpay_token(self, ovpay_token_id: Optional[int]) -> Optional[dict[str, Any]]:
|
||||||
|
if ovpay_token_id is None:
|
||||||
|
return None
|
||||||
|
return deepcopy(MOCK_OVPAY_TOKENS.get(ovpay_token_id, {"ovPayTokenId": ovpay_token_id, "alias": None}))
|
||||||
|
|
||||||
|
async def get_devices(self, customer_profile_id: int) -> list[dict[str, Any]]:
|
||||||
|
return deepcopy(MOCK_DEVICES)
|
||||||
|
|
||||||
|
async def get_persons(self, customer_profile_id: int) -> list[dict[str, Any]]:
|
||||||
|
return deepcopy(MOCK_CUSTOMERS)
|
||||||
|
|
||||||
|
|
||||||
|
MOCK_CATEGORIES: dict[int, dict[str, Any]] = {
|
||||||
|
1: {
|
||||||
|
"notificationCategoryId": 1,
|
||||||
|
"name": "Reizen",
|
||||||
|
"groupName": "Mijn passen",
|
||||||
|
"eventTypes": [
|
||||||
|
{
|
||||||
|
"eventTypeId": 10,
|
||||||
|
"name": "OVPAY_CHECK_IN",
|
||||||
|
"subName": "Check-in",
|
||||||
|
"prettyName": "Check-in bevestiging",
|
||||||
|
"eventTypeChannels": [
|
||||||
|
{
|
||||||
|
"eventTypeChannelId": "etc-push-default-on",
|
||||||
|
"channel": {
|
||||||
|
"channelId": 1,
|
||||||
|
"name": "Push",
|
||||||
|
"resourceName": {"resourceNameId": 8, "name": "devices"},
|
||||||
|
},
|
||||||
|
"isDefault": True,
|
||||||
|
"isMandatory": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"eventTypeChannelId": "etc-email-default-off",
|
||||||
|
"channel": {
|
||||||
|
"channelId": 2,
|
||||||
|
"name": "E-mail",
|
||||||
|
"resourceName": {"resourceNameId": 4, "name": "customers"},
|
||||||
|
},
|
||||||
|
"isDefault": False,
|
||||||
|
"isMandatory": False,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"eventTypeId": 20,
|
||||||
|
"name": "SERVICE_MESSAGE",
|
||||||
|
"subName": "Service",
|
||||||
|
"prettyName": "Servicebericht",
|
||||||
|
"eventTypeChannels": [
|
||||||
|
{
|
||||||
|
"eventTypeChannelId": "etc-email-mandatory",
|
||||||
|
"channel": {
|
||||||
|
"channelId": 2,
|
||||||
|
"name": "E-mail",
|
||||||
|
"resourceName": {"resourceNameId": 4, "name": "customers"},
|
||||||
|
},
|
||||||
|
"isDefault": True,
|
||||||
|
"isMandatory": True,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_SUBSCRIPTIONS: dict[str, list[dict[str, Any]]] = {
|
||||||
|
# Mixed scenario demonstrates both default behavior and customer deviations.
|
||||||
|
"mixed": [
|
||||||
|
{
|
||||||
|
"notificationSubscriptionId": "sub-mixed-1",
|
||||||
|
"notificationCategoryId": 1,
|
||||||
|
"notificationCategory": {"notificationCategoryId": 1, "name": "Reizen", "groupName": "Mijn passen"},
|
||||||
|
"customerProfileId": 42,
|
||||||
|
"ovPayTokenId": 112,
|
||||||
|
"subscriptionActivities": [{"timestamp": "2026-04-01T10:00:00Z", "isActive": True}],
|
||||||
|
"notificationPreferences": [
|
||||||
|
# Default push=true: this row opts out only device-2.
|
||||||
|
{"notificationPreferenceId": "pref-push-device-2-off", "eventTypeChannelId": "etc-push-default-on", "resourceIdentifier": "device-2"},
|
||||||
|
# Default email=false: this row opts in the customer's email resource.
|
||||||
|
{"notificationPreferenceId": "pref-email-on", "eventTypeChannelId": "etc-email-default-off", "resourceIdentifier": "42"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
# No preferences: output should be entirely based on category defaults.
|
||||||
|
"defaults_only": [
|
||||||
|
{
|
||||||
|
"notificationSubscriptionId": "sub-defaults-1",
|
||||||
|
"notificationCategoryId": 1,
|
||||||
|
"notificationCategory": {"notificationCategoryId": 1, "name": "Reizen", "groupName": "Mijn passen"},
|
||||||
|
"customerProfileId": 42,
|
||||||
|
"ovPayTokenId": 112,
|
||||||
|
"subscriptionActivities": [{"timestamp": "2026-04-01T10:00:00Z", "isActive": True}],
|
||||||
|
"notificationPreferences": [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
# Global preference: null resourceIdentifier applies the deviation to all resources.
|
||||||
|
"global_override": [
|
||||||
|
{
|
||||||
|
"notificationSubscriptionId": "sub-global-1",
|
||||||
|
"notificationCategoryId": 1,
|
||||||
|
"notificationCategory": {"notificationCategoryId": 1, "name": "Reizen", "groupName": "Mijn passen"},
|
||||||
|
"customerProfileId": 42,
|
||||||
|
"ovPayTokenId": 112,
|
||||||
|
"subscriptionActivities": [{"timestamp": "2026-04-01T10:00:00Z", "isActive": True}],
|
||||||
|
"notificationPreferences": [
|
||||||
|
{"notificationPreferenceId": "pref-all-push-off", "eventTypeChannelId": "etc-push-default-on", "resourceIdentifier": None}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
# Subscription inactive while preferences are still written out for the frontend.
|
||||||
|
"inactive_subscription": [
|
||||||
|
{
|
||||||
|
"notificationSubscriptionId": "sub-inactive-1",
|
||||||
|
"notificationCategoryId": 1,
|
||||||
|
"notificationCategory": {"notificationCategoryId": 1, "name": "Reizen", "groupName": "Mijn passen"},
|
||||||
|
"customerProfileId": 42,
|
||||||
|
"ovPayTokenId": 112,
|
||||||
|
"subscriptionActivities": [{"timestamp": "2026-04-01T10:00:00Z", "isActive": False}],
|
||||||
|
"notificationPreferences": [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_OVPAY_TOKENS = {
|
||||||
|
112: {"ovPayTokenId": 112, "alias": "Mijn betaalpas"},
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_DEVICES = [
|
||||||
|
{"deviceId": "device-1", "alias": "Mijn iPhone"},
|
||||||
|
{"deviceId": "device-2", "alias": "Werktelefoon"},
|
||||||
|
]
|
||||||
|
|
||||||
|
MOCK_CUSTOMERS = [
|
||||||
|
{"customerProfileId": 42, "person": {"emailAddress": "klant@example.nl"}},
|
||||||
|
]
|
||||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,60 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from typing import Any, Optional
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class Resource(BaseModel):
|
||||||
|
resourceName: str
|
||||||
|
resourceIdentifier: str
|
||||||
|
alias: Optional[str] = None
|
||||||
|
isActive: bool
|
||||||
|
|
||||||
|
|
||||||
|
class EventTypeChannelPreference(BaseModel):
|
||||||
|
eventTypeChannelId: str
|
||||||
|
channelId: int
|
||||||
|
name: str
|
||||||
|
isMandatory: bool = False
|
||||||
|
resources: list[Resource] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class EventTypePreference(BaseModel):
|
||||||
|
eventTypeId: int
|
||||||
|
name: str
|
||||||
|
subName: Optional[str] = None
|
||||||
|
prettyName: str
|
||||||
|
eventTypeChannels: list[EventTypeChannelPreference] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class OvPayToken(BaseModel):
|
||||||
|
ovPayTokenId: int
|
||||||
|
alias: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationSubscriptionPreference(BaseModel):
|
||||||
|
notificationSubscriptionId: str
|
||||||
|
customerProfileId: int
|
||||||
|
ovPayToken: Optional[OvPayToken] = None
|
||||||
|
isActive: bool
|
||||||
|
eventTypes: list[EventTypePreference] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationCategoryPreference(BaseModel):
|
||||||
|
notificationCategoryId: int
|
||||||
|
name: str
|
||||||
|
groupName: Optional[str] = None
|
||||||
|
notificationSubscriptions: list[NotificationSubscriptionPreference] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerNotificationPreferencesResponse(BaseModel):
|
||||||
|
notificationCategories: list[NotificationCategoryPreference] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
def latest_activity_is_active(subscription: dict[str, Any]) -> bool:
|
||||||
|
"""CRUD returns subscriptionActivities; the most recent/current one determines active state."""
|
||||||
|
activities = subscription.get("subscriptionActivities") or []
|
||||||
|
if not activities:
|
||||||
|
return False
|
||||||
|
# CRUD activityLimit defaults to 1; when more are supplied, sort defensively on timestamp.
|
||||||
|
latest = sorted(activities, key=lambda a: a.get("timestamp", ""), reverse=True)[0]
|
||||||
|
return bool(latest.get("isActive"))
|
||||||
Binary file not shown.
@ -0,0 +1,17 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
import azure.functions as func
|
||||||
|
|
||||||
|
from app.service_factory import create_notification_preferences_service
|
||||||
|
|
||||||
|
|
||||||
|
async def main(req: func.HttpRequest) -> func.HttpResponse:
|
||||||
|
customer_profile_id = req.headers.get("X-HTM-CUSTOMER-PROFILE-ID-HEADER")
|
||||||
|
if not customer_profile_id:
|
||||||
|
return func.HttpResponse("Missing X-HTM-CUSTOMER-PROFILE-ID-HEADER", status_code=400)
|
||||||
|
|
||||||
|
service = create_notification_preferences_service()
|
||||||
|
result = await service.get_customer_notification_preferences(
|
||||||
|
customer_profile_id=int(customer_profile_id),
|
||||||
|
device_id=req.params.get("deviceId"),
|
||||||
|
)
|
||||||
|
return func.HttpResponse(result.model_dump_json(exclude_none=True), mimetype="application/json", status_code=200)
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from fastapi import FastAPI, Header, Query
|
||||||
|
|
||||||
|
from app.domain.models import CustomerNotificationPreferencesResponse
|
||||||
|
from app.service_factory import create_notification_preferences_service
|
||||||
|
from app.settings import settings
|
||||||
|
|
||||||
|
app = FastAPI(title="SE Notifications example")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
async def health():
|
||||||
|
return {"status": "ok", "useMockData": settings.use_mock_data, "mockScenario": settings.mock_scenario}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/customers/notificationpreferences", response_model=CustomerNotificationPreferencesResponse)
|
||||||
|
async def get_customer_notification_preferences(
|
||||||
|
x_htm_customer_profile_id_header: int = Header(..., alias="X-HTM-CUSTOMER-PROFILE-ID-HEADER"),
|
||||||
|
device_id: str | None = Query(default=None, alias="deviceId"),
|
||||||
|
):
|
||||||
|
service = create_notification_preferences_service()
|
||||||
|
return await service.get_customer_notification_preferences(
|
||||||
|
customer_profile_id=x_htm_customer_profile_id_header,
|
||||||
|
device_id=device_id,
|
||||||
|
)
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from app.clients.crud_client import CrudApiClient
|
||||||
|
from app.clients.mock_crud_client import MockCrudClient
|
||||||
|
from app.services.notification_preferences_service import NotificationPreferencesService
|
||||||
|
from app.settings import settings
|
||||||
|
|
||||||
|
|
||||||
|
def create_notification_preferences_service() -> NotificationPreferencesService:
|
||||||
|
if settings.use_mock_data:
|
||||||
|
return NotificationPreferencesService(MockCrudClient(settings.mock_scenario))
|
||||||
|
|
||||||
|
return NotificationPreferencesService(
|
||||||
|
CrudApiClient(
|
||||||
|
notifications_base_url=settings.notifications_crud_base_url,
|
||||||
|
customers_base_url=settings.customers_crud_base_url,
|
||||||
|
)
|
||||||
|
)
|
||||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,228 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from collections import defaultdict
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
from app.clients.crud_client import NotificationsCrudClient
|
||||||
|
from app.domain.models import (
|
||||||
|
CustomerNotificationPreferencesResponse,
|
||||||
|
EventTypeChannelPreference,
|
||||||
|
EventTypePreference,
|
||||||
|
NotificationCategoryPreference,
|
||||||
|
NotificationSubscriptionPreference,
|
||||||
|
OvPayToken,
|
||||||
|
Resource,
|
||||||
|
latest_activity_is_active,
|
||||||
|
)
|
||||||
|
|
||||||
|
RESOURCE_DEVICES_ID = 8
|
||||||
|
RESOURCE_PERSONS_ID = 4
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationPreferencesService:
|
||||||
|
def __init__(self, crud_client: NotificationsCrudClient):
|
||||||
|
self.crud_client = crud_client
|
||||||
|
|
||||||
|
async def get_customer_notification_preferences(
|
||||||
|
self,
|
||||||
|
customer_profile_id: int,
|
||||||
|
device_id: Optional[str] = None,
|
||||||
|
) -> CustomerNotificationPreferencesResponse:
|
||||||
|
subscriptions = await self.crud_client.get_notification_subscriptions(customer_profile_id)
|
||||||
|
categories_by_id: dict[int, NotificationCategoryPreference] = {}
|
||||||
|
|
||||||
|
# Small in-request caches avoid repeated calls for the same category/resources.
|
||||||
|
default_category_cache: dict[int, dict[str, Any]] = {}
|
||||||
|
resource_cache: dict[int, list[dict[str, Any]]] = {}
|
||||||
|
|
||||||
|
for subscription in subscriptions:
|
||||||
|
category_id = _extract_category_id(subscription)
|
||||||
|
default_category = default_category_cache.get(category_id)
|
||||||
|
if default_category is None:
|
||||||
|
default_category = await self.crud_client.get_notification_category_defaults(category_id)
|
||||||
|
if default_category is None:
|
||||||
|
# Defensive choice: skip orphaned subscriptions rather than returning incomplete UI data.
|
||||||
|
continue
|
||||||
|
default_category_cache[category_id] = default_category
|
||||||
|
|
||||||
|
category_response = categories_by_id.setdefault(
|
||||||
|
category_id,
|
||||||
|
NotificationCategoryPreference(
|
||||||
|
notificationCategoryId=category_id,
|
||||||
|
name=default_category.get("name") or subscription.get("notificationCategory", {}).get("name"),
|
||||||
|
groupName=default_category.get("groupName") or subscription.get("notificationCategory", {}).get("groupName"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
token_payload = await self.crud_client.get_ovpay_token(subscription.get("ovPayTokenId"))
|
||||||
|
token = _to_ovpay_token(token_payload, subscription.get("ovPayTokenId"))
|
||||||
|
|
||||||
|
subscription_response = NotificationSubscriptionPreference(
|
||||||
|
notificationSubscriptionId=subscription["notificationSubscriptionId"],
|
||||||
|
customerProfileId=subscription["customerProfileId"],
|
||||||
|
ovPayToken=token,
|
||||||
|
isActive=latest_activity_is_active(subscription),
|
||||||
|
)
|
||||||
|
|
||||||
|
preferences_by_event_type_channel = _index_preferences(subscription)
|
||||||
|
|
||||||
|
for event_type in default_category.get("eventTypes", []):
|
||||||
|
event_type_response = EventTypePreference(
|
||||||
|
eventTypeId=event_type["eventTypeId"],
|
||||||
|
name=event_type["name"],
|
||||||
|
subName=event_type.get("subName"),
|
||||||
|
prettyName=event_type.get("prettyName") or event_type["name"],
|
||||||
|
)
|
||||||
|
|
||||||
|
for event_type_channel in event_type.get("eventTypeChannels", []):
|
||||||
|
channel = event_type_channel.get("channel", {})
|
||||||
|
resource_name = channel.get("resourceName", {})
|
||||||
|
resource_name_id = resource_name.get("resourceNameId")
|
||||||
|
resource_name_text = resource_name.get("name") or channel.get("name")
|
||||||
|
|
||||||
|
if resource_name_id not in resource_cache:
|
||||||
|
resource_cache[resource_name_id] = await self._load_resources(resource_name_id, customer_profile_id)
|
||||||
|
source_resources = resource_cache[resource_name_id]
|
||||||
|
|
||||||
|
if device_id and resource_name_id == RESOURCE_DEVICES_ID:
|
||||||
|
source_resources = [r for r in source_resources if str(_resource_identifier(r)) == str(device_id)]
|
||||||
|
if not source_resources:
|
||||||
|
# SE swagger states a deviceId filter returns only ETCs with resources for that device.
|
||||||
|
continue
|
||||||
|
|
||||||
|
matching_preferences = preferences_by_event_type_channel.get(
|
||||||
|
str(event_type_channel["eventTypeChannelId"]), []
|
||||||
|
)
|
||||||
|
|
||||||
|
resources = self._normalize_resources(
|
||||||
|
resource_name=resource_name_text,
|
||||||
|
event_type_channel=event_type_channel,
|
||||||
|
source_resources=source_resources,
|
||||||
|
preferences=matching_preferences,
|
||||||
|
)
|
||||||
|
|
||||||
|
event_type_response.eventTypeChannels.append(
|
||||||
|
EventTypeChannelPreference(
|
||||||
|
eventTypeChannelId=event_type_channel["eventTypeChannelId"],
|
||||||
|
channelId=channel["channelId"],
|
||||||
|
name=channel["name"],
|
||||||
|
isMandatory=bool(event_type_channel.get("isMandatory")),
|
||||||
|
resources=resources,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if event_type_response.eventTypeChannels:
|
||||||
|
subscription_response.eventTypes.append(event_type_response)
|
||||||
|
|
||||||
|
category_response.notificationSubscriptions.append(subscription_response)
|
||||||
|
|
||||||
|
return CustomerNotificationPreferencesResponse(notificationCategories=list(categories_by_id.values()))
|
||||||
|
|
||||||
|
async def _load_resources(self, resource_name_id: int, customer_profile_id: int) -> list[dict[str, Any]]:
|
||||||
|
if resource_name_id == RESOURCE_DEVICES_ID:
|
||||||
|
return await self.crud_client.get_devices(customer_profile_id)
|
||||||
|
if resource_name_id == RESOURCE_PERSONS_ID:
|
||||||
|
return await self.crud_client.get_persons(customer_profile_id)
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _normalize_resources(
|
||||||
|
self,
|
||||||
|
resource_name: str,
|
||||||
|
event_type_channel: dict[str, Any],
|
||||||
|
source_resources: list[dict[str, Any]],
|
||||||
|
preferences: list[dict[str, Any]],
|
||||||
|
) -> list[Resource]:
|
||||||
|
default_active = bool(event_type_channel.get("isDefault"))
|
||||||
|
|
||||||
|
if not preferences:
|
||||||
|
return [
|
||||||
|
Resource(
|
||||||
|
resourceName=resource_name,
|
||||||
|
resourceIdentifier=str(_resource_identifier(resource)),
|
||||||
|
alias=_resource_alias(resource),
|
||||||
|
isActive=default_active,
|
||||||
|
)
|
||||||
|
for resource in source_resources
|
||||||
|
]
|
||||||
|
|
||||||
|
# Preference rows are exceptions/deviations. A null resourceIdentifier means the exception applies to all resources.
|
||||||
|
preference_by_resource: dict[str, dict[str, Any]] = {}
|
||||||
|
global_preference: Optional[dict[str, Any]] = None
|
||||||
|
for preference in preferences:
|
||||||
|
pref_resource_id = preference.get("resourceIdentifier")
|
||||||
|
if pref_resource_id is None:
|
||||||
|
global_preference = preference
|
||||||
|
else:
|
||||||
|
preference_by_resource[str(pref_resource_id)] = preference
|
||||||
|
|
||||||
|
normalized: list[Resource] = []
|
||||||
|
for resource in source_resources:
|
||||||
|
resource_id = str(_resource_identifier(resource))
|
||||||
|
preference = preference_by_resource.get(resource_id) or global_preference
|
||||||
|
if preference is None:
|
||||||
|
is_active = default_active
|
||||||
|
else:
|
||||||
|
# The CRUD example only shows the existence of a preference row, no explicit isActive.
|
||||||
|
# Therefore: for default-on channels a row means opted out; for default-off a row means opted in.
|
||||||
|
is_active = bool(preference.get("isActive", not default_active))
|
||||||
|
|
||||||
|
normalized.append(
|
||||||
|
Resource(
|
||||||
|
resourceName=resource_name,
|
||||||
|
resourceIdentifier=resource_id,
|
||||||
|
alias=_resource_alias(resource),
|
||||||
|
isActive=is_active,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return normalized
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_category_id(subscription: dict[str, Any]) -> int:
|
||||||
|
if subscription.get("notificationCategoryId") is not None:
|
||||||
|
return int(subscription["notificationCategoryId"])
|
||||||
|
return int(subscription["notificationCategory"]["notificationCategoryId"])
|
||||||
|
|
||||||
|
|
||||||
|
def _index_preferences(subscription: dict[str, Any]) -> dict[str, list[dict[str, Any]]]:
|
||||||
|
result: dict[str, list[dict[str, Any]]] = defaultdict(list)
|
||||||
|
for preference in subscription.get("notificationPreferences", []) or []:
|
||||||
|
event_type_channel_id = preference.get("eventTypeChannelId")
|
||||||
|
if isinstance(event_type_channel_id, dict):
|
||||||
|
event_type_channel_id = event_type_channel_id.get("eventTypeChannelId")
|
||||||
|
if event_type_channel_id is None and isinstance(preference.get("eventTypeChannel"), dict):
|
||||||
|
event_type_channel_id = preference["eventTypeChannel"].get("eventTypeChannelId")
|
||||||
|
if event_type_channel_id is not None:
|
||||||
|
result[str(event_type_channel_id)].append(preference)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _to_ovpay_token(payload: Optional[dict[str, Any]], fallback_id: Optional[int]) -> Optional[OvPayToken]:
|
||||||
|
if fallback_id is None:
|
||||||
|
return None
|
||||||
|
# Support both {ovPayToken: {...}} and direct {...} shapes.
|
||||||
|
token = (payload or {}).get("ovPayToken", payload or {})
|
||||||
|
return OvPayToken(ovPayTokenId=token.get("ovPayTokenId", fallback_id), alias=token.get("alias"))
|
||||||
|
|
||||||
|
|
||||||
|
def _resource_identifier(resource: dict[str, Any]) -> Any:
|
||||||
|
# Device resources use deviceId. Customer/person email resources are normalized
|
||||||
|
# to customerProfileId because customers-crud-v2 exposes person under /customers.
|
||||||
|
return (
|
||||||
|
resource.get("resourceIdentifier")
|
||||||
|
or resource.get("deviceId")
|
||||||
|
or resource.get("personId")
|
||||||
|
or resource.get("customerProfileId")
|
||||||
|
or resource.get("id")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _resource_alias(resource: dict[str, Any]) -> Optional[str]:
|
||||||
|
person = resource.get("person") or {}
|
||||||
|
return (
|
||||||
|
resource.get("alias")
|
||||||
|
or resource.get("emailAddress")
|
||||||
|
or resource.get("emailAddresses")
|
||||||
|
or resource.get("email")
|
||||||
|
or person.get("emailAddress")
|
||||||
|
or person.get("emailAddresses")
|
||||||
|
or resource.get("name")
|
||||||
|
)
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
|
|
||||||
|
class Settings(BaseSettings):
|
||||||
|
notifications_crud_base_url: str = "http://localhost:8001"
|
||||||
|
customers_crud_base_url: str = "http://localhost:8002"
|
||||||
|
|
||||||
|
# local development aid: set USE_MOCK_DATA=true to run without CRUD APIs
|
||||||
|
use_mock_data: bool = False
|
||||||
|
mock_scenario: str = "mixed"
|
||||||
|
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fastapi==0.115.6
|
||||||
|
uvicorn[standard]==0.34.0
|
||||||
|
httpx==0.28.1
|
||||||
|
pydantic>=2.12.0
|
||||||
|
pydantic-settings>=2.7.1
|
||||||
|
azure-functions==1.21.3
|
||||||
|
pytest==8.3.4
|
||||||
|
pytest-asyncio==0.25.2
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,69 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from app.clients.mock_crud_client import MockCrudClient
|
||||||
|
from app.services.notification_preferences_service import NotificationPreferencesService
|
||||||
|
|
||||||
|
|
||||||
|
def _channels(result):
|
||||||
|
subscription = result.notificationCategories[0].notificationSubscriptions[0]
|
||||||
|
return {
|
||||||
|
channel.eventTypeChannelId: channel
|
||||||
|
for event_type in subscription.eventTypes
|
||||||
|
for channel in event_type.eventTypeChannels
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_mixed_scenario_applies_default_on_and_default_off_deviations():
|
||||||
|
service = NotificationPreferencesService(MockCrudClient("mixed"))
|
||||||
|
result = await service.get_customer_notification_preferences(42)
|
||||||
|
channels = _channels(result)
|
||||||
|
|
||||||
|
push_resources = channels["etc-push-default-on"].resources
|
||||||
|
assert [(r.resourceIdentifier, r.isActive) for r in push_resources] == [
|
||||||
|
("device-1", True),
|
||||||
|
("device-2", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
email_resources = channels["etc-email-default-off"].resources
|
||||||
|
assert [(r.resourceIdentifier, r.isActive) for r in email_resources] == [("42", True)]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_defaults_only_scenario_writes_all_resources_from_defaults():
|
||||||
|
service = NotificationPreferencesService(MockCrudClient("defaults_only"))
|
||||||
|
result = await service.get_customer_notification_preferences(42)
|
||||||
|
channels = _channels(result)
|
||||||
|
|
||||||
|
assert [r.isActive for r in channels["etc-push-default-on"].resources] == [True, True]
|
||||||
|
assert [r.isActive for r in channels["etc-email-default-off"].resources] == [False]
|
||||||
|
assert channels["etc-email-mandatory"].isMandatory is True
|
||||||
|
assert [r.isActive for r in channels["etc-email-mandatory"].resources] == [True]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_global_override_applies_to_all_resources_when_resource_identifier_is_null():
|
||||||
|
service = NotificationPreferencesService(MockCrudClient("global_override"))
|
||||||
|
result = await service.get_customer_notification_preferences(42)
|
||||||
|
channels = _channels(result)
|
||||||
|
|
||||||
|
assert [r.isActive for r in channels["etc-push-default-on"].resources] == [False, False]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_device_filter_returns_only_requested_device_for_device_channels():
|
||||||
|
service = NotificationPreferencesService(MockCrudClient("mixed"))
|
||||||
|
result = await service.get_customer_notification_preferences(42, device_id="device-1")
|
||||||
|
channels = _channels(result)
|
||||||
|
|
||||||
|
assert [(r.resourceIdentifier, r.isActive) for r in channels["etc-push-default-on"].resources] == [("device-1", True)]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_inactive_subscription_is_visible_but_marked_inactive():
|
||||||
|
service = NotificationPreferencesService(MockCrudClient("inactive_subscription"))
|
||||||
|
result = await service.get_customer_notification_preferences(42)
|
||||||
|
subscription = result.notificationCategories[0].notificationSubscriptions[0]
|
||||||
|
|
||||||
|
assert subscription.isActive is False
|
||||||
|
assert subscription.eventTypes
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from app.services.notification_preferences_service import NotificationPreferencesService
|
||||||
|
|
||||||
|
|
||||||
|
class FakeCrudClient:
|
||||||
|
async def get_notification_subscriptions(self, customer_profile_id: int):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"notificationSubscriptionId": "sub-1",
|
||||||
|
"notificationCategory": {"notificationCategoryId": 1, "name": "Reizen", "groupName": "Mijn passen"},
|
||||||
|
"customerProfileId": customer_profile_id,
|
||||||
|
"ovPayTokenId": 112,
|
||||||
|
"subscriptionActivities": [{"timestamp": "2026-01-01T00:00:00Z", "isActive": True}],
|
||||||
|
"notificationPreferences": [
|
||||||
|
# Default push=true, this row switches device-2 off only.
|
||||||
|
{"notificationPreferenceId": "pref-1", "eventTypeChannelId": "etc-push", "resourceIdentifier": "device-2"},
|
||||||
|
# Default email=false, this row switches customer email on.
|
||||||
|
{"notificationPreferenceId": "pref-2", "eventTypeChannelId": "etc-email", "resourceIdentifier": "42"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
async def get_notification_category_defaults(self, notification_category_id: int):
|
||||||
|
return {
|
||||||
|
"notificationCategoryId": 1,
|
||||||
|
"name": "Reizen",
|
||||||
|
"groupName": "Mijn passen",
|
||||||
|
"eventTypes": [
|
||||||
|
{
|
||||||
|
"eventTypeId": 2,
|
||||||
|
"name": "GBO",
|
||||||
|
"subName": "CI",
|
||||||
|
"prettyName": "Normal Check-in",
|
||||||
|
"eventTypeChannels": [
|
||||||
|
{
|
||||||
|
"eventTypeChannelId": "etc-push",
|
||||||
|
"channel": {"channelId": 1, "name": "push", "resourceName": {"resourceNameId": 8, "name": "devices"}},
|
||||||
|
"isDefault": True,
|
||||||
|
"isMandatory": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"eventTypeChannelId": "etc-email",
|
||||||
|
"channel": {"channelId": 2, "name": "email", "resourceName": {"resourceNameId": 4, "name": "customers"}},
|
||||||
|
"isDefault": False,
|
||||||
|
"isMandatory": False,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
async def get_ovpay_token(self, ovpay_token_id):
|
||||||
|
return {"ovPayToken": {"ovPayTokenId": ovpay_token_id, "alias": "Mijn ING bankpas"}}
|
||||||
|
|
||||||
|
async def get_devices(self, customer_profile_id: int):
|
||||||
|
return [
|
||||||
|
{"deviceId": "device-1", "alias": "Mijn iPhone"},
|
||||||
|
{"deviceId": "device-2", "alias": "Mijn Pixel"},
|
||||||
|
]
|
||||||
|
|
||||||
|
async def get_persons(self, customer_profile_id: int):
|
||||||
|
return [{"customerProfileId": 42, "emailAddress": "customer@example.nl"}]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_normalizes_defaults_and_customer_exceptions():
|
||||||
|
result = await NotificationPreferencesService(FakeCrudClient()).get_customer_notification_preferences(42)
|
||||||
|
event_type = result.notificationCategories[0].notificationSubscriptions[0].eventTypes[0]
|
||||||
|
|
||||||
|
push_resources = event_type.eventTypeChannels[0].resources
|
||||||
|
assert [r.isActive for r in push_resources] == [True, False]
|
||||||
|
|
||||||
|
email_resources = event_type.eventTypeChannels[1].resources
|
||||||
|
assert email_resources[0].isActive is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_device_filter_only_returns_that_device_resource():
|
||||||
|
result = await NotificationPreferencesService(FakeCrudClient()).get_customer_notification_preferences(42, device_id="device-1")
|
||||||
|
event_type = result.notificationCategories[0].notificationSubscriptions[0].eventTypes[0]
|
||||||
|
assert len(event_type.eventTypeChannels[0].resources) == 1
|
||||||
|
assert event_type.eventTypeChannels[0].resources[0].resourceIdentifier == "device-1"
|
||||||
151
trip2.json
151
trip2.json
@ -1,151 +0,0 @@
|
|||||||
{ "tripId": 796727186, "tripVersion": 1, "tripStatus": "COMPLETE", "organisationIcon": "/icons/organisations/3.svg", "organisationId": "3", "organisationName": "HTM", "supersededByTripIds": [], "supersedesTripIds": [], "products": [ {
|
|
||||||
"productTemplateId": "30901", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "HTM 90% Korting" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "HTM 90% Discount" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"productIcon": "001.jpg", "purchaseDateTime": "2026-04-02T12:38:28+02:00", "organisationName": "ProductRetailer HTM", "appliedValue": -125, "organisationId": "3", "category": "SALES", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "discount" }
|
|
||||||
],
|
|
||||||
"xspit": "821ddb0d-4ea7-4a0d-84aa-bb7facce15d1" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "N/A", "purchaseDateTime": "2025-07-09T12:39:27+02:00", "appliedValue": 139, "category": "SALES", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "payg" }
|
|
||||||
],
|
|
||||||
"xspit": "7618337f-c986-4bef-990d-f5a6b47292b8" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "1:2000", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Basis Bus Tram Metro" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "BTM full fare" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validFrom": "2000-01-01T01:00:00+01:00", "validUntil": "2100-01-01T00:59:59+01:00", "weight": 116, "appliedMetric": "FARE", "appliedValue": 116, "category": "INTERNAL", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "payg" }
|
|
||||||
],
|
|
||||||
"xspit": "7618337f-c986-4bef-990d-f5a6b47292b8", "xpit": "f4256df6-b767-460f-9880-f7597bd7f3f2" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "2:2000", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Basis Bus Tram Metro" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "BTM full fare" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validFrom": "2000-01-01T01:00:00+01:00", "validUntil": "2100-01-01T00:59:59+01:00", "weight": 23, "appliedMetric": "FARE", "appliedValue": 23, "category": "INTERNAL", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "payg" }
|
|
||||||
],
|
|
||||||
"xspit": "7618337f-c986-4bef-990d-f5a6b47292b8", "xpit": "f4256df6-b767-460f-9880-f7597bd7f3f2" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "3:30901", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "HTM 90% Korting" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "HTM 90% Discount" },
|
|
||||||
{
|
|
||||||
"key": "nl-NL", "value": "Reis je regelmatig met HTM? Activeer dan HTM 90% Korting op je betaalpas of credit card en reis een week lang met korting!" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "Are you a regular traveler? Activate HTM 90% discount on your EMV card!" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validFrom": "2026-04-03T04:00:00+02:00", "validUntil": "2031-04-03T04:00:00+02:00", "organisationName": "Product Owner HTM", "weight": -125, "appliedMetric": "DISCOUNT", "appliedValue": -125, "organisationId": "3", "category": "INTERNAL", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "discount" }
|
|
||||||
],
|
|
||||||
"productCatalogVersionId": "PC-HTM:70", "xspit": "821ddb0d-4ea7-4a0d-84aa-bb7facce15d1", "xpit": "1848597c-5ba9-4dab-8d9f-3948948706a1" }
|
|
||||||
],
|
|
||||||
"checkinTransactionTimestamp": "2026-04-20T16:59:48+02:00", "checkoutTransactionTimestamp": "2026-04-20T17:04:50+02:00", "checkinTransactionReference": "00310F92;29023;emvClt", "checkoutTransactionReference": "0030DBC1;30528;emvClt", "checkinLocation": { "stopId": 2721, "stopName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Station Hollands Spoor" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "Station Hollands Spoor" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stopDesc": "Stop point2721", "stopUrl": "/icons/stops/stop.svg", "locationType": 0 },
|
|
||||||
"checkoutLocation": { "stopId": 2862, "stopName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Kalvermarkt-Stadhuis" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "Kalvermarkt-Stadhuis" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stopDesc": "Stop point2862", "stopUrl": "/icons/stops/stop.svg", "locationType": 0 },
|
|
||||||
"tokenType": "EMV-CLT", "transportType": "TRAM", "lineId": "17", "lineName": "Tram17", "networkId": "1", "networkName": "HTM netwerk", "currency": "EUR", "transportIcon": "/icons/transportTypes/tram.svg", "legs": [ {
|
|
||||||
"legId": 1614950977, "checkinTransactionTimestamp": "2026-04-20T16:59:48+02:00", "checkoutTransactionTimestamp": "2026-04-20T17:04:50+02:00", "checkinLocation": { "stopId": 2721, "stopName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Station Hollands Spoor" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "Station Hollands Spoor" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stopDesc": "Stop point2721", "stopUrl": "/icons/stops/stop.svg", "locationType": 0 },
|
|
||||||
"checkoutLocation": { "stopId": 2862, "stopName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Kalvermarkt-Stadhuis" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "Kalvermarkt-Stadhuis" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stopDesc": "Stop point2862", "stopUrl": "/icons/stops/stop.svg", "locationType": 0 },
|
|
||||||
"baseRate": 139, "lineId": "17", "lineName": "Tram17", "networkId": "1", "networkName": "HTM netwerk", "fare": 14, "fareState": "CALCULATED", "currency": "EUR", "products": [ {
|
|
||||||
"productTemplateId": "30901", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "HTM 90% Korting" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "HTM 90% Discount" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"productIcon": "001.jpg", "purchaseDateTime": "2026-04-02T12:38:28+02:00", "organisationName": "ProductRetailer HTM", "appliedValue": -125, "organisationId": "3", "category": "SALES", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "discount" }
|
|
||||||
],
|
|
||||||
"xspit": "821ddb0d-4ea7-4a0d-84aa-bb7facce15d1" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "N/A", "purchaseDateTime": "2025-07-09T12:39:27+02:00", "appliedValue": 139, "category": "SALES", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "payg" }
|
|
||||||
],
|
|
||||||
"xspit": "7618337f-c986-4bef-990d-f5a6b47292b8" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "1:2000", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Basis Bus Tram Metro" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "BTM full fare" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validFrom": "2000-01-01T01:00:00+01:00", "validUntil": "2100-01-01T00:59:59+01:00", "weight": 116, "appliedMetric": "FARE", "appliedValue": 116, "category": "INTERNAL", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "payg" }
|
|
||||||
],
|
|
||||||
"xspit": "7618337f-c986-4bef-990d-f5a6b47292b8", "xpit": "f4256df6-b767-460f-9880-f7597bd7f3f2" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "2:2000", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Basis Bus Tram Metro" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "BTM full fare" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validFrom": "2000-01-01T01:00:00+01:00", "validUntil": "2100-01-01T00:59:59+01:00", "weight": 23, "appliedMetric": "FARE", "appliedValue": 23, "category": "INTERNAL", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "payg" }
|
|
||||||
],
|
|
||||||
"xspit": "7618337f-c986-4bef-990d-f5a6b47292b8", "xpit": "f4256df6-b767-460f-9880-f7597bd7f3f2" },
|
|
||||||
{
|
|
||||||
"productTemplateId": "3:30901", "productCommercialName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "HTM 90% Korting" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "HTM 90% Discount" },
|
|
||||||
{
|
|
||||||
"key": "nl-NL", "value": "Reis je regelmatig met HTM? Activeer dan HTM 90% Korting op je betaalpas of credit card en reis een week lang met korting!" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "Are you a regular traveler? Activate HTM 90% discount on your EMV card!" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"validFrom": "2026-04-03T04:00:00+02:00", "validUntil": "2031-04-03T04:00:00+02:00", "organisationName": "Product Owner HTM", "weight": -125, "appliedMetric": "DISCOUNT", "appliedValue": -125, "organisationId": "3", "category": "INTERNAL", "typesOfFareProduct": [ {
|
|
||||||
"privateCode": "discount" }
|
|
||||||
],
|
|
||||||
"discountPercentage": 90, "productCatalogVersionId": "PC-HTM:70", "xspit": "821ddb0d-4ea7-4a0d-84aa-bb7facce15d1", "xpit": "1848597c-5ba9-4dab-8d9f-3948948706a1" }
|
|
||||||
],
|
|
||||||
"appliedTimePeriods": [], "tariffJourneyStart": true, "topoDistance": 1161, "concessionId": "1", "appliedZones": [] }
|
|
||||||
],
|
|
||||||
"lastUpdatedTripDateTime": "2026-04-20T17:04:50+02:00", "fare": 14, "loyaltyOrDiscount": true, "supportCode": "pWM8Km6J8aHg5n", "tripVersionReason": "STRUCTURE", "checkinTransactionId": "00310F92-29023-emvClt-1776697188000", "checkoutTransactionId": "0030DBC1-30528-emvClt-1776697490000", "tariffVersionId": "HTM-CF1:278", "correlationId": "4bc7a040-71bf-4084-a61e-b2dd72092079", "createdAt": "2026-04-20T17:05:01.473+02:00", "entryTariffLocation": { "stopId": 2721, "stopName": { "items": [ {
|
|
||||||
"key": "nl-NL", "value": "Station Hollands Spoor" },
|
|
||||||
{
|
|
||||||
"key": "en-US", "value": "Station Hollands Spoor" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stopDesc": "Stop point2721", "stopUrl": "/icons/stops/stop.svg", "locationType": 0 },
|
|
||||||
"traveledLines": [ {
|
|
||||||
"lineId": "17", "lineName": "Tram17" }
|
|
||||||
],
|
|
||||||
"tripFareNature": "FIXED", "paymentMethodId": "229a01ff-7bd9-4740-9b19-00637146a6ca", "paymentMethodMode": "PREPAID", "paymentMethodName": "EPURSE", "paymentProviderName": "TPURSE", "paymentProviderBusinessEntityId": "600027", "registryFragmentVersionId": "REG:27", "vehicleId": 5063, "xbot": "c85e34d6-f9c1-49c2-8574-59b37e0f3b8e" }
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user