diff --git a/finance/build.gradle.kts b/finance/build.gradle.kts new file mode 100644 index 0000000..e3a3a26 --- /dev/null +++ b/finance/build.gradle.kts @@ -0,0 +1,24 @@ +plugins { + kotlin("jvm") version "2.1.10" +} + +group = "ru.soune" +version = "1.0.0" + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2") + implementation("io.insert-koin:koin-core:4.1.1") + implementation("io.insert-koin:koin-core-jvm:4.1.1") +} + +tasks.test { + useJUnitPlatform() +} +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/finance/src/main/kotlin/Main.kt b/finance/src/main/kotlin/Main.kt new file mode 100644 index 0000000..4c1e045 --- /dev/null +++ b/finance/src/main/kotlin/Main.kt @@ -0,0 +1,5 @@ +package ru.soune + +fun main() { + println("Hello World!") +} \ No newline at end of file diff --git a/finance/src/main/kotlin/actions/NoCopyAction.kt b/finance/src/main/kotlin/actions/NoCopyAction.kt new file mode 100644 index 0000000..d3d4e8d --- /dev/null +++ b/finance/src/main/kotlin/actions/NoCopyAction.kt @@ -0,0 +1,3 @@ +package ru.soune.actions + +abstract class NoCopyAction \ No newline at end of file diff --git a/finance/src/main/kotlin/actions/free/NoCopyFreeAction.kt b/finance/src/main/kotlin/actions/free/NoCopyFreeAction.kt new file mode 100644 index 0000000..7182cea --- /dev/null +++ b/finance/src/main/kotlin/actions/free/NoCopyFreeAction.kt @@ -0,0 +1,5 @@ +package ru.soune.actions.free + +import ru.soune.actions.NoCopyAction + +sealed class NoCopyFreeAction : NoCopyAction() \ No newline at end of file diff --git a/finance/src/main/kotlin/actions/paid/NoCopyPaidAction.kt b/finance/src/main/kotlin/actions/paid/NoCopyPaidAction.kt new file mode 100644 index 0000000..bbf732b --- /dev/null +++ b/finance/src/main/kotlin/actions/paid/NoCopyPaidAction.kt @@ -0,0 +1,8 @@ +package ru.soune.actions.paid + +import ru.soune.actions.NoCopyAction + +sealed class NoCopyPaidAction : NoCopyAction() { + + abstract val cost: Double +} \ No newline at end of file diff --git a/referral/src/main/kotlin/Referral.kt b/referral/src/main/kotlin/Referral.kt new file mode 100644 index 0000000..0dd336b --- /dev/null +++ b/referral/src/main/kotlin/Referral.kt @@ -0,0 +1,13 @@ +package ru.soune + +interface Referral { + + val userId: String + val referralLink: String + val inviter: String? + val currentLevel: String + val totalIncome: Int + val availableIncome: Int + val holdBalance: Int + val active: Boolean +} \ No newline at end of file diff --git a/referral/src/main/kotlin/ReferralInvitee.kt b/referral/src/main/kotlin/ReferralInvitee.kt new file mode 100644 index 0000000..a8fb79b --- /dev/null +++ b/referral/src/main/kotlin/ReferralInvitee.kt @@ -0,0 +1,7 @@ +package ru.soune + +data class ReferralInvitee( + val email: String, + val isActive: Boolean, + val regDate: String, +) \ No newline at end of file diff --git a/referral/src/main/kotlin/ReferralLevel.kt b/referral/src/main/kotlin/ReferralLevel.kt new file mode 100644 index 0000000..bf12d5b --- /dev/null +++ b/referral/src/main/kotlin/ReferralLevel.kt @@ -0,0 +1,10 @@ +package ru.soune + +interface ReferralLevel { + val id: String + val name: String + val share: Int + val minInvitee: Int + val maxInvitee: Int + val next: String? +} diff --git a/referral/src/main/kotlin/ReferralLevelProvider.kt b/referral/src/main/kotlin/ReferralLevelProvider.kt new file mode 100644 index 0000000..e278633 --- /dev/null +++ b/referral/src/main/kotlin/ReferralLevelProvider.kt @@ -0,0 +1,11 @@ +package ru.soune + +interface ReferralLevelProvider { + + fun getAvailableReferralLevels(): List + + fun getInitialReferralLevelId(): String + + fun getReferralLevelById(levelId: String): ReferralLevel + +} \ No newline at end of file diff --git a/referral/src/main/kotlin/ReferralRepo.kt b/referral/src/main/kotlin/ReferralRepo.kt new file mode 100644 index 0000000..54a6c49 --- /dev/null +++ b/referral/src/main/kotlin/ReferralRepo.kt @@ -0,0 +1,33 @@ +package ru.soune + +interface ReferralRepo { + + fun getUserReferralLink(userId: String): String + + fun getUserIdByLink(link: String): String + + fun getInviterIdForUser(userId: String): String? + + fun getReferralLevelForUser(userId: String): String + + fun getReferralByUserId(userId: String): Referral + + fun getReferralInvitees(userId: String, pageSize: Int, pageNumber: Int): List + + // создаем новую запись в БД + fun createReferralEntity(entity: Referral) + + // прибавить к totalIncome и availableIncome значение transferAmount + fun increaseIncome(userId: String, transferAmount: Int) + + // установить active в true + fun activateUser(userId: String): Boolean + + // посчитать записи, у которых inviter == userId и active == true + fun getActiveInviteeForUser(userId: String): Int + + // посчитать записи, у которых inviter == userId + fun getTotalInviteeForUser(userId: String): Int + + fun upgradeReferralLevelForUser(userId: String, newLevelId: String) +} \ No newline at end of file diff --git a/referral/src/main/kotlin/ReferralService.kt b/referral/src/main/kotlin/ReferralService.kt new file mode 100644 index 0000000..bae3dc0 --- /dev/null +++ b/referral/src/main/kotlin/ReferralService.kt @@ -0,0 +1,67 @@ +package ru.soune + +class ReferralService( + private val referralLevelProvider: ReferralLevelProvider, + private val referralRepo: ReferralRepo, +) { + + fun onRegister(userId: String, inviterReferralLink: String?) { + val initialReferralLevel = referralLevelProvider.getInitialReferralLevelId() + val referralLink = referralRepo.getUserReferralLink(userId) + val inviter = inviterReferralLink?.let(referralRepo::getUserIdByLink) + + val referral = object : Referral { + override val userId = userId + override val referralLink = referralLink + override val inviter = inviter + override val currentLevel = initialReferralLevel + override val totalIncome = 0 + override val availableIncome = 0 + override val holdBalance: Int = 0 + override val active: Boolean = false + } + + referralRepo.createReferralEntity(referral) + } + + fun onUserAccountRefill(userId: String, transferAmount: Int) { + val wasActivated = referralRepo.activateUser(userId) + val inviterId = referralRepo.getInviterIdForUser(userId) ?: return + val currentInviterLevel = referralRepo.getReferralLevelForUser(inviterId) + .let { referralLevelProvider.getReferralLevelById(it) } + val reward = transferAmount * currentInviterLevel.share / 100 + + referralRepo.increaseIncome(inviterId, reward) + + if (!wasActivated) return + + val currentCount = referralRepo.getActiveInviteeForUser(inviterId) + val nextLevel = currentInviterLevel.next + + if (currentCount + 1 > currentInviterLevel.maxInvitee && nextLevel != null) { + referralRepo.upgradeReferralLevelForUser(inviterId, nextLevel) + } + } + + fun getReferralLevels(): List = + referralLevelProvider.getAvailableReferralLevels() + + + fun getReferralLevelForUser(userId: String): ReferralLevel = + referralRepo.getReferralLevelForUser(userId) + .let { referralLevelProvider.getReferralLevelById(it) } + + fun getReferralStatForUser(userId: String): ReferralStat { + var referral = referralRepo.getReferralByUserId(userId) + return ReferralStat( + totalInvitee = referralRepo.getTotalInviteeForUser(userId), + activeInvitee = referralRepo.getActiveInviteeForUser(userId), + totalIncome = referral.totalIncome, + availableIncome = referral.availableIncome, + holdBalance = referral.holdBalance, + ) + } + + fun getInviteeForUser(userId: String, pageSize: Int, pageNumber: Int): List = + referralRepo.getReferralInvitees(userId, pageSize, pageNumber) +} \ No newline at end of file diff --git a/referral/src/main/kotlin/ReferralStat.kt b/referral/src/main/kotlin/ReferralStat.kt new file mode 100644 index 0000000..554a723 --- /dev/null +++ b/referral/src/main/kotlin/ReferralStat.kt @@ -0,0 +1,9 @@ +package ru.soune + +data class ReferralStat( + val totalInvitee: Int, + val activeInvitee: Int, + val totalIncome: Int, + val availableIncome: Int, + val holdBalance: Int, +) \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 3d2f55e..f87c38a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,5 @@ plugins { } rootProject.name = 'no-copy' include 'referral' +include 'finance'