diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..a1c1dba --- /dev/null +++ b/readme.md @@ -0,0 +1,301 @@ +# UNQ » UIs » Dominio » MercadoLibre +[![](https://jitpack.io/v/unq-ui/mercadolibre-model.svg)](https://jitpack.io/#unq-ui/mercadolibre-model) + +Construcción de Interfaces de Usuario, Universidad Nacional de Quilmes. + +### Dependencia + +Agregar el repositorio: + +```xml + + + jitpack.io + https://jitpack.io + + +``` + +Agregar la dependencia: + +```xml + + com.github.unq-ui + ?? + ?? + +``` + +### Interfaz de uso + +```kotlin +class MercadoLibreService { + private val idGenerator = IdGenerator() + val products: MutableList = mutableListOf() + val users: MutableList = mutableListOf() + val categories: MutableList = mutableListOf() + val carts: MutableList = mutableListOf() + + /** + * Registers a new user. + * @param draftNewUser The draft user data. + * @return The registered user. + * @throws UserException if the email is already registered. + */ + fun registerNewUser(draftNewUser: DraftNewUser): User + + /** + * Retrieves a user by email and password. + * @param email The user's email. + * @param password The user's password. + * @return The user. + * @throws UserException if the user is not found. + */ + fun getUser(email: String, password: String): User + + /** + * Retrieves a user by id. + * @param id The user's id. + * @return The user. + * @throws UserException if the user is not found. + */ + fun getUser(id: String): User + + /** + * Toggles the like status of a product for a user. + * @param idUser The user's ID. + * @param idProduct The product's ID. + * @return The updated user. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ + fun toggleLike(idUser: String, idProduct: String): User + + /** + * Adds a new category. + * @param name The category name. + * @return The added category. + * @throws CategoryException if the category already exists. + */ + fun addCategory(name: String): Category + + /** + * Retrieves all categories. + * @return The list of categories. + */ + fun getAllCategories(): List + + /** + * Adds a new product. + * @param userId The user's ID. + * @param draftProduct The draft product data. + * @return The added product. + * @throws UserException if the user is not found. + */ + fun addProduct(userId: String, draftProduct: DraftProduct): Product + + /** + * Edits an existing product. + * @param userId The user's ID. + * @param productId The product's ID. + * @param draftProduct The draft product data. + * @return The edited product. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + * @throws ProductException if the user is not the owner of the product. + */ + fun editProduct(userId: String, productId: String, draftProduct: DraftProduct): Product + + /** + * Retrieves a product by ID. + * @param id The product's ID. + * @return The product. + * @throws ProductException if the product is not found. + */ + fun getProduct(id: String): Product + + /** + * Retrieves products by user ID with pagination. + * @param idUser The user's ID. + * @param pageNumber The page number. + * @return A Page of products. + */ + fun getProductsByUser(idUser: String, pageNumber: Int): Page + + /** + * Retrieves products by category ID with pagination. + * @param idCategory The category's ID. + * @param pageNumber The page number. + * @return A page of products. + */ + fun getProductsByCategory(idCategory: String, pageNumber: Int): Page + + /** + * Searches for products by text with pagination. + * @param text The search text. + * @param pageNumber The page number. + * @return A page of products. + */ + fun searchProducts(text: String, pageNumber: Int): Page + + /** + * Updates the quantity of a product in the user's cart. + * @param userId The user's ID. + * @param productId The product's ID. + * @param amount The quantity to update. + * @return The updated cart. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ + fun updateItemCart(userId: String, productId: String, amount: Int): Cart + + /** + * Deletes a product from the user's cart. + * @param userId The user's ID. + * @param productId The product's ID. + * @return The updated cart. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ + fun deleteItemFromCart(userId: String, productId: String): Cart + + /** + * Retrieves the cart for a user. + * @param id The user's ID. + * @return The cart. + * @throws UserException if the user is not found. + */ + fun getCart(id: String): Cart + + /** + * Completes a purchase for a user. + * @param idUser The user's ID. + * @param payment The payment information. + * @throws BuyException if the cart is empty or items are out of stock. + * @throws UserException if the user is not found. + */ + fun purchase(idUser: String, payment: Payment) + + /** + * Adds a question to a product. + * @param idUser The user's ID. + * @param idProduct The product's ID. + * @param question The question text. + * @return The updated product. + * @throws QuestionException if the user is the owner of the product. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ + fun addQuestion(idUser: String, idProduct: String, question: String): Product + + /** + * Adds an answer to a question on a product. + * @param idUser The user's ID. + * @param idProduct The product's ID. + * @param idQuestion The question's ID. + * @param text The answer text. + * @return The updated product. + * @throws QuestionException if the user is not the owner of the product or the question is not found. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ + fun addAnswer(idUser: String, idProduct: String, idQuestion: String, text: String): Product +} +``` + +### Iniciar el sistema con datos + +```kotlin +val system = initSystem() +``` + +[Ver usuarios del sistema](https://github.com/unq-ui/mercadolibre-model/blob/main/resources/users.json) + +### Modelo + +```kotlin +class Product( + val id: String, + val owner: User, + var title: String, + var description: String, + var images: MutableList, + var stock: Int, + var price: Double, + var shipping: Shipping, + var characteristics: MutableList, + var category: Category, + val questions: MutableList, +) + +class User( + val id: String, + var name: String, + val email: String, + var password: String, + val image: String, + val buyHistory: MutableList, + val products: MutableList, + val likedProducts: MutableList, + val salesHistory: MutableList +) + +class Category(val id: String, val name: String) + +class Characteristic(val name: String, val value: String) + +class Shipping(var price: Double) + +class SaleHistory( + val product: Product, + val amount: Int, + val payment: Payment, + val date: LocalDateTime, + val user: User, +) + +class BuyHistory( + val items: MutableList, + val payment: Payment, + val date: LocalDateTime, +) + +class Question (val id: String, val product: Product, val user: User, val text: String, var response: String?) + +class Unit (val product: Product, var amount: Int) + +class Cart( + val user: User, + val items: MutableList +) + +class Payment ( + val cardNumber: String, + val expirationDate: LocalDateTime, + val cvv: String, + val name: String, +) +``` + +* El MercadoLibreService es el encargado de setear los ids de cada elemento que se agrega el sistema. +* Para simplificar se utilizan objetos draft + +```kotlin +class DraftNewUser( + val name: String, + val email: String, + val password: String, + val image: String, +) + +class DraftProduct( + val title: String, + val description: String, + var price: Double, + val images: MutableList, + val stock: Int, + val shipping: Shipping, + val characteristics: MutableList, + val category: Category, +) +``` diff --git a/src/main/kotlin/data/Bootstrap.kt b/src/main/kotlin/data/Bootstrap.kt index ea7bb74..fa4bf14 100644 --- a/src/main/kotlin/data/Bootstrap.kt +++ b/src/main/kotlin/data/Bootstrap.kt @@ -159,7 +159,7 @@ fun addPurchases(mercadoLibreService: MercadoLibreService) { } } if (random.nextBoolean()) { - mercadoLibreService.buy(user.id, getPayment()) + mercadoLibreService.purchase(user.id, getPayment()) } } } diff --git a/src/main/kotlin/model/DataClasses.kt b/src/main/kotlin/model/DataClasses.kt index ea44b0c..abbf3b0 100644 --- a/src/main/kotlin/model/DataClasses.kt +++ b/src/main/kotlin/model/DataClasses.kt @@ -6,8 +6,6 @@ class Category(val id: String, val name: String) class Characteristic(val name: String, val value: String) -class Notification(val text: String) - class Shipping(var price: Double) class Product( diff --git a/src/main/kotlin/service/MercadoLibreService.kt b/src/main/kotlin/service/MercadoLibreService.kt index 1acb29b..8e9a402 100644 --- a/src/main/kotlin/service/MercadoLibreService.kt +++ b/src/main/kotlin/service/MercadoLibreService.kt @@ -12,6 +12,12 @@ class MercadoLibreService { val categories: MutableList = mutableListOf() val carts: MutableList = mutableListOf() + /** + * Registers a new user. + * @param draftNewUser The draft user data. + * @return The registered user. + * @throws UserException if the email is already registered. + */ fun registerNewUser(draftNewUser: DraftNewUser): User { if (users.any { it.email == draftNewUser.email}) { throw UserException("The email is already registered.") @@ -31,14 +37,35 @@ class MercadoLibreService { return user } + /** + * Retrieves a user by email and password. + * @param email The user's email. + * @param password The user's password. + * @return The user. + * @throws UserException if the user is not found. + */ fun getUser(email: String, password: String): User { return users.find { it.email == email && it.password == password } ?: throw UserException("Not found") } + /** + * Retrieves a user by id. + * @param id The user's id. + * @return The user. + * @throws UserException if the user is not found. + */ fun getUser(id: String): User { return users.find { it.id == id } ?: throw UserException("Not found") } + /** + * Toggles the like status of a product for a user. + * @param idUser The user's ID. + * @param idProduct The product's ID. + * @return The updated user. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ fun toggleLike(idUser: String, idProduct: String): User { val user = getUser(idUser) val product = getProduct(idProduct) @@ -48,6 +75,12 @@ class MercadoLibreService { return user } + /** + * Adds a new category. + * @param name The category name. + * @return The added category. + * @throws CategoryException if the category already exists. + */ fun addCategory(name: String): Category { if (categories.any { it.name == name}) { throw CategoryException("The category already exists.") @@ -57,8 +90,19 @@ class MercadoLibreService { return category } + /** + * Retrieves all categories. + * @return The list of categories. + */ fun getAllCategories(): List = categories + /** + * Adds a new product. + * @param userId The user's ID. + * @param draftProduct The draft product data. + * @return The added product. + * @throws UserException if the user is not found. + */ fun addProduct(userId: String, draftProduct: DraftProduct): Product { val user = getUser(userId) val product = Product( @@ -80,6 +124,16 @@ class MercadoLibreService { return product } + /** + * Edits an existing product. + * @param userId The user's ID. + * @param productId The product's ID. + * @param draftProduct The draft product data. + * @return The edited product. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + * @throws ProductException if the user is not the owner of the product. + */ fun editProduct(userId: String, productId: String, draftProduct: DraftProduct): Product { val user = getUser(userId) val product = getProduct(productId) @@ -94,25 +148,58 @@ class MercadoLibreService { return product } + /** + * Retrieves a product by ID. + * @param id The product's ID. + * @return The product. + * @throws ProductException if the product is not found. + */ fun getProduct(id: String): Product { return products.find { it.id == id } ?: throw ProductException("Not found") } + /** + * Retrieves products by user ID with pagination. + * @param idUser The user's ID. + * @param pageNumber The page number. + * @return A Page of products. + */ fun getProductsByUser(idUser: String, pageNumber: Int): Page { val filteredProducts = products.filter { it.owner.id == idUser } return getPage(filteredProducts, pageNumber) } + /** + * Retrieves products by category ID with pagination. + * @param idCategory The category's ID. + * @param pageNumber The page number. + * @return A page of products. + */ fun getProductsByCategory(idCategory: String, pageNumber: Int): Page { val filteredProducts = products.filter { it.category.id == idCategory } return getPage(filteredProducts, pageNumber) } + /** + * Searches for products by text with pagination. + * @param text The search text. + * @param pageNumber The page number. + * @return A page of products. + */ fun searchProducts(text: String, pageNumber: Int): Page { val filteredProducts = products.filter { it.title.contains(text, true) || it.description.contains(text, true)} return getPage(filteredProducts, pageNumber) } + /** + * Updates the quantity of a product in the user's cart. + * @param userId The user's ID. + * @param productId The product's ID. + * @param amount The quantity to update. + * @return The updated cart. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ fun updateItemCart(userId: String, productId: String, amount: Int): Cart { val cart = getCart(userId) val product = getProduct(productId) @@ -121,6 +208,14 @@ class MercadoLibreService { return cart } + /** + * Deletes a product from the user's cart. + * @param userId The user's ID. + * @param productId The product's ID. + * @return The updated cart. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ fun deleteItemFromCart(userId: String, productId: String): Cart { val cart = getCart(userId) val product = getProduct(productId) @@ -128,6 +223,12 @@ class MercadoLibreService { return cart } + /** + * Retrieves the cart for a user. + * @param id The user's ID. + * @return The cart. + * @throws UserException if the user is not found. + */ fun getCart(id: String): Cart { return carts.find { it.user.id == id } ?: run { val cart = Cart(getUser(id), mutableListOf()) @@ -136,7 +237,14 @@ class MercadoLibreService { } } - fun buy(idUser: String, payment: Payment) { + /** + * Completes a purchase for a user. + * @param idUser The user's ID. + * @param payment The payment information. + * @throws BuyException if the cart is empty or items are out of stock. + * @throws UserException if the user is not found. + */ + fun purchase(idUser: String, payment: Payment) { val user = getUser(idUser) val cart = getCart(idUser) if (cart.items.isEmpty()) throw BuyException("Cart is empty") @@ -154,6 +262,16 @@ class MercadoLibreService { } } + /** + * Adds a question to a product. + * @param idUser The user's ID. + * @param idProduct The product's ID. + * @param question The question text. + * @return The updated product. + * @throws QuestionException if the user is the owner of the product. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ fun addQuestion(idUser: String, idProduct: String, question: String): Product { val user = getUser(idUser) val product = getProduct(idProduct) @@ -162,6 +280,17 @@ class MercadoLibreService { return product } + /** + * Adds an answer to a question on a product. + * @param idUser The user's ID. + * @param idProduct The product's ID. + * @param idQuestion The question's ID. + * @param text The answer text. + * @return The updated product. + * @throws QuestionException if the user is not the owner of the product or the question is not found. + * @throws UserException if the user is not found. + * @throws ProductException if the product is not found. + */ fun addAnswer(idUser: String, idProduct: String, idQuestion: String, text: String): Product { val user = getUser(idUser) val product = getProduct(idProduct) diff --git a/src/test/kotlin/service/MercadoLibreServiceTest.kt b/src/test/kotlin/service/MercadoLibreServiceTest.kt index 0bccddd..d06f380 100644 --- a/src/test/kotlin/service/MercadoLibreServiceTest.kt +++ b/src/test/kotlin/service/MercadoLibreServiceTest.kt @@ -310,7 +310,7 @@ class MercadoLibreServiceTest { } @Test - fun buyTest() { + fun purchaseTest() { val mercadoLibreService = MercadoLibreService() val seller = mercadoLibreService.registerNewUser(getDraftNewUser("example")) val buyer = mercadoLibreService.registerNewUser(getDraftNewUser("user")) @@ -322,7 +322,7 @@ class MercadoLibreServiceTest { assertEquals(p1.stock, 10) val payment = Payment("3333", LocalDateTime.now(), "333", "pepe") - mercadoLibreService.buy(buyer.id, payment) + mercadoLibreService.purchase(buyer.id, payment) assertEquals(seller.salesHistory.size, 1) assertEquals(seller.salesHistory[0].amount, 1) @@ -337,16 +337,16 @@ class MercadoLibreServiceTest { } @Test - fun buyWithoutItemsTest() { + fun purchaseWithoutItemsTest() { val mercadoLibreService = MercadoLibreService() val buyer = mercadoLibreService.registerNewUser(getDraftNewUser("user")) assertFailsWith { - mercadoLibreService.buy(buyer.id, Payment("3333", LocalDateTime.now(), "333", "pepe")) + mercadoLibreService.purchase(buyer.id, Payment("3333", LocalDateTime.now(), "333", "pepe")) } } @Test - fun buyMoreItemsThanStockTest() { + fun purchaseMoreItemsThanStockTest() { val mercadoLibreService = MercadoLibreService() val seller = mercadoLibreService.registerNewUser(getDraftNewUser("example")) val buyer = mercadoLibreService.registerNewUser(getDraftNewUser("user")) @@ -354,7 +354,7 @@ class MercadoLibreServiceTest { mercadoLibreService.updateItemCart(buyer.id, p1.id, 100) assertFailsWith { - mercadoLibreService.buy(buyer.id, Payment("3333", LocalDateTime.now(), "333", "pepe")) + mercadoLibreService.purchase(buyer.id, Payment("3333", LocalDateTime.now(), "333", "pepe")) } }