From b5ee5d0a0d30961aeeaf6e22c9cd0af8da07622c Mon Sep 17 00:00:00 2001 From: YegorZh Date: Mon, 23 Feb 2026 12:46:14 +0000 Subject: [PATCH 1/2] feat: get missing fields request and application related updates --- openapi.json | 5 +- schemas/application/application.json | 62 ++++- .../application/applicationMissingFields.json | 104 ++++++++ schemas/application/applicationPaths.json | 31 +++ schemas/application/createApplication.json | 32 ++- schemas/application/updateApplication.json | 229 ++++++++++++++++++ unit/e2e_tests/java/ApplicationTests.java | 150 +++++------- 7 files changed, 510 insertions(+), 103 deletions(-) create mode 100644 schemas/application/applicationMissingFields.json diff --git a/openapi.json b/openapi.json index fcecda8..10a1b17 100644 --- a/openapi.json +++ b/openapi.json @@ -3,7 +3,7 @@ "info": { "title": "Unit OpenAPI specifications", "description": "An OpenAPI specifications for unit-sdk clients", - "version": "0.3.2" + "version": "0.4.0" }, "servers": [ { @@ -47,6 +47,9 @@ "/beneficial-owner/{beneficialOwnerId}": { "$ref": "./schemas/application/applicationPaths.json#/updateBusinessBeneficialOwner" }, + "/applications/{applicationId}/missing-fields": { + "$ref": "./schemas/application/applicationPaths.json#/applicationMissingFields" + }, "/accounts": { "$ref": "./schemas/account/accountPaths.json#/accounts" }, diff --git a/schemas/application/application.json b/schemas/application/application.json index 670b6ec..df1f5fb 100644 --- a/schemas/application/application.json +++ b/schemas/application/application.json @@ -445,6 +445,48 @@ }, "operatingAddress": { "$ref": "../types.json#/components/schemas/Address" + }, + "sourceOfFunds": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessSourceOfFunds" + }, + "sourceOfFundsDescription": { + "type": "string" + }, + "businessIndustry": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessIndustry" + }, + "businessDescription": { + "type": "string" + }, + "isRegulated": { + "type": "boolean" + }, + "regulatorName": { + "type": "string" + }, + "usNexus": { + "type": "array", + "items": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessUsNexus" + } + }, + "accountPurpose": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessAccountPurpose" + }, + "accountPurposeDescription": { + "type": "string" + }, + "accountPurposeDetail": { + "type": "string" + }, + "transactionVolume": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessTransactionVolume" + }, + "transactionVolumeDescription": { + "type": "string" + }, + "stockExchangeName": { + "type": "string" } }, "additionalProperties": false, @@ -625,7 +667,25 @@ "businessVertical": { "$ref": "../types.json#/components/schemas/BusinessVertical" }, - "website": { "type": "string" } + "website": { "type": "string" }, + "accountPurpose": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualAccountPurpose" + }, + "accountPurposeDetail": { + "type": "string" + }, + "sourceOfFunds": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualSourceOfFunds" + }, + "transactionVolume": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualTransactionVolume" + }, + "transactionVolumeDescription": { + "type": "string" + }, + "profession": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualProfession" + } }, "additionalProperties": false, "required": ["createdAt", "status", "fullName"] diff --git a/schemas/application/applicationMissingFields.json b/schemas/application/applicationMissingFields.json new file mode 100644 index 0000000..a4f54f8 --- /dev/null +++ b/schemas/application/applicationMissingFields.json @@ -0,0 +1,104 @@ +{ + "components": { + "schemas": { + "MissingField": { + "title": "Missing Field", + "type": "object", + "properties": { + "fieldName": { + "type": "string", + "description": "The name of the application field that is missing" + }, + "description": { + "type": "string", + "description": "Human-readable description which will indicate dependant fields that are also required" + } + }, + "required": ["fieldName", "description"], + "additionalProperties": false + }, + "IndividualApplicationMissingFields": { + "title": "Individual Application Missing Fields", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["individualApplicationMissingFields"], + "default": "individualApplicationMissingFields" + }, + "attributes": { + "type": "object", + "properties": { + "missingFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MissingField" + }, + "description": "An array of missing field objects. Empty when there are no missing fields." + } + }, + "required": ["missingFields"], + "additionalProperties": false + } + }, + "required": ["type", "attributes"], + "additionalProperties": false + }, + "BusinessApplicationMissingFields": { + "title": "Business Application Missing Fields", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["businessApplicationMissingFields"], + "default": "businessApplicationMissingFields" + }, + "attributes": { + "type": "object", + "properties": { + "missingFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MissingField" + }, + "description": "An array of missing field objects. Empty when there are no missing fields." + } + }, + "required": ["missingFields"], + "additionalProperties": false + } + }, + "required": ["type", "attributes"], + "additionalProperties": false + }, + "ApplicationMissingFields": { + "title": "Application Missing Fields", + "oneOf": [ + { + "$ref": "#/components/schemas/IndividualApplicationMissingFields" + }, + { + "$ref": "#/components/schemas/BusinessApplicationMissingFields" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "individualApplicationMissingFields": "#/components/schemas/IndividualApplicationMissingFields", + "businessApplicationMissingFields": "#/components/schemas/BusinessApplicationMissingFields" + } + } + }, + "UnitApplicationMissingFieldsResponse": { + "type": "object", + "title": "Unit Application Missing Fields Response", + "properties": { + "data": { + "$ref": "#/components/schemas/ApplicationMissingFields" + } + }, + "required": ["data"] + } + } + } +} diff --git a/schemas/application/applicationPaths.json b/schemas/application/applicationPaths.json index ef2cd10..5af6a29 100644 --- a/schemas/application/applicationPaths.json +++ b/schemas/application/applicationPaths.json @@ -850,5 +850,36 @@ } } } + }, + "applicationMissingFields": { + "get": { + "tags": ["unit"], + "operationId": "getApplicationMissingFields", + "summary": "Get Missing Fields by Application ID", + "description": "Get list of missing due diligence fields by application id", + "parameters": [ + { + "schema": { + "type": "string" + }, + "name": "applicationId", + "in": "path", + "required": true, + "description": "ID of the application to get missing fields for" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/vnd.api+json; charset=utf-8": { + "schema": { + "$ref": "./applicationMissingFields.json#/components/schemas/UnitApplicationMissingFieldsResponse" + } + } + } + } + } + } } } diff --git a/schemas/application/createApplication.json b/schemas/application/createApplication.json index a18109a..23026c6 100644 --- a/schemas/application/createApplication.json +++ b/schemas/application/createApplication.json @@ -404,11 +404,11 @@ "additionalProperties": false, "required": [ "fullName", + "title", "email", "phone", "address", - "dateOfBirth", - "occupation" + "dateOfBirth" ] }, "CreateBeneficialOwner": { @@ -446,7 +446,7 @@ }, "percentage": { "type": "integer", - "minimum": 0, + "minimum": 25, "maximum": 100 }, "EvaluationParams": { @@ -548,6 +548,9 @@ }, "sourceOfIncome": { "$ref": "../types.json#/components/schemas/SourceOfIncome" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false, @@ -669,6 +672,9 @@ }, "website": { "type": "string" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false, @@ -900,6 +906,9 @@ }, "profession": { "$ref": "#/components/schemas/ThreadIndividualProfession" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false, @@ -1046,6 +1055,9 @@ }, "businessDescription": { "type": "string" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false, @@ -1058,7 +1070,7 @@ "accountPurpose", "sourceOfFunds", "transactionVolume", - "profession" + "businessIndustry" ] } }, @@ -1194,6 +1206,9 @@ }, "entityType": { "$ref": "../types.json#/components/schemas/ThreadApplicationEntityType" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false, @@ -1209,7 +1224,14 @@ "beneficialOwners", "accountPurpose", "sourceOfFunds", - "transactionVolume" + "transactionVolume", + "website", + "businessIndustry", + "businessDescription", + "isRegulated", + "usNexus", + "countriesOfOperation", + "yearOfIncorporation" ] } }, diff --git a/schemas/application/updateApplication.json b/schemas/application/updateApplication.json index a3aa081..cf1c133 100644 --- a/schemas/application/updateApplication.json +++ b/schemas/application/updateApplication.json @@ -24,6 +24,9 @@ }, "sourceOfIncome": { "$ref": "../types.json#/components/schemas/SourceOfIncome" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false @@ -70,6 +73,9 @@ "website": { "type": "string" }, "businessVertical": { "$ref": "../types.json#/components/schemas/BusinessVertical" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false @@ -135,6 +141,9 @@ }, "website": { "type": "string" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false @@ -191,6 +200,9 @@ "properties": { "tags": { "$ref": "../types.json#/components/schemas/Tags" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false @@ -213,6 +225,9 @@ "properties": { "tags": { "$ref": "../types.json#/components/schemas/Tags" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false @@ -235,6 +250,9 @@ "properties": { "tags": { "$ref": "../types.json#/components/schemas/Tags" + }, + "operatingAddress": { + "$ref": "../types.json#/components/schemas/Address" } }, "additionalProperties": false @@ -278,6 +296,217 @@ }, "additionalProperties": false, "required": ["data"] + }, + "UpgradeIndividualApplicationToThreadApplication": { + "title": "Upgrade Individual Application To Thread Application", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["individualApplication"], + "default": "individualApplication" + }, + "attributes": { + "type": "object", + "properties": { + "tags": { + "$ref": "../types.json#/components/schemas/Tags" + }, + "accountPurpose": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualAccountPurpose" + }, + "accountPurposeDescription": { + "type": "string" + }, + "sourceOfFunds": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualSourceOfFunds" + }, + "transactionVolume": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualTransactionVolume" + }, + "transactionVolumeDescription": { + "type": "string" + }, + "profession": { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualProfession" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["type", "attributes"] + }, + "UpgradeSoleProprietorApplicationToThreadApplication": { + "title": "Upgrade Sole Proprietor Application To Thread Application", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["individualApplication"], + "default": "individualApplication" + }, + "attributes": { + "type": "object", + "properties": { + "tags": { + "$ref": "../types.json#/components/schemas/Tags" + }, + "website": { + "type": "string" + }, + "sourceOfFunds": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessSourceOfFunds" + }, + "sourceOfFundsDescription": { + "type": "string" + }, + "businessIndustry": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessIndustry" + }, + "isIncorporated": { + "type": "boolean" + }, + "stateOfIncorporation": { + "type": "string", + "minLength": 2, + "maxLength": 2 + }, + "yearOfIncorporation": { + "$ref": "../types.json#/components/schemas/Year" + }, + "countriesOfOperation": { + "type": "array", + "items": { + "$ref": "../types.json#/components/schemas/Country" + }, + "minItems": 1 + }, + "usNexus": { + "type": "array", + "items": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessUsNexus" + } + }, + "transactionVolume": { + "$ref": "./createApplication.json#/components/schemas/ThreadSoleProprietorshipTransactionVolume" + }, + "transactionVolumeDescription": { + "type": "string" + }, + "accountPurpose": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessAccountPurpose" + }, + "accountPurposeDescription": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["type", "attributes"] + }, + "UpgradeBusinessApplicationToThreadApplication": { + "title": "Upgrade Business Application To Thread Application", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["businessApplication"], + "default": "businessApplication" + }, + "attributes": { + "type": "object", + "properties": { + "tags": { + "$ref": "../types.json#/components/schemas/Tags" + }, + "sourceOfFunds": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessSourceOfFunds" + }, + "sourceOfFundsDescription": { + "type": "string" + }, + "businessIndustry": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessIndustry" + }, + "businessDescription": { + "type": "string" + }, + "isRegulated": { + "type": "boolean" + }, + "regulatorName": { + "type": "string" + }, + "usNexus": { + "type": "array", + "items": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessUsNexus" + } + }, + "accountPurpose": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessAccountPurpose" + }, + "accountPurposeDescription": { + "type": "string" + }, + "transactionVolume": { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessTransactionVolume" + }, + "transactionVolumeDescription": { + "type": "string" + }, + "stockExchangeName": { + "type": "string" + }, + "stockSymbol": { + "type": "string" + }, + "countriesOfOperation": { + "type": "array", + "items": { + "$ref": "../types.json#/components/schemas/Country" + }, + "minItems": 1 + }, + "yearOfIncorporation": { + "$ref": "../types.json#/components/schemas/Year" + }, + "entityType": { + "$ref": "../types.json#/components/schemas/ThreadApplicationEntityType" + }, + "website": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["type", "attributes"] + }, + "UpgradeApplicationToThreadApplicationRequest": { + "title": "Upgrade Application To Thread Application", + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/UpgradeIndividualApplicationToThreadApplication" + }, + { + "$ref": "#/components/schemas/UpgradeSoleProprietorApplicationToThreadApplication" + }, + { + "$ref": "#/components/schemas/UpgradeBusinessApplicationToThreadApplication" + } + ] + } + }, + "additionalProperties": false, + "required": ["data"] } } } diff --git a/unit/e2e_tests/java/ApplicationTests.java b/unit/e2e_tests/java/ApplicationTests.java index b868a28..56842eb 100644 --- a/unit/e2e_tests/java/ApplicationTests.java +++ b/unit/e2e_tests/java/ApplicationTests.java @@ -3,20 +3,14 @@ import java.io.File; import java.io.InputStream; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.junit.Test; import static unit.java.sdk.TestHelpers.GenerateCreateIndividualApplicationRequest; import static unit.java.sdk.TestHelpers.GenerateCreateSoleProprietorApplicationRequest; import static unit.java.sdk.TestHelpers.GenerateCreateBusinessApplicationRequest; -import static unit.java.sdk.TestHelpers.GenerateCreateIndividualThreadApplicationRequest; -import static unit.java.sdk.TestHelpers.GenerateCreateBusinessThreadApplicationRequest; -import static unit.java.sdk.TestHelpers.GenerateCreateSoleProprietorThreadApplicationRequest; import static unit.java.sdk.TestHelpers.GenerateUnitApiClient; -import static unit.java.sdk.TestHelpers.GenerateThreadUnitApiClient; import unit.java.sdk.api.UnitApi; import unit.java.sdk.model.AnnualIncome; import unit.java.sdk.model.Application; @@ -31,7 +25,6 @@ import unit.java.sdk.model.CancelApplicationRequest; import unit.java.sdk.model.CancelApplicationRequestData; import unit.java.sdk.model.CancelApplicationRequestDataAttributes; -import unit.java.sdk.model.CreateApplicationRequest; import unit.java.sdk.model.CreateApplicationFormRequest; import unit.java.sdk.model.CreateApplicationFormRequestData; import unit.java.sdk.model.CreateApplicationFormRequestDataAttributes; @@ -53,6 +46,10 @@ import unit.java.sdk.model.UnitDocumentResponse; import unit.java.sdk.model.UnitListApplicationsResponse; import unit.java.sdk.model.UnitListDocumentsResponse; +import unit.java.sdk.model.UnitApplicationMissingFieldsResponse; +import unit.java.sdk.model.ApplicationMissingFields; +import unit.java.sdk.model.IndividualApplicationMissingFields; +import unit.java.sdk.model.BusinessApplicationMissingFields; import unit.java.sdk.model.UpdateApplicationRequest; import unit.java.sdk.model.UpdateApplicationRequestData; import unit.java.sdk.model.UpdateBusinessApplication; @@ -71,15 +68,9 @@ import unit.java.sdk.model.UploadApplicationDocumentContentType; import unit.java.sdk.model.CreateApplicationFormRequestDataAttributes.AllowedApplicationTypesEnum; import unit.java.sdk.model.CreateApplicationFormRequestDataAttributes.LangEnum; -// TODO: Fix after enum refactoring -import unit.java.sdk.model.UpdateIndividualThreadApplication; -import unit.java.sdk.model.UpdateIndividualThreadApplicationAttributes; -import unit.java.sdk.model.UpdateBusinessThreadApplication; -import unit.java.sdk.model.UpdateSoleProprietorThreadApplication; public class ApplicationTests { UnitApi unitApi = GenerateUnitApiClient(); - UnitApi threadUnitApi = GenerateThreadUnitApiClient(); @Test public void GetApplicationListApiTest() throws ApiException { @@ -458,104 +449,71 @@ public void GetApplicationFormByIdApiTest() throws ApiException { }); } - // Thread Application Tests - @Test - public void CreateIndividualThreadApplicationApiTest() throws ApiException { - UnitCreateApplicationResponse res = threadUnitApi.createApplication(GenerateCreateIndividualThreadApplicationRequest(null)); + public void GetIndividualApplicationMissingFieldsApiTest() throws ApiException { + UnitCreateApplicationResponse res = unitApi.createApplication(GenerateCreateIndividualApplicationRequest(null)); assert res.getData().getType().equals(Application.TypeEnum.INDIVIDUAL_APPLICATION); - - IndividualApplication individualApp = (IndividualApplication) res.getData(); - assert individualApp.getAttributes() != null; - } - @Test - public void CreateBusinessThreadApplicationApiTest() throws ApiException { - UnitCreateApplicationResponse res = threadUnitApi.createApplication(GenerateCreateBusinessThreadApplicationRequest()); - assert res.getData().getType().equals(Application.TypeEnum.BUSINESS_APPLICATION); + String applicationId = res.getData().getId(); + UnitApplicationMissingFieldsResponse missingFieldsResponse = unitApi.getApplicationMissingFields(applicationId); - BusinessApplication businessApp = (BusinessApplication) res.getData(); - assert businessApp.getAttributes() != null; - } - - @Test - public void CreateSoleProprietorThreadApplicationApiTest() throws ApiException { - UnitCreateApplicationResponse res = threadUnitApi.createApplication(GenerateCreateSoleProprietorThreadApplicationRequest()); - assert res.getData().getType().equals(Application.TypeEnum.INDIVIDUAL_APPLICATION); + assert missingFieldsResponse != null; + assert missingFieldsResponse.getData() != null; - IndividualApplication soleProprietorApp = (IndividualApplication) res.getData(); - assert soleProprietorApp.getAttributes() != null; - } - - @Test - public void UpdateIndividualThreadApplicationApiTest() throws ApiException { - UnitApi threadApi = GenerateThreadUnitApiClient(); - UnitCreateApplicationResponse res = threadApi.createApplication(GenerateCreateIndividualThreadApplicationRequest(null)); - assert res.getData().getType().equals(unit.java.sdk.model.Application.TypeEnum.INDIVIDUAL_APPLICATION); - - String applicationId = res.getData().getId(); + ApplicationMissingFields missingFields = missingFieldsResponse.getData(); + Object actualInstance = missingFields.getActualInstance(); + assert actualInstance instanceof IndividualApplicationMissingFields; - // Update with tags - UpdateIndividualThreadApplication body = new UpdateIndividualThreadApplication(); - UpdateIndividualThreadApplicationAttributes attributes = new UpdateIndividualThreadApplicationAttributes(); - Map tags = new HashMap<>(); - tags.put("testKey", "testValue"); - attributes.setTags(tags); - body.setAttributes(attributes); - - UpdateApplicationRequestData d = new UpdateApplicationRequestData(body); - UpdateApplicationRequest ua = new UpdateApplicationRequest(); - ua.data(d); - - UnitApplicationResponseWithIncluded res2 = threadApi.updateApplication(applicationId, ua); - assert res2.getData().getId().equals(applicationId); + IndividualApplicationMissingFields individualMissingFields = (IndividualApplicationMissingFields) actualInstance; + assert individualMissingFields.getType().equals(IndividualApplicationMissingFields.TypeEnum.INDIVIDUAL_APPLICATION_MISSING_FIELDS); } @Test - public void UpdateBusinessThreadApplicationApiTest() throws ApiException { - UnitApi threadApi = GenerateThreadUnitApiClient(); - UnitCreateApplicationResponse res = threadApi.createApplication(GenerateCreateBusinessThreadApplicationRequest()); - assert res.getData().getType().equals(unit.java.sdk.model.Application.TypeEnum.BUSINESS_APPLICATION); + public void GetBusinessApplicationMissingFieldsApiTest() throws ApiException { + UnitCreateApplicationResponse res = unitApi.createApplication(GenerateCreateBusinessApplicationRequest()); + assert res.getData().getType().equals(Application.TypeEnum.BUSINESS_APPLICATION); String applicationId = res.getData().getId(); + UnitApplicationMissingFieldsResponse missingFieldsResponse = unitApi.getApplicationMissingFields(applicationId); - // Update with tags - UpdateBusinessThreadApplication body = new UpdateBusinessThreadApplication(); - UpdateIndividualThreadApplicationAttributes attributes = new UpdateIndividualThreadApplicationAttributes(); - Map tags = new HashMap<>(); - tags.put("businessTag", "businessValue"); - attributes.setTags(tags); - body.setAttributes(attributes); - - UpdateApplicationRequestData d = new UpdateApplicationRequestData(body); - UpdateApplicationRequest ua = new UpdateApplicationRequest(); - ua.data(d); - - UnitApplicationResponseWithIncluded res2 = threadApi.updateApplication(applicationId, ua); - assert res2.getData().getId().equals(applicationId); + assert missingFieldsResponse != null; + assert missingFieldsResponse.getData() != null; + + ApplicationMissingFields missingFields = missingFieldsResponse.getData(); + Object actualInstance = missingFields.getActualInstance(); + assert actualInstance instanceof BusinessApplicationMissingFields; + + BusinessApplicationMissingFields businessMissingFields = (BusinessApplicationMissingFields) actualInstance; + assert businessMissingFields.getType().equals(BusinessApplicationMissingFields.TypeEnum.BUSINESS_APPLICATION_MISSING_FIELDS); } @Test - public void UpdateSoleProprietorThreadApplicationApiTest() throws ApiException { - UnitApi threadApi = GenerateThreadUnitApiClient(); - UnitCreateApplicationResponse res = threadApi.createApplication(GenerateCreateSoleProprietorThreadApplicationRequest()); - assert res.getData().getType().equals(unit.java.sdk.model.Application.TypeEnum.INDIVIDUAL_APPLICATION); - - String applicationId = res.getData().getId(); - - // Update with tags - UpdateSoleProprietorThreadApplication body = new UpdateSoleProprietorThreadApplication(); - UpdateIndividualThreadApplicationAttributes attributes = new UpdateIndividualThreadApplicationAttributes(); - Map tags = new HashMap<>(); - tags.put("soleProprietorTag", "soleProprietorValue"); - attributes.setTags(tags); - body.setAttributes(attributes); - - UpdateApplicationRequestData d = new UpdateApplicationRequestData(body); - UpdateApplicationRequest ua = new UpdateApplicationRequest(); - ua.data(d); + public void GetApplicationMissingFieldsFromListApiTest() throws ApiException { + ListPageParameters page = new ListPageParameters(); + page.setLimit(10); + UnitListApplicationsResponse response = unitApi.getApplicationsList(page, null, null); + assert !response.getData().isEmpty(); - UnitApplicationResponseWithIncluded res2 = threadApi.updateApplication(applicationId, ua); - assert res2.getData().getId().equals(applicationId); + response.getData().forEach(application -> { + try { + if (application == null) return; + + UnitApplicationMissingFieldsResponse missingFieldsResponse = unitApi.getApplicationMissingFields(application.getId()); + assert missingFieldsResponse != null; + assert missingFieldsResponse.getData() != null; + + ApplicationMissingFields missingFields = missingFieldsResponse.getData(); + Object actualInstance = missingFields.getActualInstance(); + + // Verify the response type matches the application type + if (application.getType().equals(Application.TypeEnum.INDIVIDUAL_APPLICATION)) { + assert actualInstance instanceof IndividualApplicationMissingFields; + } else if (application.getType().equals(Application.TypeEnum.BUSINESS_APPLICATION)) { + assert actualInstance instanceof BusinessApplicationMissingFields; + } + } catch (ApiException e) { + throw new RuntimeException(e); + } + }); } } \ No newline at end of file From 346c63564b8916de234fbd003ea5466cba8cf7e9 Mon Sep 17 00:00:00 2001 From: YegorZh Date: Mon, 23 Feb 2026 14:21:31 +0000 Subject: [PATCH 2/2] fix: test fixes --- schemas/application/application.json | 27 ++++- unit/e2e_tests/java/ApplicationTests.java | 137 ++++++++++++++++++++++ 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/schemas/application/application.json b/schemas/application/application.json index df1f5fb..233a231 100644 --- a/schemas/application/application.json +++ b/schemas/application/application.json @@ -669,16 +669,37 @@ }, "website": { "type": "string" }, "accountPurpose": { - "$ref": "./createApplication.json#/components/schemas/ThreadIndividualAccountPurpose" + "oneOf": [ + { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualAccountPurpose" + }, + { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessAccountPurpose" + } + ] }, "accountPurposeDetail": { "type": "string" }, "sourceOfFunds": { - "$ref": "./createApplication.json#/components/schemas/ThreadIndividualSourceOfFunds" + "oneOf": [ + { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualSourceOfFunds" + }, + { + "$ref": "./createApplication.json#/components/schemas/ThreadBusinessSourceOfFunds" + } + ] }, "transactionVolume": { - "$ref": "./createApplication.json#/components/schemas/ThreadIndividualTransactionVolume" + "oneOf": [ + { + "$ref": "./createApplication.json#/components/schemas/ThreadIndividualTransactionVolume" + }, + { + "$ref": "./createApplication.json#/components/schemas/ThreadSoleProprietorshipTransactionVolume" + } + ] }, "transactionVolumeDescription": { "type": "string" diff --git a/unit/e2e_tests/java/ApplicationTests.java b/unit/e2e_tests/java/ApplicationTests.java index 56842eb..d6b7882 100644 --- a/unit/e2e_tests/java/ApplicationTests.java +++ b/unit/e2e_tests/java/ApplicationTests.java @@ -3,14 +3,20 @@ import java.io.File; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.junit.Test; import static unit.java.sdk.TestHelpers.GenerateCreateIndividualApplicationRequest; import static unit.java.sdk.TestHelpers.GenerateCreateSoleProprietorApplicationRequest; import static unit.java.sdk.TestHelpers.GenerateCreateBusinessApplicationRequest; +import static unit.java.sdk.TestHelpers.GenerateCreateIndividualThreadApplicationRequest; +import static unit.java.sdk.TestHelpers.GenerateCreateSoleProprietorThreadApplicationRequest; +import static unit.java.sdk.TestHelpers.GenerateCreateBusinessThreadApplicationRequest; import static unit.java.sdk.TestHelpers.GenerateUnitApiClient; +import static unit.java.sdk.TestHelpers.GenerateThreadUnitApiClient; import unit.java.sdk.api.UnitApi; import unit.java.sdk.model.AnnualIncome; import unit.java.sdk.model.Application; @@ -65,12 +71,17 @@ import unit.java.sdk.model.UpdateIndividualApplicationAttributes; import unit.java.sdk.model.UpdateSoleProprietorApplication; import unit.java.sdk.model.UpdateSoleProprietorApplicationAttributes; +import unit.java.sdk.model.UpdateIndividualThreadApplication; +import unit.java.sdk.model.UpdateIndividualThreadApplicationAttributes; +import unit.java.sdk.model.UpdateBusinessThreadApplication; +import unit.java.sdk.model.UpdateSoleProprietorThreadApplication; import unit.java.sdk.model.UploadApplicationDocumentContentType; import unit.java.sdk.model.CreateApplicationFormRequestDataAttributes.AllowedApplicationTypesEnum; import unit.java.sdk.model.CreateApplicationFormRequestDataAttributes.LangEnum; public class ApplicationTests { UnitApi unitApi = GenerateUnitApiClient(); + UnitApi threadUnitApi = GenerateThreadUnitApiClient(); @Test public void GetApplicationListApiTest() throws ApiException { @@ -282,6 +293,33 @@ public void CreateBusinessApplicationApiTest() throws ApiException { assert res.getData().getType().equals(Application.TypeEnum.BUSINESS_APPLICATION); } + @Test + public void CreateIndividualThreadApplicationApiTest() throws ApiException { + UnitCreateApplicationResponse res = threadUnitApi.createApplication(GenerateCreateIndividualThreadApplicationRequest(null)); + assert res.getData().getType().equals(Application.TypeEnum.INDIVIDUAL_APPLICATION); + + IndividualApplication individualApp = (IndividualApplication) res.getData(); + assert individualApp.getAttributes() != null; + } + + @Test + public void CreateBusinessThreadApplicationApiTest() throws ApiException { + UnitCreateApplicationResponse res = threadUnitApi.createApplication(GenerateCreateBusinessThreadApplicationRequest()); + assert res.getData().getType().equals(Application.TypeEnum.BUSINESS_APPLICATION); + + BusinessApplication businessApp = (BusinessApplication) res.getData(); + assert businessApp.getAttributes() != null; + } + + @Test + public void CreateSoleProprietorThreadApplicationApiTest() throws ApiException { + UnitCreateApplicationResponse res = threadUnitApi.createApplication(GenerateCreateSoleProprietorThreadApplicationRequest()); + assert res.getData().getType().equals(Application.TypeEnum.INDIVIDUAL_APPLICATION); + + IndividualApplication soleProprietorApp = (IndividualApplication) res.getData(); + assert soleProprietorApp.getAttributes() != null; + } + @Test public void CancelApplicationApiTest() throws ApiException { UnitCreateApplicationResponse res = unitApi.createApplication(GenerateCreateIndividualApplicationRequest("000000004")); @@ -516,4 +554,103 @@ public void GetApplicationMissingFieldsFromListApiTest() throws ApiException { } }); } + + @Test + public void UpdateIndividualThreadApplicationApiTest() throws ApiException { + UnitApi threadApi = GenerateThreadUnitApiClient(); + UnitCreateApplicationResponse res = threadApi.createApplication(GenerateCreateIndividualThreadApplicationRequest(null)); + assert res.getData().getType().equals(Application.TypeEnum.INDIVIDUAL_APPLICATION); + + IndividualApplication individualApp = (IndividualApplication) res.getData(); + ApplicationStatus status = individualApp.getAttributes().getStatus(); + if (!status.equals(ApplicationStatus.APPROVED)) return; + + UpdateIndividualThreadApplication body = new UpdateIndividualThreadApplication(); + UpdateIndividualThreadApplicationAttributes attributes = new UpdateIndividualThreadApplicationAttributes(); + + // Set tags + Map tags = new HashMap<>(); + tags.put("testKey", "testValue"); + attributes.setTags(tags); + + body.setAttributes(attributes); + + UpdateApplicationRequestData d = new UpdateApplicationRequestData(body); + UpdateApplicationRequest ua = new UpdateApplicationRequest(); + ua.setData(d); + + UnitApplicationResponseWithIncluded app = threadApi.updateApplication(res.getData().getId(), ua); + assert app.getData().getId().equals(res.getData().getId()); + assert app.getData().getType().toString().toLowerCase() + .equals(app.getData().getClass().getSimpleName().toLowerCase()); + IndividualApplication resApplication = (IndividualApplication) app.getData(); + assert resApplication.getAttributes().getTags().containsKey("testKey"); + assert resApplication.getAttributes().getTags().get("testKey").equals("testValue"); + } + + @Test + public void UpdateSoleProprietorThreadApplicationApiTest() throws ApiException { + UnitApi threadApi = GenerateThreadUnitApiClient(); + UnitCreateApplicationResponse res = threadApi.createApplication(GenerateCreateSoleProprietorThreadApplicationRequest()); + assert res.getData().getType().equals(Application.TypeEnum.INDIVIDUAL_APPLICATION); + + IndividualApplication individualApp = (IndividualApplication) res.getData(); + ApplicationStatus status = individualApp.getAttributes().getStatus(); + if (!status.equals(ApplicationStatus.APPROVED)) return; + + UpdateSoleProprietorThreadApplication body = new UpdateSoleProprietorThreadApplication(); + UpdateIndividualThreadApplicationAttributes attributes = new UpdateIndividualThreadApplicationAttributes(); + + // Set tags + Map tags = new HashMap<>(); + tags.put("soleProprietorKey", "soleProprietorValue"); + attributes.setTags(tags); + + body.setAttributes(attributes); + + UpdateApplicationRequestData d = new UpdateApplicationRequestData(body); + UpdateApplicationRequest ua = new UpdateApplicationRequest(); + ua.setData(d); + + UnitApplicationResponseWithIncluded app = threadApi.updateApplication(res.getData().getId(), ua); + assert app.getData().getId().equals(res.getData().getId()); + assert app.getData().getType().toString().toLowerCase() + .equals(app.getData().getClass().getSimpleName().toLowerCase()); + IndividualApplication resApplication = (IndividualApplication) app.getData(); + assert resApplication.getAttributes().getTags().containsKey("soleProprietorKey"); + assert resApplication.getAttributes().getTags().get("soleProprietorKey").equals("soleProprietorValue"); + } + + @Test + public void UpdateBusinessThreadApplicationApiTest() throws ApiException { + UnitApi threadApi = GenerateThreadUnitApiClient(); + UnitCreateApplicationResponse res = threadApi.createApplication(GenerateCreateBusinessThreadApplicationRequest()); + assert res.getData().getType().equals(Application.TypeEnum.BUSINESS_APPLICATION); + + BusinessApplication businessApp = (BusinessApplication) res.getData(); + ApplicationStatus status = businessApp.getAttributes().getStatus(); + if (!status.equals(ApplicationStatus.APPROVED)) return; + + UpdateBusinessThreadApplication body = new UpdateBusinessThreadApplication(); + UpdateIndividualThreadApplicationAttributes attributes = new UpdateIndividualThreadApplicationAttributes(); + + // Set tags + Map tags = new HashMap<>(); + tags.put("businessKey", "businessValue"); + attributes.setTags(tags); + + body.setAttributes(attributes); + + UpdateApplicationRequestData d = new UpdateApplicationRequestData(body); + UpdateApplicationRequest ua = new UpdateApplicationRequest(); + ua.setData(d); + + UnitApplicationResponseWithIncluded app = threadApi.updateApplication(res.getData().getId(), ua); + assert app.getData().getId().equals(res.getData().getId()); + assert app.getData().getType().toString().toLowerCase() + .equals(app.getData().getClass().getSimpleName().toLowerCase()); + BusinessApplication resApplication = (BusinessApplication) app.getData(); + assert resApplication.getAttributes().getTags().containsKey("businessKey"); + assert resApplication.getAttributes().getTags().get("businessKey").equals("businessValue"); + } } \ No newline at end of file