https://github.com/iobruno/kotlin-shop
Kotlin Shop (eCommerce Pet Project)
https://github.com/iobruno/kotlin-shop
gradle-kotlin-dsl kotlin kotlin-language kotlin-learning
Last synced: 5 months ago
JSON representation
Kotlin Shop (eCommerce Pet Project)
- Host: GitHub
- URL: https://github.com/iobruno/kotlin-shop
- Owner: iobruno
- Created: 2018-09-28T16:24:53.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2025-02-02T07:53:16.000Z (5 months ago)
- Last Synced: 2025-02-06T19:50:17.715Z (5 months ago)
- Topics: gradle-kotlin-dsl, kotlin, kotlin-language, kotlin-learning
- Language: Kotlin
- Homepage:
- Size: 142 KB
- Stars: 5
- Watchers: 2
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Kotlin Shop
[](https://github.com/JetBrains/kotlin/releases/tag/v2.1.10)
[](https://sdkman.io/)
[](https://kotest.io/docs/framework/testing-styles.html)
[](https://junit.org/junit5/)
[](https://gradle.org/releases/)
[](https://codecov.io/gh/iobruno/kotlin-shop)
[](https://codeclimate.com/github/iobruno/kotlin-shop/maintainability)This is just a pet project of mine to play with Kotlin stdlib
For this, I'm simulating an eCommerce platform as close as I can, model-wise.
I took inspiration based on my understanding of how Amazon handles Physical, Digital and Subscription Orders## Getting Started
```kotlin
fun main() {val cart = ShoppingCart()
.add(Product("PS4 Slim 1TB", ProductType.PHYSICAL, 1899.00), 1)
.add(Product("PDP Chair", ProductType.PHYSICAL, 399.00), 2)
.add(Product("Cracking the Code Interview", ProductType.PHYSICAL_TAX_FREE, 219.57), 2)
.add(Product("The Hitchhiker's Guide to the Galaxy", ProductType.PHYSICAL_TAX_FREE, 120.00), 1)
.add(Product("Stairway to Heaven", ProductType.DIGITAL, 5.00), 1)
.add(Product("Nier:Automata", ProductType.DIGITAL, 129.90), 4)
.add(Product("Netflix Familiar Plan", ProductType.SUBSCRIPTION, 29.90), 1)
.add(Product("Spotify Premium", ProductType.SUBSCRIPTION, 14.90), 1)
.add(Product("Amazon Prime", ProductType.SUBSCRIPTION, 12.90), 1)val account = Account("john doe", "[email protected]", "passwd")
val orders = cart.checkout(account)// Pick one or Iterate through the orders
val physicalOrder = orders.first { it.type == OrderType.PHYSICAL } as PhysicalOrder
val digitalOrder = orders.first { it.type == OrderType.DIGITAL } as DigitalOrder
val subscriptionOrder = orders.first { it.type == OrderType.SUBSCRIPTION } as SubscriptionOrderval address = Address.builder
.country("Brazil")
.city("Sao Paulo")
.state("SP")
.zipCode("01000-000")
.streetAddress("Av Paulista, 1000")
.build()val myCreditCard = CreditCard(
nameOnCard = "John Doe",
number = "123.456.789-00",
securityCode = 123,
expiresAt = YearMonth.of(2027, 7),
billingAddress = address
)val physicalOrderInvoice = physicalOrder
.withShippingAddress(address)
.withPaymentMethod(myCreditCard)
.place()
.pay()
.invoice()val digitalOrderInvoice = digitalOrder
.withPaymentMethod(myCreditCard)
.place()
.pay()
.invoice()val membershipOrderInvoice = subscriptionOrder
.withPaymentMethod(myCreditCard)
.place()
.pay()
.invoice()
}
```## Application Design
### Product, ProductType
These are pretty self explanatory, right ? :)
ProductType has an enum parameter, mapping to what kind of Order that product would be in### Item
Represents a given amount of Product in the `Shopping Cart` or in an `Order`
### Order
Represents an interface defining the implementations for Physical, Digital and Membership Orders,
each with its own set of rules for `place()`, `pay()`, `fulfill()` and `complete()`### PhysicalOrder
May only contain products which the `ProductType` is 'Physical' or 'PHYSICAL_TAX_FREE'
- `place()`:
- Setups the Packaging for Shipping
- Includes a `Shipping and Handling` cost of extra $10 per package
- Ready the order to the `PENDING` status
- **Note**: Provided that there are items that fall under the `PHYSICAL_BOOK` category, they're grouped together into another shipment with the label `TAX_FREE`
- `pay()`:
- Provided that the Order has been placed, and not yet payed:
- `//TODO:` Process the Payment
- Updates the OrderStatus to `UNSHIPPED`
- `fulfill()`:
- Provided that the order has been payed and not yet shipped:
- `//TODO:` Notifies the seller to fulfill/process the Order on its end
- Updates the OrderStatus to `SHIPPED`
- `complete()`:
- `// TODO:`: Track the packages/shipment they're all delivered
- Updates the OrderStatus to `DELIVERED`
### Digital OrderMay only contain products which the `ProductType` is 'Digital'
- `place()`:
- Includes a `Voucher` discount of $10 for the Order
- Ready the order to the `PENDING` status
- `pay()`:
- Provided that the Order has been placed, and not yet payed:
- `//TODO:` Process the Payment
- Updates the OrderStatus to `UNSENT`
- `fulfill()`:
- Provided that the order has been payed and not yet sent:
- `//TODO:` Notifies the seller to fulfill/process the Order on its end
- Updates the OrderStatus to `SENT`
- `complete()`:
- `// TODO:`: Track when the the Buyer clicks on the emailed link to redeem the item
- Updates the OrderStatus to `REDEEMED`### SubscriptionOrder
May only contain products which the `ProductType` is 'Subscription'
- `place()`:
- Ensures there's only one Subscription per Order
- Ready the order to the `PENDING` status
- **Note**: In a scenario with multiple `Membership` Items in the Shopping Cart,
each will spawn a different Order
- `pay()`:
- Provided that the Order has been placed, and not yet payed:
- `//TODO:` Process the Payment
- Updates the OrderStatus to `PENDING_ACTIVATION`
- `fulfill()`:
- Provided that the order has been payed and not yet activated:
- `//TODO:` Activates the Subscription Service
- Updates the OrderStatus to `ACTIVATED`
### ShoppingCart
To better simulate the user experience in an e-commerce platform,
and also to wrap all the complexity of creating an Order, this Shopping Cart entity was created- `add(product: Product, n: Int)`:
- Adds the N-amounts of the given `product` to the shopping Cart
- **Note**: if the product is already in the Cart, adds up in the quantity
- `updateQuantity(product: Product, n: Int)`:
- Overrides whatever amount there is of the given `product` wih the specified `n` amount.
If `(n == 0)`, the product is deleted from the cart
- `delete(product: Product)` Deletes the product from the cart regardless of the quantity- `subtotal()` Computes the sum of (unittest price of each product in the Cart * quantity)
- `checkout(account: Account)`:
- All items that fall under `Physical` (regardless if their product category will be tax-free on Shipment or not)
are grouped together to create a `PhysicalOrder`
- All items that fall under `Digital` are grouped together to create a `DigitalOrder`
- Each item that falls under `Membership` will create a different Membership Order
(due to the complexity of activating each subscription individually, and probably through 3rd-party APIs)## TODO's:
- [x] Build Automation with CI (Travis CI)
- [x] Code Coverage check
- [x] Code Inspection for maintainability
- [x] GitHub CI