Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a1b57f90fd | ||
|
e086b3a04b | ||
|
ed634ebd21 | ||
|
c74b39e692 | ||
|
ebade00c96 | ||
|
9a9b066120 | ||
|
710b20c3af | ||
|
105378ca52 |
@ -3,20 +3,7 @@
|
||||
<component name="deploymentTargetDropDown">
|
||||
<value>
|
||||
<entry key="app">
|
||||
<State>
|
||||
<targetSelectedWithDropDown>
|
||||
<Target>
|
||||
<type value="QUICK_BOOT_TARGET" />
|
||||
<deviceKey>
|
||||
<Key>
|
||||
<type value="VIRTUAL_DEVICE_PATH" />
|
||||
<value value="$USER_HOME$/.android/avd/Pixel_7_API_33.avd" />
|
||||
</Key>
|
||||
</deviceKey>
|
||||
</Target>
|
||||
</targetSelectedWithDropDown>
|
||||
<timeTargetWasSelectedWithDropDown value="2023-12-20T08:37:35.519292927Z" />
|
||||
</State>
|
||||
<State />
|
||||
</entry>
|
||||
</value>
|
||||
</component>
|
||||
|
@ -11,7 +11,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.zyzf.coffeepreorder"
|
||||
minSdk = 24
|
||||
minSdk = 26
|
||||
targetSdk = 33
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
@ -2,7 +2,12 @@ package com.zyzf.coffeepreorder.api
|
||||
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import com.zyzf.coffeepreorder.api.model.CoffeeRemote
|
||||
import com.zyzf.coffeepreorder.api.model.OrderCoffeeCrossRefRemote
|
||||
import com.zyzf.coffeepreorder.api.model.OrderCoffeeRemote
|
||||
import com.zyzf.coffeepreorder.api.model.OrderRemote
|
||||
import com.zyzf.coffeepreorder.api.model.UserRemote
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
@ -77,8 +82,44 @@ interface MyServerService {
|
||||
@Path("id") id: Int,
|
||||
): CoffeeRemote
|
||||
|
||||
@GET("order/byDate")
|
||||
suspend fun getOrdersByDate(
|
||||
@Query("startDate") startDate: String,
|
||||
@Query("endDate") endDate: String,
|
||||
): List<OrderCoffeeRemote>
|
||||
|
||||
@POST("order/")
|
||||
suspend fun createOrder(
|
||||
@Body order: OrderRemote,
|
||||
): OrderRemote
|
||||
|
||||
@GET("order/byUser")
|
||||
suspend fun getOrdersByUser(
|
||||
@Query("userId") userId: Int,
|
||||
@Query("pageNo") page: Int,
|
||||
@Query("pageSize") limit: Int,
|
||||
): List<OrderRemote>
|
||||
|
||||
@GET("order/coffeesByOrder")
|
||||
suspend fun getCoffeesByOrder(
|
||||
@Query("orderId") orderId: Int,
|
||||
): List<CoffeeRemote>
|
||||
|
||||
@GET("order/coffeeCrossRef")
|
||||
suspend fun getOrderCoffees(): List<OrderCoffeeCrossRefRemote>
|
||||
|
||||
@POST("order/coffeeCrossRef")
|
||||
suspend fun createOrderCoffee(
|
||||
@Body orderCoffee: OrderCoffeeCrossRefRemote,
|
||||
)
|
||||
|
||||
@DELETE("order/coffeeCrossRef/{id}")
|
||||
suspend fun deleteOrderCoffee(
|
||||
@Path("id") id: Int,
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "http://192.168.0.100:8080/api/"
|
||||
private const val BASE_URL = "https://api.zyzf.space/api/"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: MyServerService? = null
|
||||
|
@ -63,7 +63,7 @@ class CoffeeRemoteMediator(
|
||||
val nextKey = if (endOfPaginationReached) null else page + 1
|
||||
val keys = coffees.map {
|
||||
RemoteKeys(
|
||||
entityId = it.uid,
|
||||
entityId = it.coffeeId,
|
||||
type = RemoteKeyType.COFFEE,
|
||||
prevKey = prevKey,
|
||||
nextKey = nextKey
|
||||
@ -83,14 +83,14 @@ class CoffeeRemoteMediator(
|
||||
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Coffee>): RemoteKeys? {
|
||||
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
|
||||
?.let { coffee ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.COFFEE)
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(coffee.coffeeId, RemoteKeyType.COFFEE)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Coffee>): RemoteKeys? {
|
||||
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
|
||||
?.let { coffee ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.COFFEE)
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(coffee.coffeeId, RemoteKeyType.COFFEE)
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ class CoffeeRemoteMediator(
|
||||
state: PagingState<Int, Coffee>
|
||||
): RemoteKeys? {
|
||||
return state.anchorPosition?.let { position ->
|
||||
state.closestItemToPosition(position)?.uid?.let { coffeeUid ->
|
||||
state.closestItemToPosition(position)?.coffeeId?.let { coffeeUid ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(coffeeUid, RemoteKeyType.COFFEE)
|
||||
}
|
||||
}
|
||||
|
@ -47,14 +47,14 @@ class RestCoffeeRepository(
|
||||
service.getCoffee(uid).toCoffee()
|
||||
|
||||
override suspend fun insert(coffee: Coffee): Long {
|
||||
return service.createCoffee(coffee.toCoffeeRemote()).toCoffee().uid.toLong()
|
||||
return service.createCoffee(coffee.toCoffeeRemote()).toCoffee().coffeeId.toLong()
|
||||
}
|
||||
|
||||
override suspend fun update(coffee: Coffee): Int {
|
||||
return service.updateCoffee(coffee.uid, coffee.toCoffeeRemote()).toCoffee().uid
|
||||
return service.updateCoffee(coffee.coffeeId, coffee.toCoffeeRemote()).toCoffee().coffeeId
|
||||
}
|
||||
|
||||
override suspend fun delete(coffee: Coffee) {
|
||||
service.deleteCoffee(coffee.uid).toCoffee()
|
||||
service.deleteCoffee(coffee.coffeeId).toCoffee()
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ fun CoffeeRemote.toCoffee(): Coffee = Coffee(
|
||||
)
|
||||
|
||||
fun Coffee.toCoffeeRemote(): CoffeeRemote = CoffeeRemote(
|
||||
uid,
|
||||
coffeeId,
|
||||
name,
|
||||
cost,
|
||||
ingredients
|
||||
|
@ -0,0 +1,23 @@
|
||||
package com.zyzf.coffeepreorder.api.model
|
||||
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class OrderCoffeeCrossRefRemote(
|
||||
val orderId: Int = 0,
|
||||
val coffeeId: Int = 0,
|
||||
val count: Int = 0
|
||||
)
|
||||
|
||||
fun OrderCoffeeCrossRefRemote.toOrderCoffeeCrossRef(): OrderCoffeeCrossRef = OrderCoffeeCrossRef(
|
||||
orderId,
|
||||
coffeeId,
|
||||
count
|
||||
)
|
||||
|
||||
fun OrderCoffeeCrossRef.toOrderCoffeeCrossRefRemote(): OrderCoffeeCrossRefRemote = OrderCoffeeCrossRefRemote(
|
||||
orderId,
|
||||
coffeeId,
|
||||
count
|
||||
)
|
@ -0,0 +1,27 @@
|
||||
package com.zyzf.coffeepreorder.api.model
|
||||
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class OrderCoffeeRemote(
|
||||
val order: OrderRemote = OrderRemote(),
|
||||
val coffees: List<Pair<CoffeeRemote, Int>> = listOf()
|
||||
)
|
||||
|
||||
fun OrderCoffeeRemote.toOrderWithCoffees(): OrderWithCoffees {
|
||||
val convertedOrder = this.order.toOrder()
|
||||
val convertedCoffees: List<Coffee> = this.coffees.map { it.first.toCoffee() }
|
||||
val convertedCounts: List<Int> = this.coffees.map { it.second }
|
||||
return OrderWithCoffees(convertedOrder, order.user.toUser(), convertedCoffees, convertedCounts)
|
||||
}
|
||||
|
||||
fun OrderWithCoffees.toOrderCoffeeRemote(): OrderCoffeeRemote {
|
||||
val convertedOrder = this.order.toOrderRemote()
|
||||
var convertedCoffees = ArrayList<Pair<CoffeeRemote, Int>>()
|
||||
for (i in (0..this.coffees.count()-1)) {
|
||||
convertedCoffees.add(Pair(this.coffees[i].toCoffeeRemote(), this.counts[i]))
|
||||
}
|
||||
return OrderCoffeeRemote(convertedOrder, convertedCoffees)
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.zyzf.coffeepreorder.api.model
|
||||
|
||||
import com.zyzf.coffeepreorder.api.MyServerService
|
||||
import com.zyzf.coffeepreorder.api.user.RestUserRepository
|
||||
import com.zyzf.coffeepreorder.database.AppContainer
|
||||
import com.zyzf.coffeepreorder.database.AppDataContainer
|
||||
import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.database.model.User
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class OrderRemote(
|
||||
val id: Int = 0,
|
||||
val date: String = "",
|
||||
val user: UserRemote = User.getUser().toUserRemote(),
|
||||
val sum: Double = 0.0
|
||||
)
|
||||
|
||||
fun OrderRemote.toOrder(): Order = Order(
|
||||
id,
|
||||
date,
|
||||
user.id,
|
||||
sum
|
||||
)
|
||||
|
||||
fun Order.toOrderRemote(): OrderRemote = OrderRemote(
|
||||
orderId,
|
||||
date,
|
||||
temp(userId),
|
||||
sum
|
||||
)
|
||||
|
||||
private fun temp(userId: Int): UserRemote {
|
||||
var user: UserRemote? = null
|
||||
runBlocking {
|
||||
user = MyServerService.getInstance().getUser(userId)
|
||||
}
|
||||
return user!!
|
||||
}
|
@ -23,7 +23,7 @@ fun UserRemote.toUser(): User = User(
|
||||
)
|
||||
|
||||
fun User.toUserRemote(): UserRemote = UserRemote(
|
||||
uid,
|
||||
userId,
|
||||
login,
|
||||
fio,
|
||||
phone,
|
||||
|
@ -0,0 +1,111 @@
|
||||
package com.zyzf.coffeepreorder.api.order
|
||||
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.LoadType
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.RemoteMediator
|
||||
import androidx.room.withTransaction
|
||||
import com.zyzf.coffeepreorder.CoffeeApplication
|
||||
import com.zyzf.coffeepreorder.api.MyServerService
|
||||
import com.zyzf.coffeepreorder.api.model.toCoffee
|
||||
import com.zyzf.coffeepreorder.api.model.toOrder
|
||||
import com.zyzf.coffeepreorder.database.AppContainer
|
||||
import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import com.zyzf.coffeepreorder.database.model.RemoteKeyType
|
||||
import com.zyzf.coffeepreorder.database.model.RemoteKeys
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineOrderRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
class OrderRemoteMediator(
|
||||
private val service: MyServerService,
|
||||
private val dbOrderRepository: OfflineOrderRepository,
|
||||
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
|
||||
private val database: AppDatabase
|
||||
) : RemoteMediator<Int, Order>() {
|
||||
|
||||
override suspend fun initialize(): InitializeAction {
|
||||
return InitializeAction.LAUNCH_INITIAL_REFRESH
|
||||
}
|
||||
|
||||
override suspend fun load(
|
||||
loadType: LoadType,
|
||||
state: PagingState<Int, Order>
|
||||
): MediatorResult {
|
||||
val page = when (loadType) {
|
||||
LoadType.REFRESH -> {
|
||||
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
|
||||
remoteKeys?.nextKey?.minus(1) ?: 1
|
||||
}
|
||||
|
||||
LoadType.PREPEND -> {
|
||||
val remoteKeys = getRemoteKeyForFirstItem(state)
|
||||
remoteKeys?.prevKey
|
||||
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
|
||||
}
|
||||
|
||||
LoadType.APPEND -> {
|
||||
val remoteKeys = getRemoteKeyForLastItem(state)
|
||||
remoteKeys?.nextKey
|
||||
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
val orders = service.getOrdersByUser(CoffeeApplication.currentUser!!.userId, page, state.config.pageSize).map { it.toOrder() }
|
||||
val endOfPaginationReached = orders.isEmpty()
|
||||
database.withTransaction {
|
||||
if (loadType == LoadType.REFRESH) {
|
||||
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.ORDER)
|
||||
dbOrderRepository.deleteAll()
|
||||
}
|
||||
val prevKey = if (page == 1) null else page - 1
|
||||
val nextKey = if (endOfPaginationReached) null else page + 1
|
||||
val keys = orders.map {
|
||||
RemoteKeys(
|
||||
entityId = it.orderId,
|
||||
type = RemoteKeyType.ORDER,
|
||||
prevKey = prevKey,
|
||||
nextKey = nextKey
|
||||
)
|
||||
}
|
||||
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||
dbOrderRepository.insertOrders(orders)
|
||||
}
|
||||
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
|
||||
} catch (exception: IOException) {
|
||||
return MediatorResult.Error(exception)
|
||||
} catch (exception: HttpException) {
|
||||
return MediatorResult.Error(exception)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Order>): RemoteKeys? {
|
||||
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
|
||||
?.let { order ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(order.orderId, RemoteKeyType.ORDER)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Order>): RemoteKeys? {
|
||||
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
|
||||
?.let { order ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(order.orderId, RemoteKeyType.ORDER)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyClosestToCurrentPosition(
|
||||
state: PagingState<Int, Order>
|
||||
): RemoteKeys? {
|
||||
return state.anchorPosition?.let { position ->
|
||||
state.closestItemToPosition(position)?.orderId?.let { orderUid ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(orderUid, RemoteKeyType.ORDER)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.zyzf.coffeepreorder.api.order
|
||||
|
||||
import android.util.Log
|
||||
import com.zyzf.coffeepreorder.api.MyServerService
|
||||
import com.zyzf.coffeepreorder.api.model.toOrderCoffeeCrossRef
|
||||
import com.zyzf.coffeepreorder.api.model.toOrderCoffeeCrossRefRemote
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineOrderWithCoffeesRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OrderWithCoffeesRepository
|
||||
|
||||
class RestOrderCoffeesRepository (
|
||||
private val service: MyServerService,
|
||||
private val dbOrderCoffeeRepository: OfflineOrderWithCoffeesRepository,
|
||||
): OrderWithCoffeesRepository {
|
||||
override suspend fun getAll(): List<OrderCoffeeCrossRef> {
|
||||
Log.d(RestOrderCoffeesRepository::class.simpleName, "Get OrderCoffees")
|
||||
|
||||
val existOrderCoffees = dbOrderCoffeeRepository.getAll().toMutableList()
|
||||
val serverOrderCoffees = service.getOrderCoffees().map { it.toOrderCoffeeCrossRef() }
|
||||
|
||||
// Найти записи для удаления (те, что есть в БД, но отсутствуют на сервере)
|
||||
val toDelete = existOrderCoffees.filterNot { serverOrderCoffees.contains(it) }
|
||||
toDelete.forEach { dbOrderCoffeeRepository.delete(it) }
|
||||
|
||||
// Найти новые записи для добавления (те, что есть на сервере, но отсутствуют в БД)
|
||||
val toAdd = serverOrderCoffees.filterNot { existOrderCoffees.contains(it) }
|
||||
toAdd.forEach { dbOrderCoffeeRepository.insert(it) }
|
||||
|
||||
// Вернуть обновленный список записей из БД
|
||||
return dbOrderCoffeeRepository.getAll()
|
||||
}
|
||||
override suspend fun insert(orderCoffee: OrderCoffeeCrossRef) {
|
||||
service.createOrderCoffee(orderCoffee.toOrderCoffeeCrossRefRemote())
|
||||
}
|
||||
|
||||
override suspend fun delete(orderCoffee: OrderCoffeeCrossRef) {
|
||||
service.deleteOrderCoffee(orderCoffee.orderId)
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.zyzf.coffeepreorder.api.order
|
||||
|
||||
import android.util.Log
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.zyzf.coffeepreorder.api.MyServerService
|
||||
import com.zyzf.coffeepreorder.api.model.toCoffee
|
||||
import com.zyzf.coffeepreorder.api.model.toOrder
|
||||
import com.zyzf.coffeepreorder.api.model.toOrderRemote
|
||||
import com.zyzf.coffeepreorder.api.model.toOrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.database.AppContainer
|
||||
import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineOrderRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OrderRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
class RestOrderRepository(
|
||||
private val service: MyServerService,
|
||||
private val dbOrderRepository: OfflineOrderRepository,
|
||||
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
|
||||
private val database: AppDatabase
|
||||
) : OrderRepository {
|
||||
override suspend fun getCoffeesByOrder(orderId: Int): Flow<List<Coffee>> {
|
||||
return flowOf(service.getCoffeesByOrder(orderId).map { it.toCoffee() })
|
||||
}
|
||||
|
||||
override suspend fun getOrdersByDate(startDate: String, endDate: String): Flow<List<OrderWithCoffees>> {
|
||||
return flowOf(service.getOrdersByDate(startDate, endDate).map { it.toOrderWithCoffees() })
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
override fun getOrdersByUser(id: Int): Flow<PagingData<Order>> {
|
||||
Log.d(RestOrderRepository::class.simpleName, "Get Orders by User")
|
||||
|
||||
val pagingSourceFactory = { dbOrderRepository.getOrdersByUserPagingSource(id) }
|
||||
return Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = OrderRemoteMediator(
|
||||
service,
|
||||
dbOrderRepository,
|
||||
dbRemoteKeyRepository,
|
||||
database
|
||||
),
|
||||
pagingSourceFactory = pagingSourceFactory
|
||||
).flow
|
||||
}
|
||||
|
||||
override suspend fun insert(order: Order): Long {
|
||||
return service.createOrder(order.toOrderRemote()).toOrder().orderId.toLong()
|
||||
}
|
||||
}
|
@ -44,21 +44,21 @@ class RestUserRepository(
|
||||
}
|
||||
|
||||
override suspend fun getByUid(uid: Int): User =
|
||||
service.getUser(uid).toUser()!!
|
||||
service.getUser(uid).toUser()
|
||||
|
||||
override suspend fun tryLogin(login: String, password: String): User? =
|
||||
override suspend fun tryLogin(login: String, password: String): User =
|
||||
service.tryLogin(login, password).toUser()
|
||||
|
||||
|
||||
override suspend fun insert(user: User): Long {
|
||||
return service.createUser(user.toUserRemote()).toUser()?.uid?.toLong()!!
|
||||
return service.createUser(user.toUserRemote()).toUser().userId.toLong()
|
||||
}
|
||||
|
||||
override suspend fun update(user: User): Int {
|
||||
return service.updateUser(user.uid, user.toUserRemote()).toUser()?.uid!!
|
||||
return service.updateUser(user.userId, user.toUserRemote()).toUser().userId
|
||||
}
|
||||
|
||||
override suspend fun delete(user: User) {
|
||||
service.deleteUser(user.uid).toUser()
|
||||
service.deleteUser(user.userId).toUser()
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ class UserRemoteMediator(
|
||||
val nextKey = if (endOfPaginationReached) null else page + 1
|
||||
val keys = users.map {
|
||||
RemoteKeys(
|
||||
entityId = it.uid,
|
||||
entityId = it.userId,
|
||||
type = RemoteKeyType.USER,
|
||||
prevKey = prevKey,
|
||||
nextKey = nextKey
|
||||
@ -83,14 +83,14 @@ class UserRemoteMediator(
|
||||
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, User>): RemoteKeys? {
|
||||
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
|
||||
?.let { user ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.USER)
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(user.userId, RemoteKeyType.USER)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, User>): RemoteKeys? {
|
||||
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
|
||||
?.let { user ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.USER)
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(user.userId, RemoteKeyType.USER)
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ class UserRemoteMediator(
|
||||
state: PagingState<Int, User>
|
||||
): RemoteKeys? {
|
||||
return state.anchorPosition?.let { position ->
|
||||
state.closestItemToPosition(position)?.uid?.let { userUid ->
|
||||
state.closestItemToPosition(position)?.userId?.let { userUid ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(userUid, RemoteKeyType.USER)
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,14 @@ package com.zyzf.coffeepreorder.database
|
||||
import android.content.Context
|
||||
import com.zyzf.coffeepreorder.api.MyServerService
|
||||
import com.zyzf.coffeepreorder.api.coffee.RestCoffeeRepository
|
||||
import com.zyzf.coffeepreorder.api.order.RestOrderCoffeesRepository
|
||||
import com.zyzf.coffeepreorder.api.order.RestOrderRepository
|
||||
import com.zyzf.coffeepreorder.api.user.RestUserRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.CartRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineCartRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineOrderRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineOrderWithCoffeesRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OfflineUserRepository
|
||||
|
||||
@ -14,6 +18,8 @@ interface AppContainer {
|
||||
val cartRepository: CartRepository
|
||||
val coffeeRestRepository: RestCoffeeRepository
|
||||
val userRestRepository: RestUserRepository
|
||||
val orderRestRepository: RestOrderRepository
|
||||
val orderCoffeesRestRepository: RestOrderCoffeesRepository
|
||||
|
||||
companion object {
|
||||
const val LIMIT = 10
|
||||
@ -27,6 +33,12 @@ class AppDataContainer(private val context: Context) : AppContainer {
|
||||
private val userRepository: OfflineUserRepository by lazy {
|
||||
OfflineUserRepository(AppDatabase.getInstance(context).userDao())
|
||||
}
|
||||
private val orderRepository: OfflineOrderRepository by lazy {
|
||||
OfflineOrderRepository(AppDatabase.getInstance(context).orderDao())
|
||||
}
|
||||
private val orderCoffeesRepository: OfflineOrderWithCoffeesRepository by lazy {
|
||||
OfflineOrderWithCoffeesRepository(AppDatabase.getInstance(context).orderWithCoffeesDao())
|
||||
}
|
||||
override val cartRepository: CartRepository by lazy {
|
||||
OfflineCartRepository(AppDatabase.getInstance(context).cartDao())
|
||||
}
|
||||
@ -49,4 +61,18 @@ class AppDataContainer(private val context: Context) : AppContainer {
|
||||
AppDatabase.getInstance(context)
|
||||
)
|
||||
}
|
||||
override val orderRestRepository: RestOrderRepository by lazy {
|
||||
RestOrderRepository(
|
||||
MyServerService.getInstance(),
|
||||
orderRepository,
|
||||
remoteKeyRepository,
|
||||
AppDatabase.getInstance(context)
|
||||
)
|
||||
}
|
||||
override val orderCoffeesRestRepository: RestOrderCoffeesRepository by lazy {
|
||||
RestOrderCoffeesRepository(
|
||||
MyServerService.getInstance(),
|
||||
orderCoffeesRepository
|
||||
)
|
||||
}
|
||||
}
|
@ -6,18 +6,24 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import com.zyzf.coffeepreorder.database.dao.CartDao
|
||||
import com.zyzf.coffeepreorder.database.dao.CoffeeDao
|
||||
import com.zyzf.coffeepreorder.database.dao.OrderDao
|
||||
import com.zyzf.coffeepreorder.database.dao.OrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.database.dao.RemoteKeysDao
|
||||
import com.zyzf.coffeepreorder.database.dao.UserDao
|
||||
import com.zyzf.coffeepreorder.database.model.Cart
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
import com.zyzf.coffeepreorder.database.model.RemoteKeys
|
||||
import com.zyzf.coffeepreorder.database.model.User
|
||||
|
||||
@Database(entities = [User::class, Coffee::class, Cart::class, RemoteKeys::class], version = 1, exportSchema = false)
|
||||
@Database(entities = [User::class, Coffee::class, Cart::class, Order::class, OrderCoffeeCrossRef::class, RemoteKeys::class], version = 1, exportSchema = false)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun userDao(): UserDao
|
||||
abstract fun coffeeDao(): CoffeeDao
|
||||
abstract fun cartDao(): CartDao
|
||||
abstract fun orderDao(): OrderDao
|
||||
abstract fun orderWithCoffeesDao(): OrderWithCoffees
|
||||
abstract fun remoteKeysDao(): RemoteKeysDao
|
||||
|
||||
companion object {
|
||||
|
@ -14,14 +14,17 @@ interface CartDao {
|
||||
@Query("select * from cart")
|
||||
suspend fun getAll(): Cart
|
||||
|
||||
@Query("select coffee.uid, coffee.name, coffee.cost, coffee.ingredients from cart join coffee on coffee.uid = cart.coffee_id and cart.count > 0 collate nocase")
|
||||
@Query("select coffee.* from cart join coffee on coffee.coffee_id = cart.coffee_id and cart.count > 0 collate nocase")
|
||||
fun getAllInCart(): PagingSource<Int, Coffee>
|
||||
|
||||
@Query("select sum(coffee.cost * cart.count) from cart JOIN coffee on coffee.uid = cart.coffee_id and cart.count > 0")
|
||||
@Query("select coffee.* from cart join coffee on coffee.coffee_id = cart.coffee_id and cart.count > 0 collate nocase")
|
||||
suspend fun getAllInCartList(): List<Coffee>
|
||||
|
||||
@Query("select sum(coffee.cost * cart.count) from cart JOIN coffee on coffee.coffee_id = cart.coffee_id and cart.count > 0")
|
||||
fun getSumInCart(): Double
|
||||
|
||||
@Query("select cart.count from cart JOIN coffee on coffee.uid = cart.coffee_id where coffee.uid = :coffeeId")
|
||||
fun getCountForCoffee(coffeeId: Int): Double
|
||||
@Query("select cart.count from cart JOIN coffee on coffee.coffee_id = cart.coffee_id where coffee.coffee_id = :coffeeId")
|
||||
fun getCountForCoffee(coffeeId: Int): Int
|
||||
|
||||
@Insert
|
||||
suspend fun insert(cart: Cart)
|
||||
|
@ -13,7 +13,7 @@ interface CoffeeDao {
|
||||
@Query("select * from coffee order by name collate nocase asc")
|
||||
fun getAllCoffees(): PagingSource<Int, Coffee>
|
||||
|
||||
@Query("select coffee.uid, name, cost, ingredients from coffee where coffee.uid = :uid")
|
||||
@Query("select coffee.coffee_id, name, cost, ingredients from coffee where coffee.coffee_id = :uid")
|
||||
suspend fun getByUid(uid: Int): Coffee?
|
||||
|
||||
@Insert
|
||||
|
@ -0,0 +1,56 @@
|
||||
package com.zyzf.coffeepreorder.database.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface OrderDao {
|
||||
@Query("select * from `order` order by order_id collate nocase asc")
|
||||
fun getAll(): PagingSource<Int, Order>
|
||||
|
||||
@Query("select * from `order` where `order`.order_id = :uid")
|
||||
suspend fun getByUid(uid: Int): Order?
|
||||
|
||||
@Query("""
|
||||
SELECT `order`.* FROM `order`
|
||||
WHERE user_id = :userId
|
||||
""")
|
||||
fun getOrdersByUser(userId: Int): PagingSource<Int, Order>
|
||||
|
||||
@Query("""
|
||||
SELECT coffee.* FROM coffee
|
||||
INNER JOIN ordercoffeecrossref ON coffee.coffee_id = ordercoffeecrossref.coffee_id
|
||||
WHERE ordercoffeecrossref.order_id = :orderId
|
||||
""")
|
||||
fun getCoffeesByOrder(orderId: Int): Flow<List<Coffee>>
|
||||
|
||||
@Query("""
|
||||
SELECT `order`.* FROM `order`
|
||||
INNER JOIN ordercoffeecrossref ON `order`.order_id = ordercoffeecrossref.order_id
|
||||
WHERE date >= :startDate and date <= :endDate
|
||||
""")
|
||||
fun getOrdersByDate(startDate: String, endDate: String): Flow<List<OrderWithCoffees>>
|
||||
|
||||
@Insert
|
||||
fun insert(order: Order): Long
|
||||
|
||||
@Insert
|
||||
suspend fun insert(vararg order: Order)
|
||||
|
||||
@Update
|
||||
fun update(order: Order): Int
|
||||
|
||||
@Delete
|
||||
suspend fun delete(order: Order)
|
||||
|
||||
@Query("delete from `order`")
|
||||
suspend fun deleteAll()
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.zyzf.coffeepreorder.database.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
|
||||
@Dao
|
||||
interface OrderWithCoffees {
|
||||
@Query("select * from ordercoffeecrossref")
|
||||
fun getAll(): List<OrderCoffeeCrossRef>
|
||||
@Insert
|
||||
suspend fun insert(vararg orderCoffee: OrderCoffeeCrossRef)
|
||||
@Delete
|
||||
suspend fun delete(orderCoffee: OrderCoffeeCrossRef)
|
||||
}
|
@ -16,7 +16,7 @@ interface UserDao {
|
||||
@Query("select * from user where login = :login and password = :password")
|
||||
suspend fun tryLogin(login: String, password: String): User?
|
||||
|
||||
@Query("select * from user where uid = :uid")
|
||||
@Query("select * from user where user_id = :uid")
|
||||
suspend fun getByUid(uid: Int): User?
|
||||
|
||||
@Insert
|
||||
|
@ -4,23 +4,26 @@ import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "cart", foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Cart::class,
|
||||
parentColumns = ["uid"],
|
||||
childColumns = ["coffee_id"],
|
||||
onDelete = ForeignKey.RESTRICT,
|
||||
onUpdate = ForeignKey.RESTRICT
|
||||
)
|
||||
])
|
||||
//@Entity(tableName = "cart", foreignKeys = [
|
||||
// ForeignKey(
|
||||
// entity = Coffee::class,
|
||||
// parentColumns = arrayOf("coffee_id"),
|
||||
// childColumns = arrayOf("coffee_id"),
|
||||
// onDelete = ForeignKey.SET_DEFAULT,
|
||||
// onUpdate = ForeignKey.CASCADE
|
||||
// )
|
||||
//])
|
||||
@Entity(tableName = "cart")
|
||||
data class Cart(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int = 0,
|
||||
@ColumnInfo(name = "cart_id")
|
||||
val cartId: Int = 0,
|
||||
@ColumnInfo(name = "coffee_id", index = true)
|
||||
val coffeeId: Int,
|
||||
@ColumnInfo(name = "count", index = true)
|
||||
@ColumnInfo(name = "count")
|
||||
val count: Int = 0
|
||||
) {
|
||||
@Ignore
|
||||
@ -33,13 +36,13 @@ data class Cart(
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Cart
|
||||
if (uid != other.uid) return false
|
||||
if (cartId != other.cartId) return false
|
||||
if (coffeeId != other.coffeeId) return false
|
||||
return count == other.count
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = uid
|
||||
var result = cartId
|
||||
result = 31 * result + coffeeId.hashCode()
|
||||
result = 31 * result + count.hashCode()
|
||||
return result
|
||||
|
@ -8,7 +8,8 @@ import androidx.room.PrimaryKey
|
||||
@Entity(tableName = "coffee")
|
||||
data class Coffee(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int = 0,
|
||||
@ColumnInfo(name = "coffee_id")
|
||||
val coffeeId: Int = 0,
|
||||
@ColumnInfo(name = "name")
|
||||
var name: String,
|
||||
@ColumnInfo(name = "cost")
|
||||
@ -38,14 +39,14 @@ data class Coffee(
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Coffee
|
||||
if (uid != other.uid) return false
|
||||
if (coffeeId != other.coffeeId) return false
|
||||
if (name != other.name) return false
|
||||
if (cost != other.cost) return false
|
||||
return ingredients == other.ingredients
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = uid
|
||||
var result = coffeeId
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + cost.hashCode()
|
||||
result = 31 * result + ingredients.hashCode()
|
||||
|
@ -0,0 +1,65 @@
|
||||
package com.zyzf.coffeepreorder.database.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(
|
||||
tableName = "order",
|
||||
foreignKeys = [ForeignKey(
|
||||
entity = User::class,
|
||||
parentColumns = arrayOf("user_id"),
|
||||
childColumns = arrayOf("user_id"),
|
||||
onDelete = ForeignKey.RESTRICT,
|
||||
onUpdate = ForeignKey.RESTRICT
|
||||
)]
|
||||
)
|
||||
data class Order(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "order_id")
|
||||
val orderId: Int = 0,
|
||||
@ColumnInfo(name = "date")
|
||||
var date: String,
|
||||
@ColumnInfo(name = "user_id", index = true)
|
||||
val userId: Int,
|
||||
@ColumnInfo(name = "sum")
|
||||
val sum: Double
|
||||
) {
|
||||
@Ignore
|
||||
constructor(
|
||||
date: String,
|
||||
userId: Int,
|
||||
sum: Double
|
||||
) : this(0, date, userId, sum)
|
||||
|
||||
companion object {
|
||||
fun getOrder(index: Int = 0): Order {
|
||||
return Order(
|
||||
index,
|
||||
"",
|
||||
0,
|
||||
0.0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Order
|
||||
if (orderId != other.orderId) return false
|
||||
if (date != other.date) return false
|
||||
if (userId != other.userId) return false
|
||||
return sum == other.sum
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = orderId
|
||||
result = 31 * result + date.hashCode()
|
||||
result = 31 * result + userId.hashCode()
|
||||
result = 31 * result + sum.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.zyzf.coffeepreorder.database.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
|
||||
@Entity(primaryKeys = ["order_id", "coffee_id"])
|
||||
class OrderCoffeeCrossRef (
|
||||
@ColumnInfo(name = "order_id")
|
||||
val orderId: Int,
|
||||
@ColumnInfo(name = "coffee_id")
|
||||
val coffeeId: Int,
|
||||
@ColumnInfo(name = "count")
|
||||
val count: Int
|
||||
)
|
@ -0,0 +1,27 @@
|
||||
package com.zyzf.coffeepreorder.database.model
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Junction
|
||||
import androidx.room.Relation
|
||||
|
||||
data class OrderWithCoffees(
|
||||
@Embedded val order: Order,
|
||||
@Relation(
|
||||
parentColumn = "order_id",
|
||||
entityColumn = "user_id"
|
||||
)
|
||||
val user: User,
|
||||
@Relation(
|
||||
parentColumn = "order_id",
|
||||
entityColumn = "coffee_id",
|
||||
associateBy = Junction(OrderCoffeeCrossRef::class)
|
||||
)
|
||||
val coffees: List<Coffee>,
|
||||
@Relation(
|
||||
parentColumn = "order_id",
|
||||
entityColumn = "coffee_id",
|
||||
entity = OrderCoffeeCrossRef::class,
|
||||
projection = ["count"]
|
||||
)
|
||||
val counts: List<Int>
|
||||
)
|
@ -7,7 +7,8 @@ import androidx.room.TypeConverters
|
||||
|
||||
enum class RemoteKeyType(private val type: String) {
|
||||
COFFEE(Coffee::class.simpleName ?: "Coffee"),
|
||||
USER(User::class.simpleName ?: "User");
|
||||
USER(User::class.simpleName ?: "User"),
|
||||
ORDER(Order::class.simpleName ?: "Order");
|
||||
|
||||
@TypeConverter
|
||||
fun toRemoteKeyType(value: String) = entries.first { it.type == value }
|
||||
|
@ -8,7 +8,8 @@ import androidx.room.PrimaryKey
|
||||
@Entity(tableName = "user")
|
||||
data class User(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int = 0,
|
||||
@ColumnInfo(name = "user_id")
|
||||
val userId: Int = 0,
|
||||
@ColumnInfo(name = "login")
|
||||
var login: String,
|
||||
@ColumnInfo(name = "fio")
|
||||
@ -46,7 +47,7 @@ data class User(
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as User
|
||||
if (uid != other.uid) return false
|
||||
if (userId != other.userId) return false
|
||||
if (login != other.login) return false
|
||||
if (fio != other.fio) return false
|
||||
if (phone != other.phone) return false
|
||||
@ -55,7 +56,7 @@ data class User(
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = uid
|
||||
var result = userId
|
||||
result = 31 * result + login.hashCode()
|
||||
result = 31 * result + fio.hashCode()
|
||||
result = 31 * result + phone.hashCode()
|
||||
|
@ -9,10 +9,11 @@ interface CartRepository {
|
||||
suspend fun getAll(): Cart
|
||||
suspend fun insert(cart: Cart)
|
||||
fun getAllInCart(): Flow<PagingData<Coffee>>
|
||||
suspend fun getAllInCartList(): List<Coffee>
|
||||
fun getSumInCart(): Double
|
||||
suspend fun insertCoffee(coffeeId: Int, count: Int)
|
||||
suspend fun deleteCoffee(coffeeId: Int, count: Int)
|
||||
fun getCountForCoffee(coffeeId: Int): Double
|
||||
fun getCountForCoffee(coffeeId: Int): Int
|
||||
suspend fun update(cart: Cart)
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
@ -17,12 +17,14 @@ class OfflineCartRepository(private val cartDao: CartDao) : CartRepository {
|
||||
),
|
||||
pagingSourceFactory = cartDao::getAllInCart
|
||||
).flow
|
||||
|
||||
override suspend fun getAllInCartList(): List<Coffee> = cartDao.getAllInCartList()
|
||||
override fun getSumInCart(): Double = cartDao.getSumInCart()
|
||||
override suspend fun getAll(): Cart = cartDao.getAll()
|
||||
override suspend fun insert(cart: Cart) = cartDao.insert(cart)
|
||||
override suspend fun insertCoffee(coffeeId: Int, count: Int) = cartDao.insertCoffee(coffeeId, count)
|
||||
override suspend fun deleteCoffee(coffeeId: Int, count: Int) = cartDao.deleteCoffee(coffeeId, count)
|
||||
override fun getCountForCoffee(coffeeId: Int): Double = cartDao.getCountForCoffee(coffeeId)
|
||||
override fun getCountForCoffee(coffeeId: Int): Int = cartDao.getCountForCoffee(coffeeId)
|
||||
override suspend fun update(cart: Cart) = cartDao.update(cart)
|
||||
override suspend fun deleteAll() = cartDao.deleteAll()
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.zyzf.coffeepreorder.database.repository
|
||||
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import com.zyzf.coffeepreorder.database.AppContainer
|
||||
import com.zyzf.coffeepreorder.database.dao.OrderDao
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineOrderRepository(private val orderDao: OrderDao) : OrderRepository {
|
||||
override fun getOrdersByUser(id: Int): Flow<PagingData<Order>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = { orderDao.getOrdersByUser(id) }
|
||||
).flow
|
||||
override suspend fun getCoffeesByOrder(orderId: Int): Flow<List<Coffee>> = orderDao.getCoffeesByOrder(orderId)
|
||||
override suspend fun insert(order: Order) = orderDao.insert(order)
|
||||
override suspend fun getOrdersByDate(
|
||||
startDate: String,
|
||||
endDate: String
|
||||
): Flow<List<OrderWithCoffees>> = orderDao.getOrdersByDate(startDate, endDate)
|
||||
fun getOrdersByUserPagingSource(id: Int): PagingSource<Int, Order> = orderDao.getOrdersByUser(id)
|
||||
suspend fun deleteAll() = orderDao.deleteAll()
|
||||
suspend fun insertOrders(orders: List<Order>) =
|
||||
orderDao.insert(*orders.toTypedArray())
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.zyzf.coffeepreorder.database.repository
|
||||
|
||||
import com.zyzf.coffeepreorder.database.dao.OrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
|
||||
class OfflineOrderWithCoffeesRepository(private val orderCoffeesDAO: OrderWithCoffees) : OrderWithCoffeesRepository {
|
||||
override suspend fun getAll() = orderCoffeesDAO.getAll()
|
||||
override suspend fun insert(orderCoffee: OrderCoffeeCrossRef) = orderCoffeesDAO.insert(orderCoffee)
|
||||
override suspend fun delete(orderCoffee: OrderCoffeeCrossRef) = orderCoffeesDAO.delete(orderCoffee)
|
||||
suspend fun insertAll(orderBouquet: List<OrderCoffeeCrossRef>) =
|
||||
orderCoffeesDAO.insert(*orderBouquet.toTypedArray())
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.zyzf.coffeepreorder.database.repository
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface OrderRepository {
|
||||
suspend fun getCoffeesByOrder(orderId: Int): Flow<List<Coffee>>
|
||||
fun getOrdersByUser(id: Int): Flow<PagingData<Order>>
|
||||
suspend fun insert(order: Order): Long
|
||||
suspend fun getOrdersByDate(startDate: String, endDate: String): Flow<List<OrderWithCoffees>>
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.zyzf.coffeepreorder.database.repository
|
||||
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
|
||||
interface OrderWithCoffeesRepository {
|
||||
suspend fun getAll(): List<OrderCoffeeCrossRef>
|
||||
suspend fun insert(orderCoffee: OrderCoffeeCrossRef)
|
||||
suspend fun delete(orderCoffee: OrderCoffeeCrossRef)
|
||||
}
|
@ -8,8 +8,10 @@ import com.zyzf.coffeepreorder.CoffeeApplication
|
||||
import com.zyzf.coffeepreorder.ui.cart.CartViewModel
|
||||
import com.zyzf.coffeepreorder.ui.coffee.CoffeeListViewModel
|
||||
import com.zyzf.coffeepreorder.ui.login.LoginViewModel
|
||||
import com.zyzf.coffeepreorder.ui.order.OrderViewModel
|
||||
import com.zyzf.coffeepreorder.ui.profile.ProfileViewModel
|
||||
import com.zyzf.coffeepreorder.ui.register.RegisterViewModel
|
||||
import com.zyzf.coffeepreorder.ui.statistic.OrderStatisticViewModel
|
||||
|
||||
object AppViewModelProvider {
|
||||
val Factory = viewModelFactory {
|
||||
@ -26,7 +28,16 @@ object AppViewModelProvider {
|
||||
RegisterViewModel(coffeeApplication().container.userRestRepository)
|
||||
}
|
||||
initializer {
|
||||
ProfileViewModel(coffeeApplication().container.userRestRepository)
|
||||
ProfileViewModel(coffeeApplication().container.userRestRepository,
|
||||
coffeeApplication().container.cartRepository)
|
||||
}
|
||||
initializer {
|
||||
OrderStatisticViewModel(coffeeApplication().container.orderRestRepository)
|
||||
}
|
||||
initializer {
|
||||
OrderViewModel(coffeeApplication().container.orderRestRepository,
|
||||
coffeeApplication().container.orderCoffeesRestRepository,
|
||||
coffeeApplication().container.cartRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ fun Cart(
|
||||
)
|
||||
CartList(
|
||||
coffeeList = coffeeListUiState,
|
||||
onDeleteFromCartClick = {currentCoffee: Coffee ->
|
||||
onDeleteFromCartClick = { currentCoffee: Coffee ->
|
||||
coffee.value = currentCoffee
|
||||
openDialog.value = true
|
||||
}
|
||||
@ -126,7 +126,7 @@ fun Cart(
|
||||
private fun CartList(
|
||||
coffeeList: LazyPagingItems<Coffee>,
|
||||
onDeleteFromCartClick: (coffee: Coffee) -> Unit,
|
||||
getCoffeeCount: (coffeeId: Int) -> Double
|
||||
getCoffeeCount: (Int) -> Int
|
||||
) {
|
||||
LazyColumn(
|
||||
horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
@ -151,7 +151,7 @@ private fun CartList(
|
||||
private fun CartListItem (
|
||||
coffee: Coffee,
|
||||
onDeleteFromCartClick: (coffee: Coffee) -> Unit,
|
||||
getCoffeeCount: (coffeeId: Int) -> Double
|
||||
getCoffeeCount: (coffeeId: Int) -> Int
|
||||
) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -159,7 +159,7 @@ private fun CartListItem (
|
||||
.padding(bottom = 10.dp, top = 10.dp),
|
||||
horizontalArrangement = Arrangement.SpaceAround) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.uid +".png")
|
||||
model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.coffeeId +".png")
|
||||
.crossfade(true).build(),
|
||||
error = painterResource(R.drawable.ic_broken_image),
|
||||
placeholder = painterResource(R.drawable.loading_img),
|
||||
@ -173,7 +173,7 @@ private fun CartListItem (
|
||||
Modifier
|
||||
.weight(2f)
|
||||
.padding(start = 20.dp)) {
|
||||
val coffeeCount: Double = getCoffeeCount(coffee.uid)
|
||||
val coffeeCount: Int = getCoffeeCount(coffee.coffeeId)
|
||||
val currentCoffeeName: String = if (coffeeCount > 1) {
|
||||
coffee.name + " x" + coffeeCount.toString()
|
||||
} else {
|
||||
|
@ -11,11 +11,11 @@ class CartViewModel(
|
||||
) : ViewModel() {
|
||||
val coffeeListUiState: Flow<PagingData<Coffee>> = cartRepository.getAllInCart()
|
||||
|
||||
fun getCountForCoffee(coffeeId: Int): Double {
|
||||
fun getCountForCoffee(coffeeId: Int): Int {
|
||||
return cartRepository.getCountForCoffee(coffeeId)
|
||||
}
|
||||
|
||||
suspend fun deleteCoffeeFromCart(coffee: Coffee) {
|
||||
cartRepository.deleteCoffee(coffee.uid, 1)
|
||||
cartRepository.deleteCoffee(coffee.coffeeId, 1)
|
||||
}
|
||||
}
|
@ -180,7 +180,7 @@ fun CoffeeList(
|
||||
imageUri = imageUri,
|
||||
beforeOpen = {coffeeUid: Int ->
|
||||
if (coffeeUid != 0 && !isImageChanged.value) {
|
||||
imageUri = Uri.parse("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.value.uid +".png")
|
||||
imageUri = Uri.parse("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.value.coffeeId +".png")
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -199,7 +199,7 @@ private fun AddEditModalBottomSheet(
|
||||
imageUri: Any?,
|
||||
beforeOpen: (coffeeUid: Int) -> Unit
|
||||
) {
|
||||
beforeOpen(coffee.value.uid)
|
||||
beforeOpen(coffee.value.coffeeId)
|
||||
var name: String by remember { mutableStateOf("")}
|
||||
var cost: Double by remember { mutableDoubleStateOf(0.0) }
|
||||
var ingredients: String by remember { mutableStateOf("")}
|
||||
@ -271,16 +271,16 @@ private fun AddEditModalBottomSheet(
|
||||
.build(),
|
||||
)
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||||
if (coffee.value.uid == 0) {
|
||||
if (coffee.value.coffeeId == 0) {
|
||||
Button(onClick = {
|
||||
onAddClick(Coffee(coffee.value.uid, name, cost, ingredients), context)
|
||||
onAddClick(Coffee(coffee.value.coffeeId, name, cost, ingredients), context)
|
||||
openDialog.value = false
|
||||
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
|
||||
Text("Добавить")
|
||||
}
|
||||
} else {
|
||||
Button(onClick = {
|
||||
onEditClick(Coffee(coffee.value.uid, name, cost, ingredients), context)
|
||||
onEditClick(Coffee(coffee.value.coffeeId, name, cost, ingredients), context)
|
||||
openDialog.value = false
|
||||
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
|
||||
Text("Изменить")
|
||||
@ -339,7 +339,7 @@ private fun CoffeeListItem(
|
||||
AsyncImage(
|
||||
model = ImageRequest
|
||||
.Builder(context = LocalContext.current)
|
||||
.data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.uid +".png")
|
||||
.data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.coffeeId +".png")
|
||||
.crossfade(true).build(),
|
||||
error = painterResource(R.drawable.ic_broken_image),
|
||||
placeholder = painterResource(R.drawable.loading_img),
|
||||
@ -363,7 +363,7 @@ private fun CoffeeListItem(
|
||||
.padding(top = 5.dp)) {
|
||||
Button(
|
||||
onClick = {
|
||||
onAddToCartClick(coffee.uid)
|
||||
onAddToCartClick(coffee.coffeeId)
|
||||
},
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.75f)
|
||||
|
@ -55,6 +55,7 @@ class CoffeeListViewModel(
|
||||
suspend fun editCoffee(coffee: Coffee, imageUri: Any?, context: Context) {
|
||||
val editedCoffee: Int = coffeeRepository.update(coffee)
|
||||
if (imageUri !is Uri) return
|
||||
if (imageUri.host == "zyzf.space") return
|
||||
val inputStream = context.contentResolver.openInputStream(imageUri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.zyzf.coffeepreorder.ui.login
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@ -16,7 +15,6 @@ import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@ -33,7 +31,6 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
@ -45,8 +42,6 @@ import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.database.model.User
|
||||
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
|
||||
import com.zyzf.coffeepreorder.ui.navigation.Screen
|
||||
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -142,17 +137,4 @@ fun Login(
|
||||
Text(text = "Зарегистрироваться")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun LoginPreview() {
|
||||
CoffeePreorderTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
Login(null)
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ class LoginViewModel(
|
||||
) : ViewModel() {
|
||||
suspend fun tryLogin(login: String, password: String): User? {
|
||||
val user: User? = userRepository.tryLogin(login, password)
|
||||
return if (user?.uid == 0) {
|
||||
return if (user?.userId == 0) {
|
||||
null
|
||||
} else {
|
||||
user
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.zyzf.coffeepreorder.ui.navigation
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
@ -26,6 +28,7 @@ import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.zyzf.coffeepreorder.CoffeeApplication
|
||||
import com.zyzf.coffeepreorder.R
|
||||
import com.zyzf.coffeepreorder.ui.cart.Cart
|
||||
import com.zyzf.coffeepreorder.ui.coffee.CoffeeList
|
||||
@ -33,6 +36,7 @@ import com.zyzf.coffeepreorder.ui.login.Login
|
||||
import com.zyzf.coffeepreorder.ui.order.Order
|
||||
import com.zyzf.coffeepreorder.ui.profile.Profile
|
||||
import com.zyzf.coffeepreorder.ui.register.Register
|
||||
import com.zyzf.coffeepreorder.ui.statistic.OrderStatistic
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -74,6 +78,11 @@ fun Navbar(
|
||||
) {
|
||||
NavigationBar(modifier) {
|
||||
Screen.bottomBarItems.forEach { screen ->
|
||||
if (CoffeeApplication.currentUser != null &&
|
||||
CoffeeApplication.currentUser!!.role != "admin" &&
|
||||
screen.route == "order-statistic") {
|
||||
return@forEach
|
||||
}
|
||||
NavigationBarItem(
|
||||
icon = { Icon(screen.icon, contentDescription = null) },
|
||||
label = { Text(stringResource(screen.resourceId)) },
|
||||
@ -92,6 +101,7 @@ fun Navbar(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun Navhost(
|
||||
navController: NavHostController,
|
||||
@ -109,6 +119,8 @@ fun Navhost(
|
||||
composable(Screen.Profile.route) { Profile(navController) }
|
||||
composable(Screen.Cart.route) { Cart(navController) }
|
||||
composable(Screen.Order.route) { Order(navController) }
|
||||
composable(Screen.OrderStatistic.route) { OrderStatistic() }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,13 @@ package com.zyzf.coffeepreorder.ui.navigation
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.filled.ShoppingCart
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.zyzf.coffeepreorder.R
|
||||
import com.zyzf.coffeepreorder.database.AppContainer
|
||||
|
||||
enum class Screen(
|
||||
val route: String,
|
||||
@ -32,13 +34,17 @@ enum class Screen(
|
||||
),
|
||||
Order(
|
||||
"order", R.string.coffee_order, Icons.Filled.ShoppingCart
|
||||
),
|
||||
OrderStatistic(
|
||||
"order-statistic", R.string.coffee_order_statistic, Icons.Filled.DateRange
|
||||
);
|
||||
|
||||
companion object {
|
||||
val bottomBarItems = listOf(
|
||||
CoffeeList,
|
||||
Profile,
|
||||
Cart
|
||||
Cart,
|
||||
OrderStatistic
|
||||
)
|
||||
|
||||
fun getItem(route: String): Screen? {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.zyzf.coffeepreorder.ui.order
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@ -24,7 +23,6 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TimePicker
|
||||
import androidx.compose.material3.rememberDatePickerState
|
||||
@ -33,18 +31,18 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
|
||||
import com.zyzf.coffeepreorder.ui.navigation.Screen
|
||||
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
@ -53,18 +51,21 @@ import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Order(navController: NavController?) {
|
||||
fun Order(
|
||||
navController: NavController?,
|
||||
viewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val openDatePicker = remember { mutableStateOf(false) }
|
||||
val openTimePicker = remember { mutableStateOf(false) }
|
||||
val calendar = Calendar.getInstance()
|
||||
val datePickerState = rememberDatePickerState(initialSelectedDateMillis = calendar.timeInMillis)
|
||||
val timePickerState = rememberTimePickerState(is24Hour = true, initialHour = calendar.get(Calendar.HOUR_OF_DAY), initialMinute = calendar.get(Calendar.MINUTE))
|
||||
val formatter = SimpleDateFormat("dd.MM.yyyy", Locale.ROOT)
|
||||
val context = LocalContext.current
|
||||
val sum = remember { mutableStateOf(0.0) }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
sum.value = AppDatabase.getInstance(context).cartDao().getSumInCart()
|
||||
sum.value = viewModel.getSumInCart()
|
||||
}
|
||||
}
|
||||
Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
@ -107,7 +108,12 @@ fun Order(navController: NavController?) {
|
||||
}
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = { navController?.navigate(Screen.CoffeeList.route) },
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
viewModel.createNewOrder(datePickerState.selectedDateMillis)
|
||||
}
|
||||
navController?.navigate(Screen.Cart.route)
|
||||
},
|
||||
icon = { Icon(Icons.Filled.Add, "Оформить заказ") },
|
||||
text = { Text(text = "Оформить заказ") },
|
||||
modifier = Modifier
|
||||
@ -169,17 +175,4 @@ fun Order(navController: NavController?) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun OrderPreview() {
|
||||
CoffeePreorderTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
Order(null)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.zyzf.coffeepreorder.ui.order
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.zyzf.coffeepreorder.CoffeeApplication
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.Order
|
||||
import com.zyzf.coffeepreorder.database.model.OrderCoffeeCrossRef
|
||||
import com.zyzf.coffeepreorder.database.repository.CartRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OrderRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.OrderWithCoffeesRepository
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class OrderViewModel(
|
||||
private val orderRepository: OrderRepository,
|
||||
private val orderWithCoffeesRepository: OrderWithCoffeesRepository,
|
||||
private val cartRepository: CartRepository
|
||||
) : ViewModel() {
|
||||
fun getSumInCart(): Double {
|
||||
return cartRepository.getSumInCart()
|
||||
}
|
||||
|
||||
suspend fun createNewOrder(date: Long?) {
|
||||
val coffees: List<Coffee> = cartRepository.getAllInCartList()
|
||||
if (coffees.isEmpty() || date == null) {
|
||||
return
|
||||
}
|
||||
val cartSum: Double = cartRepository.getSumInCart()
|
||||
val formatter = SimpleDateFormat("dd-MM-yyyy", Locale.ROOT)
|
||||
val currentOrderId: Long = orderRepository.insert(Order(formatter.format(Date(date)), CoffeeApplication.currentUser!!.userId, cartSum))
|
||||
coffees.forEach { coffee: Coffee ->
|
||||
orderWithCoffeesRepository.insert(OrderCoffeeCrossRef(currentOrderId.toInt(), coffee.coffeeId, cartRepository.getCountForCoffee(coffee.coffeeId)))
|
||||
}
|
||||
}
|
||||
}
|
@ -47,10 +47,8 @@ import com.zyzf.coffeepreorder.R
|
||||
import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.database.model.User
|
||||
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
|
||||
import com.zyzf.coffeepreorder.ui.login.LoginViewModel
|
||||
import com.zyzf.coffeepreorder.ui.navigation.Screen
|
||||
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -204,7 +202,7 @@ fun Profile(
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
val user: User = viewModel.changeUser(user.password, userOldPsswd.value, userNewPsswd.value, userNewPsswd.value,
|
||||
user.uid, userLogin, userFIO, userPhone, user.role)
|
||||
user.userId, userLogin, userFIO, userPhone, user.role)
|
||||
CoffeeApplication.currentUser = user
|
||||
}
|
||||
openDialogEdit.value = false
|
||||
@ -241,8 +239,8 @@ fun Profile(
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
GlobalScope.launch (Dispatchers.Main) {
|
||||
CoffeeApplication.currentUser = null
|
||||
coroutineScope.launch {
|
||||
viewModel.logout()
|
||||
}
|
||||
openDialogExit.value = false
|
||||
navController?.navigate(Screen.Login.route)
|
||||
@ -279,9 +277,8 @@ fun Profile(
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
GlobalScope.launch (Dispatchers.Main) {
|
||||
CoffeeApplication.currentUser = null
|
||||
AppDatabase.getInstance(context).userDao().delete(user)
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteAccount(user)
|
||||
}
|
||||
openDialogDelete.value = false
|
||||
navController?.navigate(Screen.Login.route)
|
||||
|
@ -2,12 +2,13 @@ package com.zyzf.coffeepreorder.ui.profile
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.zyzf.coffeepreorder.CoffeeApplication
|
||||
import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.database.model.User
|
||||
import com.zyzf.coffeepreorder.database.repository.CartRepository
|
||||
import com.zyzf.coffeepreorder.database.repository.UserRepository
|
||||
|
||||
class ProfileViewModel(
|
||||
private val userRepository: UserRepository
|
||||
private val userRepository: UserRepository,
|
||||
private val cartRepository: CartRepository
|
||||
) : ViewModel() {
|
||||
suspend fun changeUser(currentUserPassw: String,
|
||||
userOldPsswd: String,
|
||||
@ -25,6 +26,16 @@ class ProfileViewModel(
|
||||
val userUid: Int? = userRepository.update(User(
|
||||
userUid, userLogin, userFIO, userPhone, currentUserPassw, userRole))
|
||||
}
|
||||
return userRepository.getByUid(userUid!!)!!
|
||||
return userRepository.getByUid(userUid)!!
|
||||
}
|
||||
|
||||
suspend fun logout() {
|
||||
CoffeeApplication.currentUser = null
|
||||
cartRepository.deleteAll()
|
||||
}
|
||||
|
||||
suspend fun deleteAccount(user: User) {
|
||||
logout()
|
||||
userRepository.delete(user)
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ import com.zyzf.coffeepreorder.database.model.User
|
||||
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
|
||||
import com.zyzf.coffeepreorder.ui.navigation.Screen
|
||||
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
@ -0,0 +1,281 @@
|
||||
package com.zyzf.coffeepreorder.ui.statistic
|
||||
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.DatePicker
|
||||
import androidx.compose.material3.DatePickerState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberDatePickerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.zyzf.coffeepreorder.CoffeeApplication
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.SimpleDateFormat
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun OrderStatistic(
|
||||
viewModel: OrderStatisticViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val openDatePicker = remember { mutableStateOf(false) }
|
||||
val calendar = Calendar.getInstance()
|
||||
val datePickerState = rememberDatePickerState(initialSelectedDateMillis = calendar.timeInMillis)
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val orderListUiState = viewModel.orderListUiState.collectAsState(initial = listOf())
|
||||
val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
|
||||
val startDate = remember { mutableStateOf(LocalDate.now().minusDays(1).format(formatter))}
|
||||
val endDate = remember { mutableStateOf(LocalDate.now().format(formatter))}
|
||||
val isStartDate = remember { mutableStateOf(true)}
|
||||
Scaffold(
|
||||
topBar = {},
|
||||
floatingActionButton = {
|
||||
if (CoffeeApplication.currentUser?.role == "admin") {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
viewModel.getOrdersByDate(startDate.value, endDate.value, coroutineScope)
|
||||
}
|
||||
},
|
||||
Modifier
|
||||
.padding(all = 20.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Check,
|
||||
contentDescription = "Perform",
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
Column (modifier = Modifier
|
||||
.padding(innerPadding).fillMaxSize()) {
|
||||
StartEndDateBlock(
|
||||
startDate = startDate,
|
||||
endDate = endDate,
|
||||
onStartDateClick = {
|
||||
isStartDate.value = true
|
||||
openDatePicker.value = true
|
||||
},
|
||||
onEndDateClick = {
|
||||
isStartDate.value = false
|
||||
openDatePicker.value = true
|
||||
}
|
||||
)
|
||||
TotalBlock(orderList = orderListUiState.value)
|
||||
OrderList(
|
||||
orderList = orderListUiState
|
||||
)
|
||||
}
|
||||
DateDialog(
|
||||
startDate = startDate,
|
||||
endDate = endDate,
|
||||
isStartDate = isStartDate,
|
||||
openDatePicker = openDatePicker,
|
||||
datePickerState = datePickerState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OrderList(
|
||||
orderList: State<List<OrderWithCoffees>>,
|
||||
) {
|
||||
LazyColumn(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(start = 10.dp, end = 10.dp)) {
|
||||
items(items = orderList.value) {order ->
|
||||
OrderListItem(
|
||||
order = order
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StartEndDateBlock(
|
||||
startDate: MutableState<String>,
|
||||
endDate: MutableState<String>,
|
||||
onStartDateClick: () -> Unit,
|
||||
onEndDateClick: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 140.dp)
|
||||
.padding(bottom = 10.dp, top = 10.dp)) {
|
||||
|
||||
Row(horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Button(onClick = {onStartDateClick()},
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.width(100.dp).padding(10.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
) {
|
||||
Text(text = "От")
|
||||
}
|
||||
Text(text = startDate.value, modifier = Modifier.padding(10.dp))
|
||||
Button(onClick = {onEndDateClick()},
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.width(100.dp).padding(10.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
) {
|
||||
Text(text = "До")
|
||||
}
|
||||
Text(text = endDate.value, modifier = Modifier.padding(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TotalBlock(
|
||||
orderList: List<OrderWithCoffees>
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 140.dp)
|
||||
.padding(bottom = 10.dp, top = 10.dp)) {
|
||||
|
||||
Row(horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()) {
|
||||
Row(modifier = Modifier.width(145.dp)) {
|
||||
Text(text = "Итого: ", modifier = Modifier.padding(5.dp))
|
||||
Text(text = orderList.sumOf { it.order.sum }.toString(), modifier = Modifier.padding(5.dp))
|
||||
}
|
||||
Row(modifier = Modifier.width(145.dp)) {
|
||||
Text(text = "Количество: ", modifier = Modifier.padding(5.dp))
|
||||
Text(text = orderList.count().toString(), modifier = Modifier.padding(5.dp))
|
||||
}
|
||||
Row(modifier = Modifier.width(145.dp)) {
|
||||
Text(text = "Среднее: ", modifier = Modifier.padding(5.dp))
|
||||
Text(text = (orderList.sumOf { it.order.sum } / orderList.count()).toString(), modifier = Modifier.padding(5.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OrderListItem(
|
||||
order: OrderWithCoffees
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 150.dp)
|
||||
.padding(bottom = 10.dp, top = 10.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(text = order.user.fio, fontSize = 25.sp)
|
||||
Text(text = order.user.phone, fontSize = 25.sp)
|
||||
Text(text = String.format("%.2f", order.order.sum), fontSize = 30.sp)
|
||||
Row() {
|
||||
for (i in (0..order.coffees.count()-1)) {
|
||||
if (order.counts[i] > 1) {
|
||||
Text(text = order.coffees[i].name + " x" + order.counts[i] + "(" + order.coffees[i].cost * order.counts[i] + ")", fontSize = 15.sp)
|
||||
} else {
|
||||
Text(text = order.coffees[i].name + "(" + order.coffees[i].cost + ")", fontSize = 15.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun DateDialog(
|
||||
startDate: MutableState<String>,
|
||||
endDate: MutableState<String>,
|
||||
isStartDate: MutableState<Boolean>,
|
||||
openDatePicker: MutableState<Boolean>,
|
||||
datePickerState: DatePickerState
|
||||
) {
|
||||
if (openDatePicker.value) {
|
||||
Dialog(onDismissRequest = { openDatePicker.value = false },
|
||||
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = true, usePlatformDefaultWidth = false)
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(0.7f)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.End) {
|
||||
Button(
|
||||
onClick = {
|
||||
if (datePickerState.selectedDateMillis != null) {
|
||||
val formatter = SimpleDateFormat("dd-MM-yyyy", Locale.ROOT)
|
||||
if (isStartDate.value) {
|
||||
startDate.value = formatter.format(Date(datePickerState.selectedDateMillis!!))
|
||||
} else {
|
||||
endDate.value = formatter.format(Date(datePickerState.selectedDateMillis!!))
|
||||
}
|
||||
}
|
||||
openDatePicker.value = false
|
||||
},
|
||||
modifier = Modifier.padding(10.dp),
|
||||
) {
|
||||
Text("Ок")
|
||||
}
|
||||
DatePicker(
|
||||
state = datePickerState,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(10.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.zyzf.coffeepreorder.ui.statistic
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.zyzf.coffeepreorder.database.model.OrderWithCoffees
|
||||
import com.zyzf.coffeepreorder.database.repository.OrderRepository
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
class OrderStatisticViewModel(
|
||||
private val orderRepository: OrderRepository
|
||||
) : ViewModel() {
|
||||
private val formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
|
||||
private var startDate: String = LocalDate.now().minusDays(1).format(formatter)
|
||||
private var endDate: String = LocalDate.now().format(formatter)
|
||||
|
||||
var orderListUiState: Flow<List<OrderWithCoffees>> = temp()
|
||||
|
||||
private fun temp(): Flow<List<OrderWithCoffees>> {
|
||||
var orderWithCoffees: Flow<List<OrderWithCoffees>>? = null
|
||||
runBlocking {
|
||||
orderWithCoffees = orderRepository.getOrdersByDate(startDate, endDate)
|
||||
}
|
||||
return orderWithCoffees!!
|
||||
}
|
||||
|
||||
fun getOrdersByDate(startDate: String, endDate: String, scope: CoroutineScope) {
|
||||
this.startDate = startDate
|
||||
this.endDate = endDate
|
||||
scope.launch {
|
||||
orderListUiState = orderRepository.getOrdersByDate(startDate, endDate)
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
<string name="coffee_main_title">Меню</string>
|
||||
<string name="coffee_cart">Корзина</string>
|
||||
<string name="coffee_order">Заказ</string>
|
||||
<string name="coffee_order_statistic">Статистика</string>
|
||||
<string name="coffee_name">Название</string>
|
||||
<string name="coffee_cost">Стоимость</string>
|
||||
<string name="coffee_ingredients">Ингредиенты</string>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">192.168.0.100</domain>
|
||||
<domain includeSubdomains="true">192.168.1.230</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
4
backend/Dockerfile
Normal file
4
backend/Dockerfile
Normal file
@ -0,0 +1,4 @@
|
||||
FROM eclipse-temurin:17-jdk-alpine
|
||||
VOLUME /tmp
|
||||
COPY build/libs/yan-0.0.1-SNAPSHOT.jar app.jar
|
||||
ENTRYPOINT ["java","-jar","/app.jar"]
|
@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.2.0'
|
||||
id 'org.springframework.boot' version '3.2.1'
|
||||
id 'io.spring.dependency-management' version '1.1.4'
|
||||
}
|
||||
|
||||
@ -16,16 +16,15 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-devtools'
|
||||
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'com.h2database:h2'
|
||||
//implementation 'com.h2database:h2:2.1.212'
|
||||
|
||||
implementation 'org.hibernate.validator:hibernate-validator'
|
||||
implementation 'org.projectlombok:lombok'
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
runtimeOnly 'org.postgresql:postgresql'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
java.targetCompatibility = JavaVersion.VERSION_17
|
@ -1,7 +1,20 @@
|
||||
package com.kalyshev.yan.coffee.repository;
|
||||
|
||||
import com.kalyshev.yan.coffee.model.Coffee;
|
||||
import com.kalyshev.yan.order.model.OrderCoffeeCrossRef;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CoffeeRepository extends JpaRepository<Coffee, Long> {
|
||||
@Query(value = """
|
||||
select c, ord.count from Coffee c
|
||||
join OrderCoffeeCrossRef ord on c.id = ord.coffee.id
|
||||
join Order o on o.id = ord.order.id
|
||||
where o.id = :order_id
|
||||
""")
|
||||
public List<Object[]> findCoffeesByOrder(@Param("order_id") Long orderId);
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.kalyshev.yan.order.controller;
|
||||
|
||||
import com.kalyshev.yan.order.model.OrderCoffeeCrossRef;
|
||||
|
||||
public class OrderCoffeeCrossRefDto {
|
||||
private Long id;
|
||||
private Long orderId;
|
||||
private Long coffeeId;
|
||||
private int count;
|
||||
public OrderCoffeeCrossRefDto(){}
|
||||
public OrderCoffeeCrossRefDto(OrderCoffeeCrossRef orderCoffeeCrossRef) {
|
||||
this.id = orderCoffeeCrossRef.getId();
|
||||
this.orderId = orderCoffeeCrossRef.getOrder().getId();
|
||||
this.coffeeId = orderCoffeeCrossRef.getCoffee().getId();
|
||||
this.count = orderCoffeeCrossRef.getCount();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public Long getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
public void setOrderId(Long orderId) {
|
||||
this.orderId = orderId;
|
||||
}
|
||||
public Long getCoffeeId() {
|
||||
return coffeeId;
|
||||
}
|
||||
public void setCoffeeId(Long coffeeId) {
|
||||
this.coffeeId = coffeeId;
|
||||
}
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.kalyshev.yan.order.controller;
|
||||
|
||||
import com.kalyshev.yan.WebConfiguration;
|
||||
import com.kalyshev.yan.coffee.controller.CoffeeDto;
|
||||
import com.kalyshev.yan.order.model.OrderCoffeeCrossRef;
|
||||
import com.kalyshev.yan.order.model.OrderCoffees;
|
||||
import com.kalyshev.yan.order.service.OrderService;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(WebConfiguration.REST_API + "/order")
|
||||
public class OrderController {
|
||||
private final OrderService orderService;
|
||||
public OrderController(OrderService orderService) {
|
||||
this.orderService = orderService;
|
||||
}
|
||||
@GetMapping("/coffeesByOrder")
|
||||
public List<Pair<CoffeeDto, Integer>> getCoffeesByOrder(
|
||||
@RequestParam(value = "orderId") Long orderId
|
||||
){
|
||||
return orderService.findCoffeesByOrder(orderId);
|
||||
}
|
||||
|
||||
@GetMapping("/byDate")
|
||||
public List<OrderCoffees> getOrdersByDate(
|
||||
@RequestParam(value = "startDate") String startDate,
|
||||
@RequestParam(value = "endDate") String endDate
|
||||
) throws ParseException {
|
||||
return orderService.findOrdersByDate(startDate, endDate);
|
||||
}
|
||||
|
||||
@GetMapping("/byUser")
|
||||
public List<OrderDto> getOrdersByUser(
|
||||
@RequestParam(value = "userId") Long userId,
|
||||
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
|
||||
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize,
|
||||
@RequestParam(value = "sortBy", defaultValue = "id", required = false) String sortBy,
|
||||
@RequestParam(value = "sortDir", defaultValue = "asc", required = false) String sortDir
|
||||
) {
|
||||
return orderService.findOrderByUser(userId, pageNo, pageSize, sortBy, sortDir).stream()
|
||||
.map(OrderDto::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@GetMapping("/coffeeCrossRef")
|
||||
public List<OrderCoffeeCrossRef> getOrdersByDate() {
|
||||
return orderService.findOrderCoffeeCrossRef();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public OrderDto createOrder(@RequestBody @Valid OrderDto orderDto) throws ParseException {
|
||||
return new OrderDto(orderService.addOrder(orderDto.getDate(), orderDto.getSum(), orderDto.getUser().getId()));
|
||||
}
|
||||
|
||||
@PostMapping("/coffeeCrossRef")
|
||||
public void createOrderCoffeeCrossRef(@RequestBody @Valid OrderCoffeeCrossRefDto orderCoffeeCrossRefDto) {
|
||||
orderService.createOrderCoffeeCrossRef(orderCoffeeCrossRefDto.getOrderId(), orderCoffeeCrossRefDto.getCoffeeId(), orderCoffeeCrossRefDto.getCount());
|
||||
}
|
||||
|
||||
@DeleteMapping("/coffeeCrossRef/{id}")
|
||||
public void deleteOrderCoffeeCrossRef(@PathVariable Long id) {
|
||||
orderService.deleteOrderCoffeeCrossRef(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.kalyshev.yan.order.controller;
|
||||
|
||||
import com.kalyshev.yan.order.model.Order;
|
||||
import com.kalyshev.yan.user.model.User;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class OrderDto {
|
||||
private Long id;
|
||||
private String date;
|
||||
private Double sum;
|
||||
private User user;
|
||||
public OrderDto(){}
|
||||
public OrderDto(Order order) {
|
||||
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
|
||||
this.id = order.getId();
|
||||
this.date = format.format(order.getDate());
|
||||
this.sum = order.getSum();
|
||||
this.user = order.getUser();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
public Double getSum() {
|
||||
return sum;
|
||||
}
|
||||
public void setSum(Double sum) {
|
||||
this.sum = sum;
|
||||
}
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.kalyshev.yan.order.model;
|
||||
|
||||
import com.kalyshev.yan.user.model.User;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Entity
|
||||
@Table(name = "order_o")
|
||||
public class Order {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date date;
|
||||
private Double sum;
|
||||
@ManyToOne(cascade = {CascadeType.MERGE})
|
||||
@JoinColumn(name = "user_id", unique = false)
|
||||
private User user;
|
||||
public Order(Date date, Double sum, User user) {
|
||||
this.date = date;
|
||||
this.sum = sum;
|
||||
this.user = user;
|
||||
}
|
||||
public Order(Long id, Date date, Double sum, User user) {
|
||||
this.id = id;
|
||||
this.date = date;
|
||||
this.sum = sum;
|
||||
this.user = user;
|
||||
}
|
||||
public Order() {}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
public Double getSum() {
|
||||
return sum;
|
||||
}
|
||||
public void setSum(Double sum) {
|
||||
this.sum = sum;
|
||||
}
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.kalyshev.yan.order.model;
|
||||
|
||||
import com.kalyshev.yan.coffee.model.Coffee;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
@Entity
|
||||
@Table(name = "order_coffee")
|
||||
public class OrderCoffeeCrossRef {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
@ManyToOne(cascade = {CascadeType.MERGE})
|
||||
@JoinColumn(name = "order_id", unique = false)
|
||||
private Order order;
|
||||
@ManyToOne(cascade = {CascadeType.MERGE})
|
||||
@JoinColumn(name = "coffee_id", unique = false)
|
||||
private Coffee coffee;
|
||||
@Column(name = "count")
|
||||
private int count;
|
||||
public OrderCoffeeCrossRef(Order order, Coffee coffee, int count) {
|
||||
this.order = order;
|
||||
this.coffee = coffee;
|
||||
this.count = count;
|
||||
}
|
||||
public OrderCoffeeCrossRef(Long id, Order order, Coffee coffee, int count) {
|
||||
this.id = id;
|
||||
this.order = order;
|
||||
this.coffee = coffee;
|
||||
this.count = count;
|
||||
}
|
||||
public OrderCoffeeCrossRef() {}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
public void setOrder(Order order) {
|
||||
this.order = order;
|
||||
}
|
||||
public Coffee getCoffee() {
|
||||
return coffee;
|
||||
}
|
||||
public void setCoffee(Coffee coffee) {
|
||||
this.coffee = coffee;
|
||||
}
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.kalyshev.yan.order.model;
|
||||
|
||||
import com.kalyshev.yan.coffee.controller.CoffeeDto;
|
||||
import com.kalyshev.yan.coffee.model.Coffee;
|
||||
import com.kalyshev.yan.order.controller.OrderDto;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OrderCoffees {
|
||||
private OrderDto order;
|
||||
private List<Pair<CoffeeDto, Integer>> coffees;
|
||||
public OrderCoffees() {
|
||||
|
||||
}
|
||||
public OrderCoffees(OrderDto order, List<Pair<CoffeeDto, Integer>> coffees) {
|
||||
this.order = order;
|
||||
this.coffees = coffees;
|
||||
}
|
||||
|
||||
public OrderDto getOrder() {
|
||||
return order;
|
||||
}
|
||||
public void setOrder(OrderDto order) {
|
||||
this.order = order;
|
||||
}
|
||||
public List<Pair<CoffeeDto, Integer>> getCoffees() {
|
||||
return coffees;
|
||||
}
|
||||
public void setCoffees(List<Pair<CoffeeDto, Integer>> coffees) {
|
||||
this.coffees = coffees;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.kalyshev.yan.order.repository;
|
||||
|
||||
import com.kalyshev.yan.order.model.OrderCoffeeCrossRef;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface OrderCoffeeCrossRefRepository extends JpaRepository<OrderCoffeeCrossRef, Long> {
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.kalyshev.yan.order.repository;
|
||||
|
||||
public class OrderNotFoundException extends RuntimeException {
|
||||
public OrderNotFoundException(Long id) {
|
||||
super(String.format("Order with id [%s] is not found", id));
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.kalyshev.yan.order.repository;
|
||||
|
||||
import com.kalyshev.yan.coffee.model.Coffee;
|
||||
import com.kalyshev.yan.order.model.Order;
|
||||
import com.kalyshev.yan.order.model.OrderCoffeeCrossRef;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public interface OrderRepository extends JpaRepository<Order, Long> {
|
||||
|
||||
@Query(value = """
|
||||
select * from order_o
|
||||
where order_o.date >= :start_date and order_o.date <= :end_date
|
||||
""", nativeQuery = true)
|
||||
public List<Order> findOrdersByDate(@Param("start_date") Date startDate,
|
||||
@Param("end_date") Date endDate);
|
||||
|
||||
@Query(value = """
|
||||
select new OrderCoffeeCrossRef(ord.id, ord.order, ord.coffee, ord.count) from OrderCoffeeCrossRef ord
|
||||
""")
|
||||
public List<OrderCoffeeCrossRef> findOrderCoffeeCrossRef();
|
||||
|
||||
public Page<Order> findOrdersByUser(Long userId, Pageable pageable);
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package com.kalyshev.yan.order.service;
|
||||
|
||||
import com.kalyshev.yan.coffee.controller.CoffeeDto;
|
||||
import com.kalyshev.yan.coffee.model.Coffee;
|
||||
import com.kalyshev.yan.coffee.repository.CoffeeNotFoundException;
|
||||
import com.kalyshev.yan.coffee.repository.CoffeeRepository;
|
||||
import com.kalyshev.yan.order.controller.OrderCoffeeCrossRefDto;
|
||||
import com.kalyshev.yan.order.controller.OrderDto;
|
||||
import com.kalyshev.yan.order.model.Order;
|
||||
import com.kalyshev.yan.order.model.OrderCoffeeCrossRef;
|
||||
import com.kalyshev.yan.order.model.OrderCoffees;
|
||||
import com.kalyshev.yan.order.repository.OrderCoffeeCrossRefRepository;
|
||||
import com.kalyshev.yan.order.repository.OrderNotFoundException;
|
||||
import com.kalyshev.yan.order.repository.OrderRepository;
|
||||
import com.kalyshev.yan.user.model.User;
|
||||
import com.kalyshev.yan.user.repository.UserNotFoundException;
|
||||
import com.kalyshev.yan.user.repository.UserRepository;
|
||||
import com.kalyshev.yan.util.validation.ValidatorUtil;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class OrderService {
|
||||
private final OrderRepository orderRepository;
|
||||
private final OrderCoffeeCrossRefRepository orderCoffeeCrossRefRepository;
|
||||
private final UserRepository userRepository;
|
||||
private final CoffeeRepository coffeeRepository;
|
||||
private final ValidatorUtil validatorUtil;
|
||||
public OrderService(OrderRepository orderRepository,
|
||||
OrderCoffeeCrossRefRepository orderCoffeeCrossRefRepository,
|
||||
UserRepository userRepository,
|
||||
CoffeeRepository coffeeRepository,
|
||||
ValidatorUtil validatorUtil) {
|
||||
this.orderRepository = orderRepository;
|
||||
this.orderCoffeeCrossRefRepository = orderCoffeeCrossRefRepository;
|
||||
this.userRepository = userRepository;
|
||||
this.coffeeRepository = coffeeRepository;
|
||||
this.validatorUtil = validatorUtil;
|
||||
}
|
||||
@Transactional
|
||||
public Order addOrder(String date, Double sum, Long userId) throws ParseException {
|
||||
if (!StringUtils.hasText(date)) {
|
||||
throw new IllegalArgumentException("Date is null or empty");
|
||||
}
|
||||
if (sum <= 0) {
|
||||
throw new IllegalArgumentException("Sum is null or negative");
|
||||
}
|
||||
if (userId <= 0) {
|
||||
throw new IllegalArgumentException("UserId is null or negative");
|
||||
}
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
|
||||
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
|
||||
final User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException(userId));
|
||||
final Order order = new Order(format.parse(date), sum, user);
|
||||
validatorUtil.validate(order);
|
||||
return orderRepository.save(order);
|
||||
}
|
||||
@Transactional(readOnly = true)
|
||||
public List<Pair<CoffeeDto, Integer>> findCoffeesByOrder(Long orderId) {
|
||||
List<Object[]> coffees = coffeeRepository.findCoffeesByOrder(orderId);
|
||||
List<Pair<CoffeeDto, Integer>> resultCoffees = new ArrayList<>();
|
||||
for (Object[] coffee : coffees) {
|
||||
resultCoffees.add(Pair.of(new CoffeeDto((Coffee) coffee[0]),(Integer) coffee[1]));
|
||||
}
|
||||
return resultCoffees;
|
||||
}
|
||||
@Transactional(readOnly = true)
|
||||
public List<OrderCoffees> findOrdersByDate(String startDate, String endDate) throws ParseException {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ROOT);
|
||||
SimpleDateFormat formatter1 = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
|
||||
Date startDateDate = formatter.parse(startDate);
|
||||
Date endDateDate = formatter.parse(endDate);
|
||||
List<Order> orders = orderRepository.findOrdersByDate(startDateDate, endDateDate);
|
||||
List<OrderCoffees> orderCoffees = new ArrayList<OrderCoffees>();
|
||||
for (Order order : orders) {
|
||||
List<Object[]> coffees = coffeeRepository.findCoffeesByOrder(order.getId());
|
||||
List<Pair<CoffeeDto, Integer>> resultCoffees = new ArrayList<>();
|
||||
for (Object[] coffee : coffees) {
|
||||
resultCoffees.add(Pair.of(new CoffeeDto((Coffee) coffee[0]),(Integer) coffee[1]));
|
||||
}
|
||||
orderCoffees.add(new OrderCoffees(new OrderDto(order), resultCoffees));
|
||||
}
|
||||
return orderCoffees;
|
||||
}
|
||||
@Transactional(readOnly = true)
|
||||
public List<OrderCoffeeCrossRef> findOrderCoffeeCrossRef() {
|
||||
List<OrderCoffeeCrossRef> orderCoffeeCrossRefs = orderRepository.findOrderCoffeeCrossRef();
|
||||
return orderCoffeeCrossRefs;
|
||||
}
|
||||
@Transactional
|
||||
public void createOrderCoffeeCrossRef(Long orderId, Long coffeeId, int count) {
|
||||
final Order order = orderRepository.findById(orderId).orElseThrow(() -> new OrderNotFoundException(orderId));
|
||||
final Coffee coffee = coffeeRepository.findById(coffeeId).orElseThrow(() -> new CoffeeNotFoundException(coffeeId));
|
||||
final OrderCoffeeCrossRef orderCoffeeCrossRef = new OrderCoffeeCrossRef(order, coffee, count);
|
||||
validatorUtil.validate(orderCoffeeCrossRef);
|
||||
orderCoffeeCrossRefRepository.save(orderCoffeeCrossRef);
|
||||
}
|
||||
@Transactional(readOnly = true)
|
||||
public List<Order> findOrderByUser(Long userId, int pageNo, int pageSize, String sortBy, String sortDir) {
|
||||
Sort sort = sortDir.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortBy).ascending()
|
||||
: Sort.by(sortBy).descending();
|
||||
|
||||
// create Pageable instance
|
||||
Pageable pageable = PageRequest.of(pageNo, pageSize, sort);
|
||||
|
||||
Page<Order> orders = orderRepository.findOrdersByUser(userId, pageable);
|
||||
|
||||
// get content for page object
|
||||
List<Order> listOfOrders = orders.getContent();
|
||||
|
||||
return listOfOrders;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteOrderCoffeeCrossRef(Long id) {
|
||||
orderCoffeeCrossRefRepository.deleteById(id);
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import org.springframework.data.repository.query.Param;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
@Query(value = "select * from \"USER_U\" where \"LOGIN\" = :login and \"PASSWORD\" = :password", nativeQuery = true)
|
||||
@Query(value = "select * from user_u where login = :login and password = :password", nativeQuery = true)
|
||||
public Optional<User> tryLogin(@Param("login") String login,
|
||||
@Param("password") String password);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.kalyshev.yan.util.error;
|
||||
|
||||
import com.kalyshev.yan.coffee.repository.CoffeeNotFoundException;
|
||||
import com.kalyshev.yan.order.repository.OrderNotFoundException;
|
||||
import com.kalyshev.yan.user.repository.UserNotFoundException;
|
||||
import com.kalyshev.yan.util.validation.ValidationException;
|
||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||
@ -18,7 +19,8 @@ public class AdviceController {
|
||||
@ExceptionHandler({
|
||||
CoffeeNotFoundException.class,
|
||||
UserNotFoundException.class,
|
||||
ValidationException.class
|
||||
ValidationException.class,
|
||||
OrderNotFoundException.class
|
||||
})
|
||||
public ResponseEntity<Object> handleException(Throwable e) {
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
|
||||
|
@ -1,11 +1,7 @@
|
||||
spring.main.banner-mode=off
|
||||
#server.port=8080
|
||||
spring.datasource.url=jdbc:h2:file:./data
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=password
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.h2.console.enabled=true
|
||||
spring.h2.console.settings.trace=false
|
||||
spring.h2.console.settings.web-allow-others=true
|
||||
spring.sql.init.mode=always
|
||||
spring.sql.init.platform=postgres
|
||||
spring.datasource.url=jdbc:postgresql://109.197.199.134:5432/coffee
|
||||
spring.datasource.username=postgres
|
||||
spring.datasource.password=gAiCyfGGv5TywE
|
||||
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
|
||||
|
Loading…
Reference in New Issue
Block a user