railseventstore / ecommerce Goto Github PK
View Code? Open in Web Editor NEWApplication with CQRS and Event Sourcing built on Rails and Rails Event Store
License: MIT License
Application with CQRS and Event Sourcing built on Rails and Rails Event Store
License: MIT License
At the moment we have some hardcoded clients for whom we can create orders.
This issue is meant to be a small step towards a more typical ecommerce where clients can create their orders.
However, for now let's just start with displaying the existing orders for the specific client.
Authentication could be part of this ticket, but we can also have a temporary shortcut of "selecting" the client which we want to log-in as.
It could be a new route like /client
and then a new read model - ClientOrders
.
Moving ItemAddedToBasket and ItemRemovedFromBasket events to the Pricing BC caused that Ordering::Order can no longer protect its business rule of not adding items after order submission.
There had been raise AlreadySubmitted unless @state.equal?(:draft)
before
At the moment the processes are testes mostly via the integration tests.
Also, they are ignored by mutant (almost always a technical debt).
The goal of this ticket is to cover our processes with unit tests.
I'd aim for unit tests where events are the input and commands are the expected output.
However, they do have the drawback of risking being out of sync (when the published events are changed), but I hope this will be caught at integration level.
To whowever is interested in helping here, feel free to approach the process one by one. Just create a ticket per each process.
Currently we have infinite retries which in some cases can lead to crashing the app.
See more at: https://blog.arkency.com/limit-your-automatic-retries/
The scope is limited to only displaying the price on the new order
page.
This will get us closer to the total_value
functionality and later to payments
feature.
This feature allows customers to get 1 item free when they buy 3 items.
The orders screen becomes messy after some time.
Let's allow to archive specific orders - they would then disappear from the main screen.
This feature allows customers to "subscribe" to a product.
For the shop owner it allows to sell more and increase customer loyalty.
Customers interested in a specific product which is not available at the moment.
It might be a product which they bought already (and a product which makes sense to buy regularly). This means it targets existing clients.
Also, new clients who are simply interested in that one product.
Instead of silently leaving the shop, we want them to subscribe for the product.
We can look which products are mostly waited on and introduce them to the offer without a risk, potentially with a bigger margin.
We sell more stuff at a bigger margin.
We collect more emails.
Add a link on a ProductPage - notify me when available.
When logged in client, show green confirmation. If not logged in - show link to login or field for email (without logging in).
Schedule an email when a product is available.
Add link also to ProductList pages.
When notifying by email present a link to a cart with this item in the cart.
Add notifications system to the store and show unread notification there.
What are the acceptance scenarios?
It used to be the part of admin panel. Later it was removed, but the code under the hood is still there and tested.
Let's add this feature to the UI.
As of recently, we've only had a check if customer id is not nil. What was missing and still is missing is to check whether a customer exists.
In a way, the check is there but only in the form of a read model coupling:
order.customer = Customer.find(event.data[:customer_id]).name
One option is to create a check in the SubmitOrder
cmd handler. Another (better?) would be to turn the OrderSubmission process into actual process manager. This resembles a typical "checklist" characteristical to process managers.
Once we allow archiving old orders - let's have a UI for accessing them.
For invoicing we sync from ProductRegistered where it sounds better to react to ProductNamed, especially once we allow changing the name of the product.
Sometimes a client may negotiate well and try to improve the discount. Let's allow it to happen.
Currently, a client can "log in" by navigating to /client
URL, selecting desired client name, and clicking the login
button.
The outcome of this issue should be a possibility to log in using the client login and password.
Right now the system is more an order management system. Let's build a simple cart system. The simplest possible. Just adding/removing from cart. Confirming. Later we will extend it.
Rails application is a web delivery mechanism for this ecommerce app. The contexts can live above the application to signify their independence. This can also draw greater line between write and read models — there they belong.
What's more — we can reuse contexts in applications based on different frameworks. Or even in different applications.
Recently I’ve introduced technical debt by adding not so nice the if statement
to the update_discount
action:
ecommerce/rails_application/app/controllers/orders_controller.rb
Lines 35 to 54 in ad00da4
We would like to improve this code and make tech debt disappear.
Issues to resolve:
All suggestions on how to resolve this issue are greatly appreciated!
We want to reuse some of the existing BCs.
Gathering them in one directory sounds like a good step forward. Also, this may be a good experiment in the popular topic of "in what directories should we put the domain code".
A simple UI for adding products with price within ProductCatalog CRUD-ish BC.
Currently, when a user logs in as a specific client /client
they see a list of submitted orders. Paid, Expired and Cancelled orders are also visible. The user has the possibility to navigate to a specific order and see its details by clicking the order's number.
Then they're redirected to that order at /orders/id
URL. The /orders
URL is dedicated to being used by the shops' staff, not the client itself.
Therefore new view should be created for the client to see its orders. The view should contain ordered items and their final price.
As a client, I would like to see the estimated price of my order before I place it. The estimation should include possible discounts that I may get or use.
Currently the validation for uniqueness on registering coupons and creating happy hours is very simple - based on id
only. If there is a coupon with a same id, the aggregate will mark it as @registered = true
and raise an AlreadyRegistered
error when somebody tries to register is again.
You can see it here - https://github.com/RailsEventStore/ecommerce/blob/0c4d8d0305c4ee6554e64789c32451c7ad826e81/ecommerce/pricing/lib/pricing/coupon.rb
It would be good to have some other uniqueness validation - eg. on the code
attribute (in both coupons and happy hours). I'm not telling where such validation should be added. I'd say this is part of the exercise to decide about it.
This feature allows setting a certain period of time when a price of a certain product (or a list of products) is different.
Now in some places it's event store.
(another debate how to rename this object)
With the current high level of decoupling between our components (BC, read models, processes) it feels like we could speedup CI/CD process by only running those component tests which could potentially be impacted by the change.
Anyone knows how to start with this?
The idea here is to use RES browser. It's already used but the stream which we show doesn't contain all the data.
We can show the Orders read model as a stream (it's not yet a stream, but we can make it a stream). This would work, but it feels a bit like coupling this stream for two purposes:
Maybe as the first step, this coupling is fine.
Creating an explicit stream per read model sounds like a very good thing to do, anyway. This will simplify the process of rebuilding orders and show it as an example education-wise.
Let's create a new menu item called "Shipments".
A list of those orders which have Shipment assigned will appear.
Probably we only need to react to "Shipment*" events.
The output would be an ActiveRecord model ShipmentsList::Shipment with shipment_id/order_id, address, status.
Currently we allow setting orders discount via the UI. It would be nice to be able to remove them
Keep in mind we're using product names in the Invoicing.
See also https://github.com/RailsEventStore/ecommerce/issues/145
The first implementation of HappyHour is not very useful in the context of ecommerce - it is a daily recurring promotion on products, while in ecommerce it's a rare use case. More often we need a one-time promotion constrained in time.
At the same time, this implementation had other flaws. It was:
As the next iteration we want to change it, simplify and get rid of some flaws at the same time.
The change - we will have TimePromotion instead of HappyHour.
It won't be a recurring promotion (for now), but just bounded by the start_time
and end_time
.
It won't be checking if there is an overlapping promotion, promotions can be stacked.
It won't be applied to a specific product, but rather to all products.
Steps to reproduce:
Setup database and then for example run rake db: seed
a couple of times (seeds are using commands)
There is some code that is supposed to raise an error, and it even has a test, but it seems the test are false positives
Both the products and customers have multiple duplicates (same attributes, different ids). Seems resonable that this state should not be allowed
we have a call to CRM module to grab the customer name.
Ideally this shouldn't exist. What options do we have to get rid of it?
In ideal world integration tests shouldn't use commands. Commands are hidden as the black box in the application.
Integration tests are the top of the testing pyramid and should assume as minimal internals as possible.
We should test via the HTTP layer instead.
Sometimes, when for some reason, certain data changes are not possible via the http, then using commands is allowed.
Also, when a feature is in progress, it might be a good idea to start with commands in the integration test but over time replace with "UI simulation".
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.