Skip to content

Commit 92220ec

Browse files
committed
feat: Add tax for tickets (#2120)
1 parent 7cecbd5 commit 92220ec

File tree

18 files changed

+2482
-30
lines changed

18 files changed

+2482
-30
lines changed

app/schemas/org.fossasia.openevent.general.OpenEventDatabase/9.json

Lines changed: 2199 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/java/org/fossasia/openevent/general/OpenEventDatabase.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import org.fossasia.openevent.general.event.Event
1515
import org.fossasia.openevent.general.event.EventDao
1616
import org.fossasia.openevent.general.event.EventIdConverter
1717
import org.fossasia.openevent.general.event.subtopic.EventSubTopicConverter
18+
import org.fossasia.openevent.general.event.tex.Tax
19+
import org.fossasia.openevent.general.event.tex.TaxDao
1820
import org.fossasia.openevent.general.event.topic.EventTopic
1921
import org.fossasia.openevent.general.event.topic.EventTopicConverter
2022
import org.fossasia.openevent.general.event.topic.EventTopicsDao
@@ -54,7 +56,7 @@ import org.fossasia.openevent.general.ticket.TicketIdConverter
5456
@Database(entities = [Event::class, User::class, SocialLink::class, Ticket::class, Attendee::class,
5557
EventTopic::class, Order::class, CustomForm::class, Speaker::class, SpeakerWithEvent::class, Sponsor::class,
5658
SponsorWithEvent::class, Session::class, SpeakersCall::class, Feedback::class, Notification::class,
57-
Settings::class, Proposal::class], version = 8)
59+
Settings::class, Proposal::class, Tax::class], version = 9)
5860
@TypeConverters(EventIdConverter::class, EventTopicConverter::class, EventTypeConverter::class,
5961
EventSubTopicConverter::class, TicketIdConverter::class, MicroLocationConverter::class, UserIdConverter::class,
6062
AttendeeIdConverter::class, ListAttendeeIdConverter::class, SessionTypeConverter::class, TrackConverter::class,
@@ -92,4 +94,6 @@ abstract class OpenEventDatabase : RoomDatabase() {
9294
abstract fun notificationDao(): NotificationDao
9395

9496
abstract fun settingsDao(): SettingsDao
97+
98+
abstract fun texDao(): TaxDao
9599
}

app/src/main/java/org/fossasia/openevent/general/attendees/AttendeeFragment.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ import kotlinx.android.synthetic.main.fragment_attendee.view.signInTextLayout
8888
import kotlinx.android.synthetic.main.fragment_attendee.view.signInLayout
8989
import kotlinx.android.synthetic.main.fragment_attendee.view.signOutLayout
9090
import kotlinx.android.synthetic.main.fragment_attendee.view.paymentTitle
91+
import kotlinx.android.synthetic.main.fragment_attendee.view.taxLayout
92+
import kotlinx.android.synthetic.main.fragment_attendee.view.taxPrice
93+
import kotlinx.android.synthetic.main.fragment_attendee.view.totalAmountLayout
94+
import kotlinx.android.synthetic.main.fragment_attendee.view.totalPrice
9195
import org.fossasia.openevent.general.BuildConfig
9296
import org.fossasia.openevent.general.R
9397
import org.fossasia.openevent.general.auth.User
@@ -313,6 +317,11 @@ class AttendeeFragment : Fragment(), ComplexBackPressFragment {
313317
rootView.ticketsRecycler.adapter = ticketsRecyclerAdapter
314318
rootView.ticketsRecycler.isNestedScrollingEnabled = false
315319

320+
rootView.taxLayout.isVisible = safeArgs.taxAmount > 0f
321+
rootView.taxPrice.text = "${safeArgs.currency}${"%.2f".format(safeArgs.taxAmount)}"
322+
rootView.totalAmountLayout.isVisible = safeArgs.amount > 0f
323+
rootView.totalPrice.text = "${safeArgs.currency}${"%.2f".format(safeArgs.amount)}"
324+
316325
rootView.ticketTableDetails.setOnClickListener {
317326
attendeeViewModel.ticketDetailsVisible = !attendeeViewModel.ticketDetailsVisible
318327
loadTicketDetailsTableUI(attendeeViewModel.ticketDetailsVisible)

app/src/main/java/org/fossasia/openevent/general/di/Modules.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ import org.fossasia.openevent.general.sessions.Session
7979
import org.fossasia.openevent.general.sessions.SessionApi
8080
import org.fossasia.openevent.general.sessions.SessionService
8181
import org.fossasia.openevent.general.event.faq.EventFAQViewModel
82+
import org.fossasia.openevent.general.event.tex.Tax
83+
import org.fossasia.openevent.general.event.tex.TaxApi
84+
import org.fossasia.openevent.general.event.tex.TaxService
8285
import org.fossasia.openevent.general.favorite.FavoriteEvent
8386
import org.fossasia.openevent.general.favorite.FavoriteEventApi
8487
import org.fossasia.openevent.general.feedback.FeedbackViewModel
@@ -209,6 +212,10 @@ val apiModule = module {
209212
val retrofit: Retrofit = get()
210213
retrofit.create(SettingsApi::class.java)
211214
}
215+
single {
216+
val retrofit: Retrofit = get()
217+
retrofit.create(TaxApi::class.java)
218+
}
212219

213220
factory { AuthHolder(get()) }
214221
factory { AuthService(get(), get(), get(), get(), get(), get(), get()) }
@@ -224,6 +231,7 @@ val apiModule = module {
224231
factory { NotificationService(get(), get()) }
225232
factory { FeedbackService(get(), get()) }
226233
factory { SettingsService(get(), get()) }
234+
factory { TaxService(get(), get()) }
227235
}
228236

229237
val viewModelModule = module {
@@ -241,7 +249,7 @@ val viewModelModule = module {
241249
viewModel { SearchLocationViewModel(get(), get()) }
242250
viewModel { SearchTimeViewModel(get()) }
243251
viewModel { SearchTypeViewModel(get(), get(), get()) }
244-
viewModel { TicketsViewModel(get(), get(), get(), get(), get()) }
252+
viewModel { TicketsViewModel(get(), get(), get(), get(), get(), get()) }
245253
viewModel { AboutEventViewModel(get(), get()) }
246254
viewModel { EventFAQViewModel(get(), get()) }
247255
viewModel { FavoriteEventsViewModel(get(), get(), get()) }
@@ -310,7 +318,7 @@ val networkModule = module {
310318
EventSubTopic::class.java, Feedback::class.java, Speaker::class.java, FavoriteEvent::class.java,
311319
Session::class.java, SessionType::class.java, MicroLocation::class.java, SpeakersCall::class.java,
312320
Sponsor::class.java, EventFAQ::class.java, Notification::class.java, Track::class.java,
313-
DiscountCode::class.java, Settings::class.java, Proposal::class.java)
321+
DiscountCode::class.java, Settings::class.java, Proposal::class.java, Tax::class.java)
314322

315323
Retrofit.Builder()
316324
.client(get())
@@ -408,4 +416,9 @@ val databaseModule = module {
408416
val database: OpenEventDatabase = get()
409417
database.settingsDao()
410418
}
419+
420+
factory {
421+
val database: OpenEventDatabase = get()
422+
database.texDao()
423+
}
411424
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.fossasia.openevent.general.event.tex
2+
3+
import androidx.room.ColumnInfo
4+
import androidx.room.Entity
5+
import androidx.room.PrimaryKey
6+
import com.fasterxml.jackson.databind.PropertyNamingStrategy
7+
import com.fasterxml.jackson.databind.annotation.JsonNaming
8+
import com.github.jasminb.jsonapi.IntegerIdHandler
9+
import com.github.jasminb.jsonapi.annotations.Id
10+
import com.github.jasminb.jsonapi.annotations.Relationship
11+
import com.github.jasminb.jsonapi.annotations.Type
12+
import org.fossasia.openevent.general.event.EventId
13+
14+
@Type("tax")
15+
@JsonNaming(PropertyNamingStrategy.KebabCaseStrategy::class)
16+
@Entity
17+
class Tax(
18+
@Id(IntegerIdHandler::class)
19+
@PrimaryKey
20+
val id: Int? = null,
21+
val name: String? = null,
22+
val rate: Float? = null,
23+
val taxId: String? = null,
24+
val registeredCompany: String? = null,
25+
val address: String? = null,
26+
val city: String? = null,
27+
val stare: String? = null,
28+
val zip: String? = null,
29+
val invoiceFooter: String? = null,
30+
val isInvoiceSend: Boolean = false,
31+
val isTaxIncludedInPrice: Boolean = false,
32+
val shouldSendInvoice: Boolean = false,
33+
@ColumnInfo(index = true)
34+
@Relationship("event")
35+
val eventId: EventId? = null
36+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.fossasia.openevent.general.event.tex
2+
3+
import io.reactivex.Single
4+
import retrofit2.http.GET
5+
import retrofit2.http.Path
6+
7+
interface TaxApi {
8+
9+
@GET("events/{event_identifier}/tax?include=event")
10+
fun getTaxDetails(@Path("event_identifier") identifier: String): Single<Tax>
11+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.fossasia.openevent.general.event.tex
2+
3+
import androidx.room.Dao
4+
import androidx.room.Insert
5+
import androidx.room.OnConflictStrategy
6+
import androidx.room.Query
7+
import io.reactivex.Single
8+
9+
@Dao
10+
interface TaxDao {
11+
12+
@Insert(onConflict = OnConflictStrategy.REPLACE)
13+
fun insertTax(tax: Tax)
14+
15+
@Query("SELECT * from Tax WHERE eventId = :eventId")
16+
fun getTaxDetails(eventId: Long): Single<Tax>
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.fossasia.openevent.general.event.tex
2+
3+
import io.reactivex.Single
4+
import timber.log.Timber
5+
6+
class TaxService(
7+
private val taxApi: TaxApi,
8+
private val taxDao: TaxDao
9+
) {
10+
11+
fun getTax(eventId: Long): Single<Tax> {
12+
return taxApi.getTaxDetails(eventId.toString())
13+
.onErrorResumeNext {
14+
Timber.e(it, "Error fetching tax")
15+
taxDao.getTaxDetails(eventId)
16+
}.map {
17+
taxDao.insertTax(it)
18+
it
19+
}
20+
}
21+
}

app/src/main/java/org/fossasia/openevent/general/ticket/TicketViewHolder.kt

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import kotlinx.android.synthetic.main.item_ticket.view.discountPrice
1717
import kotlinx.android.synthetic.main.item_ticket.view.donationInput
1818
import kotlinx.android.synthetic.main.item_ticket.view.orderQtySection
1919
import kotlinx.android.synthetic.main.item_ticket.view.priceSection
20+
import kotlinx.android.synthetic.main.item_ticket.view.taxInfo
2021
import org.fossasia.openevent.general.R
2122
import org.fossasia.openevent.general.data.Resource
2223
import kotlinx.android.synthetic.main.item_ticket.view.priceInfo
@@ -28,6 +29,7 @@ import kotlinx.android.synthetic.main.item_ticket.view.description
2829
import org.fossasia.openevent.general.discount.DiscountCode
2930
import org.fossasia.openevent.general.event.EventUtils
3031
import org.fossasia.openevent.general.event.EventUtils.getFormattedDate
32+
import org.fossasia.openevent.general.event.tex.Tax
3133
import org.threeten.bp.DateTimeUtils
3234
import java.util.Date
3335
import kotlin.collections.ArrayList
@@ -47,7 +49,8 @@ class TicketViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
4749
eventTimeZone: String?,
4850
ticketQuantity: Int,
4951
donationAmount: Float,
50-
discountCode: DiscountCode? = null
52+
discountCode: DiscountCode? = null,
53+
tax: Tax?
5154
) {
5255
itemView.ticketName.text = ticket.name
5356
setupTicketSaleDate(ticket, eventTimeZone)
@@ -76,6 +79,13 @@ class TicketViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
7679
itemView.orderRange.performClick()
7780
}
7881

82+
var ticketPrice = ticket.price
83+
if (tax?.rate != null) {
84+
val taxPrice = (ticketPrice * tax.rate / 100)
85+
ticketPrice += taxPrice
86+
itemView.taxInfo.text = "(+ $eventCurrency$taxPrice ${tax.name})"
87+
}
88+
7989
when (ticket.type) {
8090
TICKET_TYPE_DONATION -> {
8191
itemView.price.text = resource.getString(R.string.donation)
@@ -90,14 +100,14 @@ class TicketViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
90100
itemView.donationInput.isVisible = false
91101
}
92102
TICKET_TYPE_PAID -> {
93-
itemView.price.text = "$eventCurrency${"%.2f".format(ticket.price)}"
103+
itemView.price.text = "$eventCurrency${"%.2f".format(ticketPrice)}"
94104
itemView.priceSection.isVisible = true
95105
itemView.donationInput.isVisible = false
96106
}
97107
}
98108
setupQtyPicker(minQty, maxQty, selectedListener, ticket, ticketQuantity)
99109

100-
val priceInfo = "<b>${resource.getString(R.string.price)}:</b> ${itemView.price.text}"
110+
val priceInfo = "<b>${resource.getString(R.string.price)}:</b> ${ticket.price}"
101111
itemView.priceInfo.text = Html.fromHtml(priceInfo)
102112

103113
if (ticket.description.isNullOrEmpty()) {
@@ -111,8 +121,8 @@ class TicketViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
111121
itemView.discountPrice.visibility = View.VISIBLE
112122
itemView.price.paintFlags = Paint.STRIKE_THRU_TEXT_FLAG
113123
itemView.discountPrice.text =
114-
if (discountCode.type == AMOUNT) "$eventCurrency${ticket.price - discountCode.value}"
115-
else "$eventCurrency${"%.2f".format(ticket.price - (ticket.price * discountCode.value / 100))}"
124+
if (discountCode.type == AMOUNT) "$eventCurrency${ticketPrice - discountCode.value}"
125+
else "$eventCurrency${"%.2f".format(ticketPrice - (ticketPrice * discountCode.value / 100))}"
116126
}
117127
}
118128

app/src/main/java/org/fossasia/openevent/general/ticket/TicketsFragment.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class TicketsFragment : Fragment() {
137137

138138
rootView.retry.setOnClickListener {
139139
loadTickets()
140+
loadTaxDetails()
140141
}
141142

142143
rootView.applyDiscountCode.setOnClickListener {
@@ -177,7 +178,10 @@ class TicketsFragment : Fragment() {
177178
ticketsViewModel.connection
178179
.nonNull()
179180
.observe(viewLifecycleOwner, Observer { isConnected ->
180-
loadTickets()
181+
if (isConnected) {
182+
loadTickets()
183+
loadTaxDetails()
184+
}
181185
showNoInternetScreen(!isConnected && ticketsViewModel.tickets.value == null)
182186
})
183187

@@ -220,6 +224,7 @@ class TicketsFragment : Fragment() {
220224
ticketIdAndQty = wrappedTicketAndQty,
221225
currency = safeArgs.currency,
222226
amount = totalAmount,
227+
taxAmount = ticketsViewModel.totalTaxAmount,
223228
hasPaidTickets = ticketsViewModel.hasPaidTickets
224229
))
225230
ticketsViewModel.hasPaidTickets = false
@@ -295,6 +300,17 @@ class TicketsFragment : Fragment() {
295300
}
296301
}
297302

303+
private fun loadTaxDetails() {
304+
ticketsViewModel.getTaxDetails(safeArgs.eventId)
305+
ticketsViewModel.taxInfo
306+
.nonNull()
307+
.observe(viewLifecycleOwner, Observer {
308+
ticketsRecyclerAdapter.applyTax(it)
309+
ticketsRecyclerAdapter.notifyDataSetChanged()
310+
ticketsViewModel.tax = it
311+
})
312+
}
313+
298314
private fun showNoInternetScreen(show: Boolean) {
299315
rootView.noInternetCard.isVisible = show
300316
rootView.ticketTableHeader.isVisible = !show

0 commit comments

Comments
 (0)