diff --git a/.github/workflows/dev-otc.yml b/.github/workflows/dev-otc.yml index 70e3993c9..22e22fff6 100644 --- a/.github/workflows/dev-otc.yml +++ b/.github/workflows/dev-otc.yml @@ -29,10 +29,9 @@ jobs: uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: - distribution: 'adopt' - java-package: jdk + distribution: temurin java-version: ${{ matrix.java }} - name: Fetch partners config diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 9ca8609d7..a0409266b 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -16,10 +16,9 @@ jobs: - name: Checkout Source Code uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: - distribution: 'adopt' - java-package: jdk + distribution: temurin java-version: ${{ matrix.java }} # cache: maven - name: Build diff --git a/.github/workflows/main-otc.yml b/.github/workflows/main-otc.yml index b515c0237..3710997fb 100644 --- a/.github/workflows/main-otc.yml +++ b/.github/workflows/main-otc.yml @@ -29,10 +29,9 @@ jobs: uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: - distribution: 'adopt' - java-package: jdk + distribution: temurin java-version: ${{ matrix.java }} - name: Fetch partners config diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a72b0f314..82ec98ee7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,10 +16,9 @@ jobs: - name: Checkout Source Code uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: - distribution: 'adopt' - java-package: jdk + distribution: temurin java-version: ${{ matrix.java }} # cache: maven - name: Build diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 04a1ab04d..74af2bad1 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -15,17 +15,16 @@ jobs: - name: Checkout Source Code uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: - distribution: 'adopt' - java-package: jdk + distribution: temurin java-version: ${{ matrix.java }} - # cache: maven - name: Build - run: mvn -B clean install -Potc + run: mvn -B clean install -Potc - name: Run Tests - run: mvn -B -Dskip.unit.tests=false surefire:test + run: mvn -B -Dskip.unit.tests=false surefire:test + - name: Build Docker images env: TAG: pr - run: docker compose -f docker-compose.build.yml build + run: docker compose -f docker-compose.build.yml build \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 28bb270ad..05f9a75c0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,10 +22,9 @@ jobs: - name: Checkout Source Code uses: actions/checkout@v2 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: - distribution: 'adopt' - java-package: jdk + distribution: temurin java-version: ${{ matrix.java }} # cache: maven - name: Build diff --git a/common/src/main/kotlin/co/nilin/opex/common/OpexError.kt b/common/src/main/kotlin/co/nilin/opex/common/OpexError.kt index 8fab4bbe5..a93fffd30 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/OpexError.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/OpexError.kt @@ -197,7 +197,8 @@ enum class OpexError(val code: Int, val message: String?, val status: HttpStatus CardIbanInfoInquiryError(13045, "Card-IBAN info inquiry failed", HttpStatus.INTERNAL_SERVER_ERROR), BankAccountAlreadyExist(13046, "Bank account already exist", HttpStatus.BAD_REQUEST), BankAccountNotFound(13047, "Bank account not found", HttpStatus.NOT_FOUND), - AddressBookNotFound(13048, "Address book not found", HttpStatus.NOT_FOUND) + AddressBookNotFound(13048, "Address book not found", HttpStatus.NOT_FOUND), + InvalidProfileData(13049, "Invalid profile data", HttpStatus.BAD_REQUEST) ; override fun code() = this.code diff --git a/docker-compose.yml b/docker-compose.yml index fb352af93..28eb44c63 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -569,6 +569,8 @@ services: - ADMIN_APPROVAL_PROFILE_COMPLETION_REQUEST=${ADMIN_APPROVAL_PROFILE_COMPLETION_REQUEST} - ADMIN_APPROVAL_BANK_ACCOUNT=${ADMIN_APPROVAL_BANK_ACCOUNT} - TOKEN_ISSUER_URL=${KC_ISSUER_URL} + - MOBILE_IDENTITY_INQUIRY=${MOBILE_IDENTITY_INQUIRY} + - PERSONAL_IDENTITY_INQUIRY=${PERSONAL_IDENTITY_INQUIRY} depends_on: - kafka-1 - kafka-2 diff --git a/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/service/ProfileManagement.kt b/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/service/ProfileManagement.kt index a833018b3..74df80086 100644 --- a/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/service/ProfileManagement.kt +++ b/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/service/ProfileManagement.kt @@ -13,6 +13,7 @@ import co.nilin.opex.profile.core.data.profile.* import co.nilin.opex.profile.core.spi.* import co.nilin.opex.profile.core.utils.handleComparativeError import co.nilin.opex.profile.core.utils.handleShahkarError +import co.nilin.opex.utility.error.data.OpexException import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.reactive.awaitFirst import org.slf4j.LoggerFactory @@ -29,10 +30,10 @@ class ProfileManagement( private val otpProxy: OtpProxy, private val inquiryProxy: InquiryProxy, - @Value("\${app.inquiry.mobile-indentiy}") + @Value("\${app.inquiry.mobile-identity}") private var mobileIdentityEnabled: Boolean, - @Value("\${app.inquiry.personal-indentiy}") + @Value("\${app.inquiry.personal-identity}") private var personalIdentityEnabled: Boolean, @Value("\${app.admin-approval.profile-completion-request}") @@ -164,16 +165,32 @@ class ProfileManagement( ) ) - validateInquiryResponses(shahkarResponse, comparativeResponse) + try { + validateInquiryResponses(shahkarResponse, comparativeResponse) + } catch (e: OpexException) { + if (!isAdminApprovalRequired || + (e.error != OpexError.ShahkarInquiryError && e.error != OpexError.ComparativeInquiryError) + ) throw e + } + + val shahkarRequested = isIranian && mobileIdentityEnabled + val comparativeRequested = isIranian && personalIdentityEnabled - if (isIranian && !isAdminApprovalRequired) - return approveProfileAutomatically(userId, completedProfile) + val shahkarOk = !shahkarRequested || (shahkarResponse != null && !shahkarResponse.isError()) + val comparativeOk = !comparativeRequested || (comparativeResponse != null && !comparativeResponse.isError()) - return requestAdminApproval(userId) + val allRequestedInquiriesOk = shahkarOk && comparativeOk + val anyInquiryRequested = shahkarRequested || comparativeRequested + return when { + !isAdminApprovalRequired -> approveProfileAutomatically(userId, completedProfile) + isAdminApprovalRequired && !anyInquiryRequested -> requestAdminApproval(userId) + isAdminApprovalRequired && allRequestedInquiriesOk -> approveProfileAutomatically(userId, completedProfile) + else -> requestAdminApproval(userId) // At least one active inquiry has failed. + } } - private suspend fun approveProfileAutomatically(userId: String, completedProfile: Profile): Profile { + private suspend fun approveProfileAutomatically(userId: String, completedProfile: Profile): Profile { kycLevelUpdatedPublisher.publish( KycLevelUpdatedEvent(userId, KycLevel.LEVEL_2, LocalDateTime.now()) ) diff --git a/profile/profile-app/src/main/resources/application.yml b/profile/profile-app/src/main/resources/application.yml index cc91c40fb..f4b00c7ab 100644 --- a/profile/profile-app/src/main/resources/application.yml +++ b/profile/profile-app/src/main/resources/application.yml @@ -63,8 +63,8 @@ app: auth-gateway: url: lb://opex-auth-gateway inquiry: - mobile-indentiy: true - personal-indentiy: false + mobile-identity: ${MOBILE_IDENTITY_INQUIRY} + personal-identity: ${PERSONAL_IDENTITY_INQUIRY} url: ${JIBIT_URL} api-key: ${JIBIT_API_KEY} secret-key: ${JIBIT_SECRET_KEY} diff --git a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt index 485305aa8..9b8486e8c 100644 --- a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt +++ b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt @@ -15,7 +15,7 @@ interface ProfileApprovalRequestRepository : ReactiveCrudRepository + ): Mono @Query( """ diff --git a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileRepository.kt b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileRepository.kt index e765ca535..45de9f700 100644 --- a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileRepository.kt +++ b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileRepository.kt @@ -17,6 +17,9 @@ interface ProfileRepository : ReactiveCrudRepository { fun findByUserId(userId: String): Mono + @Query("select * from profile where identifier = :identifier order by last_update_date desc limit 1") + fun findLatestByIdentifier(identifier: String ): Mono + @Query( """ SELECT * diff --git a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/imp/ProfileManagementImp.kt b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/imp/ProfileManagementImp.kt index 3c85109c0..d9c598a6c 100644 --- a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/imp/ProfileManagementImp.kt +++ b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/imp/ProfileManagementImp.kt @@ -19,7 +19,6 @@ import co.nilin.opex.profile.ports.postgres.model.entity.ProfileModel import co.nilin.opex.profile.ports.postgres.utils.RegexPatterns import co.nilin.opex.profile.ports.postgres.utils.toProfileModel import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.reactive.awaitFirstOrNull @@ -52,6 +51,12 @@ class ProfileManagementImp( val existingProfile = profileRepository.findByUserId(id)?.awaitFirstOrNull() ?: throw OpexError.ProfileNotfound.exception() + val latestProfileByIdentifier = profileRepository.findLatestByIdentifier(data.identifier).awaitFirstOrNull() + if (latestProfileByIdentifier != null && (latestProfileByIdentifier.status != + ProfileStatus.PROFILE_COMPLETED && latestProfileByIdentifier.status != + ProfileStatus.ADMIN_REJECTED) + ) throw OpexError.InvalidProfileData.exception() + val newProfileModel = data.toProfileModel( existing = existingProfile, mobileMatch = mobileIdentityMatch, diff --git a/profile/profile-ports/profile-postgres/src/main/resources/db/migration/V7__drop_profile_identifier_unique_constraint.sql b/profile/profile-ports/profile-postgres/src/main/resources/db/migration/V7__drop_profile_identifier_unique_constraint.sql new file mode 100644 index 000000000..5bfa0ebb8 --- /dev/null +++ b/profile/profile-ports/profile-postgres/src/main/resources/db/migration/V7__drop_profile_identifier_unique_constraint.sql @@ -0,0 +1,2 @@ +ALTER TABLE profile + DROP CONSTRAINT unique_identifier; \ No newline at end of file