Add new transaction types for stacking, as well as support for it in the PBT import

csv
Laurent 6 years ago
parent cdf38e1716
commit 4fbcae37fd
  1. 16
      app/src/main/AndroidManifest.xml
  2. 13
      app/src/main/java/net/pokeranalytics/android/model/migrations/Patcher.kt
  3. 11
      app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt
  4. 42
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt
  5. 31
      app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt
  6. 29
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt
  8. 3
      app/src/main/java/net/pokeranalytics/android/util/Preferences.kt
  9. 4
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt
  10. 2
      app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt
  11. 56
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  12. 11
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt
  13. 2
      app/src/main/res/values/strings.xml
  14. 5
      app/src/test/java/net/pokeranalytics/android/SavableEnumTest.kt

@ -39,16 +39,16 @@
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:launchMode="singleTop"> android:launchMode="singleTop">
<!--<intent-filter tools:ignore="AppLinkUrlError">--> <intent-filter tools:ignore="AppLinkUrlError">
<!--<action android:name="android.intent.action.VIEW" />--> <action android:name="android.intent.action.VIEW" />
<!--<category android:name="android.intent.category.DEFAULT" />--> <category android:name="android.intent.category.DEFAULT" />
<!--<data android:scheme="file" />--> <data android:scheme="file" />
<!--<data android:scheme="content" />--> <data android:scheme="content" />
<!--<data android:mimeType="text/comma-separated-values" />--> <data android:mimeType="text/comma-separated-values" />
<!--<data android:mimeType="text/csv" />--> <data android:mimeType="text/csv" />
<!--</intent-filter>--> </intent-filter>
</activity> </activity>

@ -5,6 +5,7 @@ import io.realm.Realm
import net.pokeranalytics.android.model.filter.Query import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.utils.Seed
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
class Patcher { class Patcher {
@ -23,6 +24,18 @@ class Patcher {
patchBlindFormat(context) patchBlindFormat(context)
} }
val realm = Realm.getDefaultInstance()
val lockedTypes = realm.where(TransactionType::class.java).equalTo("lock", true).findAll()
if (lockedTypes.size == 3) {
Preferences.executeOnce(Preferences.Keys.ADD_NEW_TRANSACTION_TYPES, context) {
val newTypes = arrayOf(TransactionType.Value.STACKING_INCOMING, TransactionType.Value.STACKING_OUTGOING)
Seed.createDefaultTransactionTypes(newTypes, context, realm)
patchBlindFormat(context)
}
}
realm.close()
} }
private fun patchBreaks() { private fun patchBreaks() {

@ -30,6 +30,17 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
companion object { companion object {
fun newInstance(realm: Realm, bankroll: Bankroll, date: Date? = null, type: TransactionType, amount: Double): Transaction {
val transaction = realm.copyToRealm(Transaction())
transaction.date = date ?: Date()
transaction.amount = amount
transaction.type = type
transaction.bankroll = bankroll
return transaction
}
val rowRepresentation: List<RowRepresentable> by lazy { val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.addAll(TransactionRow.values()) rows.addAll(TransactionRow.values())

@ -17,16 +17,28 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionTypeRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionTypeRow
import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import net.pokeranalytics.android.util.enumerations.IntSearchable
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable { open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable {
enum class Value(val additive: Boolean) : Localizable { enum class Value(override var uniqueIdentifier: Int, val additive: Boolean) : IntIdentifiable, Localizable {
WITHDRAWAL(false),
DEPOSIT(true), WITHDRAWAL(0, false),
BONUS(true); DEPOSIT(1, true),
BONUS(2, true),
STACKING_INCOMING(3, true),
STACKING_OUTGOING(4, false);
companion object : IntSearchable<Value> {
override fun valuesInternal(): Array<Value> {
return values()
}
}
override val resId: Int? override val resId: Int?
get() { get() {
@ -34,8 +46,11 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
WITHDRAWAL -> R.string.withdrawal WITHDRAWAL -> R.string.withdrawal
DEPOSIT -> R.string.deposit DEPOSIT -> R.string.deposit
BONUS -> R.string.bonus BONUS -> R.string.bonus
STACKING_INCOMING -> R.string.stacking_incoming
STACKING_OUTGOING -> R.string.stacking_outgoing
} }
} }
} }
companion object { companion object {
@ -47,13 +62,28 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
} }
fun getByValue(value: Value, realm: Realm): TransactionType { fun getByValue(value: Value, realm: Realm): TransactionType {
val type = realm.where(TransactionType::class.java).equalTo("kind", value.ordinal).findFirst() val type = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findFirst()
type?.let { type?.let {
return it return it
} }
throw PAIllegalStateException("Transaction type ${value.name} should exist in database!") throw PAIllegalStateException("Transaction type ${value.name} should exist in database!")
} }
fun getOrCreateByValue(realm: Realm, context: Context, value: Value): TransactionType {
val type = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findFirst()
type?.let {
return it
}
val tt = TransactionType()
tt.name = value.localizedTitle(context)
tt.additive = value.additive
tt.kind = value.uniqueIdentifier
tt.lock = true
return tt
}
} }
@Ignore @Ignore
@ -64,7 +94,7 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
/** /**
* The name of the transaction type * The name of the transaction type
*/ */
override var name: String = "" override var name: String = ""
/** /**

@ -12,11 +12,29 @@ import java.util.*
class Seed(var context:Context) : Realm.Transaction { class Seed(var context:Context) : Realm.Transaction {
companion object {
fun createDefaultTransactionTypes(values: Array<TransactionType.Value>, context: Context, realm: Realm) {
values.forEach { value ->
val existing = realm.where(TransactionType::class.java).equalTo("kind", value.uniqueIdentifier).findAll()
if (existing.isEmpty()) {
val type = TransactionType()
type.name = value.localizedTitle(context)
type.additive = value.additive
type.kind = value.uniqueIdentifier
type.lock = true
realm.insertOrUpdate(type)
}
}
}
}
override fun execute(realm: Realm) { override fun execute(realm: Realm) {
this.createDefaultGames(realm) this.createDefaultGames(realm)
this.createDefaultTournamentFeatures(realm) this.createDefaultTournamentFeatures(realm)
this.createDefaultCurrencyAndBankroll(realm) this.createDefaultCurrencyAndBankroll(realm)
this.createDefaultTransactionTypes(realm) createDefaultTransactionTypes(TransactionType.Value.values(), context, realm)
} }
private fun createDefaultTournamentFeatures(realm: Realm) { private fun createDefaultTournamentFeatures(realm: Realm) {
@ -56,15 +74,4 @@ class Seed(var context:Context) : Realm.Transaction {
} }
} }
private fun createDefaultTransactionTypes(realm: Realm) {
TransactionType.Value.values().forEachIndexed { index, value ->
val type = TransactionType()
type.name = value.localizedTitle(context)
type.additive = value.additive
type.kind = index
type.lock = true
realm.insertOrUpdate(type)
}
}
} }

@ -33,6 +33,8 @@ import net.pokeranalytics.android.ui.view.ContextMenuRecyclerView
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.extensions.count
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -277,18 +279,19 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
*/ */
private fun createNewSession(isTournament: Boolean, sessionId: String? = null, duplicate: Boolean = false) { private fun createNewSession(isTournament: Boolean, sessionId: String? = null, duplicate: Boolean = false) {
// val sessionCount = this.feedSessionAdapter.realmResults.size // if (!BuildConfig.DEBUG) {
// if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG val sessionCount = getRealm().count(Session::class.java)
//// Toast.makeText(context, "Please subscribe!", Toast.LENGTH_LONG).show() if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG
// BillingActivity.newInstanceForResult(this, true) BillingActivity.newInstanceForResult(this, true)
// return return
}
// } // }
// Keep commented code for special versions // Keep commented code for special versions
if (Date().after(betaLimitDate)) { // if (Date().after(betaLimitDate)) {
this.showEndOfBetaMessage() // this.showEndOfBetaMessage()
return // return
} // }
SessionActivity.newInstanceforResult( SessionActivity.newInstanceforResult(
this, this,
@ -305,10 +308,10 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
*/ */
private fun createNewTransaction() { private fun createNewTransaction() {
if (Date().after(betaLimitDate)) { // if (Date().after(betaLimitDate)) {
this.showEndOfBetaMessage() // this.showEndOfBetaMessage()
return // return
} // }
EditableDataActivity.newInstanceForResult(this, LiveData.TRANSACTION, null, RequestCode.NEW_TRANSACTION.value) EditableDataActivity.newInstanceForResult(this, LiveData.TRANSACTION, null, RequestCode.NEW_TRANSACTION.value)
} }

@ -52,8 +52,8 @@ enum class SettingRow : RowRepresentable {
rows.addAll(arrayListOf(BANKROLL_REPORT)) rows.addAll(arrayListOf(BANKROLL_REPORT))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information))
rows.addAll(arrayListOf(VERSION, RATE_APP, CONTACT_US, BUG_REPORT)) // rows.addAll(arrayListOf(VERSION, RATE_APP, CONTACT_US, BUG_REPORT))
// rows.addAll(arrayListOf(SUBSCRIPTION, VERSION, RATE_APP, CONTACT_US, BUG_REPORT)) rows.addAll(arrayListOf(SUBSCRIPTION, VERSION, RATE_APP, CONTACT_US, BUG_REPORT))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.follow_us)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.follow_us))
rows.addAll(arrayListOf(FOLLOW_US)) rows.addAll(arrayListOf(FOLLOW_US))

@ -33,7 +33,8 @@ class Preferences {
LATEST_PURCHASE("latestPurchase"), LATEST_PURCHASE("latestPurchase"),
PATCH_BREAK("patchBreaks"), PATCH_BREAK("patchBreaks"),
PATCH_TRANSACTION_TYPES_NAMES("patchTransactionTypesNames"), PATCH_TRANSACTION_TYPES_NAMES("patchTransactionTypesNames"),
PATCH_BLINDS_FORMAT("patchBlindFormat") PATCH_BLINDS_FORMAT("patchBlindFormat"),
ADD_NEW_TRANSACTION_TYPES("addNewTransactionTypes")
} }
enum class FeedMessage { enum class FeedMessage {

@ -40,6 +40,10 @@ abstract class DataCSVDescriptor<T : Identifiable>(source: DataSource, vararg el
return if (data != null) 1 else 0 return if (data != null) 1 else 0
} }
protected fun addAdditionallyCreatedIdentifiable(identifiable: Identifiable) {
this.realmModelIds.add(identifiable.objectIdentifier)
}
override fun cancel(realm: Realm) { override fun cancel(realm: Realm) {
if (realm.isInTransaction) { if (realm.isInTransaction) {

@ -45,6 +45,8 @@ class ProductCSVDescriptors {
SessionField.TournamentPosition("place"), SessionField.TournamentPosition("place"),
SessionField.TournamentName("mttname"), SessionField.TournamentName("mttname"),
SessionField.CurrencyCode("currency"), SessionField.CurrencyCode("currency"),
SessionField.StackingIn("sharesincomings"),
SessionField.StackingOut("sharesoutgoings"),
SessionField.CurrencyRate("exchangerate"), SessionField.CurrencyRate("exchangerate"),
SessionField.TableSize("tablesize") SessionField.TableSize("tablesize")
) )

@ -104,14 +104,13 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
if (DataUtils.transactionUnicityCheck(realm, date!!, amount, type)) { if (DataUtils.transactionUnicityCheck(realm, date!!, amount, type)) {
val transaction = realm.copyToRealm(Transaction()) val bankroll = Bankroll.getOrCreate(
transaction.date = date!! realm,
transaction.amount = amount currencyCode!!,
transaction.type = type currencyCode = currencyCode!!,
currencyRate = currencyRate
val bankroll = Bankroll.getOrCreate(realm, currencyCode!!, currencyCode = currencyCode!!, currencyRate = currencyRate) )
transaction.bankroll = bankroll return Transaction.newInstance(realm, bankroll, date!!, type, amount)
return transaction
} else { } else {
Timber.d("Transaction already exists") Timber.d("Transaction already exists")
} }
@ -130,11 +129,14 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
var endDate: Date? = null var endDate: Date? = null
var isLive = true var isLive = true
var bankrollName: String? = null var bankrollName = ""
var currencyCode: String? = null var currencyCode: String? = null
var currencyRate: Double? = null var currencyRate: Double? = null
var additionalBuyins = 0.0 // rebuy + addon var additionalBuyins = 0.0 // rebuy + addon
var stackingIn: Double? = null
var stackingOut: Double? = null
fields.forEach { field -> fields.forEach { field ->
this.fieldMapping[field]?.let { index -> this.fieldMapping[field]?.let { index ->
@ -158,7 +160,8 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
session.result?.buyin = buyin session.result?.buyin = buyin
if (session.type == Session.Type.TOURNAMENT.ordinal) { if (session.type == Session.Type.TOURNAMENT.ordinal) {
session.tournamentEntryFee = buyin session.tournamentEntryFee = buyin
} else {} } else {
}
} }
is SessionField.CashedOut -> session.result?.cashout = field.parse(value) is SessionField.CashedOut -> session.result?.cashout = field.parse(value)
is SessionField.SessionType -> { is SessionField.SessionType -> {
@ -177,12 +180,14 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
is SessionField.Game -> { is SessionField.Game -> {
if (value.isNotEmpty()) { if (value.isNotEmpty()) {
session.game = realm.getOrCreate(value) session.game = realm.getOrCreate(value)
} else { } } else {
}
} }
is SessionField.Location -> { is SessionField.Location -> {
if (value.isNotEmpty()) { if (value.isNotEmpty()) {
session.location = realm.getOrCreate(value) session.location = realm.getOrCreate(value)
} else { } } else {
}
} }
is SessionField.Bankroll -> bankrollName = value is SessionField.Bankroll -> bankrollName = value
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal
@ -200,7 +205,8 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
is SessionField.TournamentName -> { is SessionField.TournamentName -> {
if (value.isNotEmpty()) { if (value.isNotEmpty()) {
session.tournamentName = realm.getOrCreate(value) session.tournamentName = realm.getOrCreate(value)
} else { } } else {
}
} }
is SessionField.TournamentType -> session.tournamentType = is SessionField.TournamentType -> session.tournamentType =
TournamentType.getValueForLabel(value)?.ordinal TournamentType.getValueForLabel(value)?.ordinal
@ -208,6 +214,12 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
field.parse(value)?.toInt() field.parse(value)?.toInt()
is SessionField.CurrencyCode -> currencyCode = value is SessionField.CurrencyCode -> currencyCode = value
is SessionField.CurrencyRate -> currencyRate = field.parse(value) is SessionField.CurrencyRate -> currencyRate = field.parse(value)
is SessionField.StackingIn -> {
stackingIn = field.parse(value)
}
is SessionField.StackingOut -> {
stackingOut = field.parse(value)
}
else -> { else -> {
} }
} }
@ -215,11 +227,12 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
} }
if (bankrollName.isNullOrEmpty()) { if (bankrollName.isEmpty()) {
bankrollName = "Import" bankrollName = "Import"
} }
session.bankroll = Bankroll.getOrCreate(realm, bankrollName ?: "Import", isLive, currencyCode, currencyRate) val bankroll = Bankroll.getOrCreate(realm, bankrollName, isLive, currencyCode, currencyRate)
session.bankroll = bankroll
session.result?.buyin?.let { session.result?.buyin?.let {
session.result?.buyin = it + additionalBuyins session.result?.buyin = it + additionalBuyins
@ -233,6 +246,19 @@ class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean
val managedSession = realm.copyToRealm(session) val managedSession = realm.copyToRealm(session)
managedSession.startDate = startDate managedSession.startDate = startDate
managedSession.endDate = endDate managedSession.endDate = endDate
if (stackingIn != null && stackingIn != 0.0) {
val type = TransactionType.getByValue(TransactionType.Value.STACKING_INCOMING, realm)
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingIn!!)
this.addAdditionallyCreatedIdentifiable(transaction)
}
if (stackingOut != null && stackingOut != 0.0) {
val type = TransactionType.getByValue(TransactionType.Value.STACKING_OUTGOING, realm)
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!)
this.addAdditionallyCreatedIdentifiable(transaction)
}
return managedSession return managedSession
} else { } else {
Timber.d("Session already exists(count=$count): sd=$startDate, ed=$endDate, net=$net") Timber.d("Session already exists(count=$count): sd=$startDate, ed=$endDate, net=$net")

@ -94,6 +94,17 @@ sealed class SessionField {
override val numberFormat: String? = null override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class StackingIn(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberCSVField
data class StackingOut(
override var header: String,
override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null
) : NumberCSVField
data class Blind(override var header: String, override var callback: ((String) -> Pair<Double, Double>?)? = null) : data class Blind(override var header: String, override var callback: ((String) -> Pair<Double, Double>?)? = null) :
BlindCSVField BlindCSVField

@ -39,6 +39,8 @@
<string name="transaction_relationship_error">The item is used in one or more transactions&#8230;Please delete the linked transactions first</string> <string name="transaction_relationship_error">The item is used in one or more transactions&#8230;Please delete the linked transactions first</string>
<string name="imported">Imported</string> <string name="imported">Imported</string>
<string name="iap_session_message">You\'ve reached the maximum number of free sessions. Please subscribe for unlimited use and don\'t hesitate to tell us how you feel about your current experience!</string> <string name="iap_session_message">You\'ve reached the maximum number of free sessions. Please subscribe for unlimited use and don\'t hesitate to tell us how you feel about your current experience!</string>
<string name="stacking_incoming">Stacking incoming</string>
<string name="stacking_outgoing">Stacking outgoing</string>
<string name="address">Address</string> <string name="address">Address</string>
<string name="suggestions">Naming suggestions</string> <string name="suggestions">Naming suggestions</string>

@ -1,7 +1,9 @@
package net.pokeranalytics.android package net.pokeranalytics.android
import com.google.android.libraries.places.internal.it
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.Criteria import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.realm.TransactionType
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
@ -16,6 +18,9 @@ class SavableEnumTest {
val criteriaIds = Criteria.valuesInternal().map { it.uniqueIdentifier } val criteriaIds = Criteria.valuesInternal().map { it.uniqueIdentifier }
Assert.assertEquals(criteriaIds.toSet().size, criteriaIds.size) Assert.assertEquals(criteriaIds.toSet().size, criteriaIds.size)
val transactionTypeValueIds = TransactionType.Value.valuesInternal().map { it.uniqueIdentifier }
Assert.assertEquals(transactionTypeValueIds.toSet().size, transactionTypeValueIds.size)
} }
} }
Loading…
Cancel
Save