I work on eCommerce app. I use micro-services with ddd. I have product service. It store title description etc. Pricing service store product prices and promotions. Category service store categories and product category. Shipment service store all about shipment data and product shipment details dweight cargo firm isFreeCargo etc.
I dont Want to use composition pattern for searching. I create search service which store all datas of services. Pricing, product information, shipment information, category information etc.
I concat all data with events. Like cQRS
So all services communicate each other with events.
my problem is;
when CreateProductRequest come To product service . It includes categoryId, price, shipmentFirm etc. I mean not only product service information.
I only save title description etc in product service. There is no data like Price or category in product service. because They dont belong this domain. When product created and event raise productCreatedEvent that includes created product id and other service informations come with request.price , category etc.
Other services listen this event. And consume. Pricing save productId and price. Cagegory save productId and categoryId ...
And search service consume event,too. But there is no data about price or category because they just published.
Okey I can prove consistency with events when price change or category After saving. but at first maybe there is not going to be price or category for 2-3 sec.
how canI save category and price for search service immediately. because there is no price and category denormalize and caculated data in productCreatedEvent .There is just reference Ids like categoryId or not caculated price.They are going to be exist on search service after own services save and publish events like ProductCategoryUpdated or ProductPriceCaculeted
.
First of all. What I can see is that price and category services are very related to Product and they dont have strong functionality on its own so I suggest you to merge the three of them in one service. If the price service is used to create promotions, I would make a promotion service wich communicates with product service asking for the price of a product or a category of products, and apply them the corresponding discount.
The first problem has to do with what I have just said, because price, category and product are so related you have to pass all the data when you create a product, but because they are different services, product service should not be aware of this information. In case you want to do this way, you should create prices and categories independently of the product and when these are created each service should send a priceCreated or categoryCreated event that will be consume by anyone interested in. For example the search service.
For the second question, the best approach I think is the first one, first because It wont couple services. The cart service only have the ids no other information. And when you want to query another information you only have to make the query to the proper service as usual, so no coupling is created.
And second, the main drawback of the second option is that you are including logic related to cart service in all the other service. For each one you have to listen events and instead of make logic related to the service like update some info, they are sending info to another service. It is like a hidden command message
Related
I am looking into event sourcing and I have a few thoughts that I need to get my head round.
Take for example an online shop -
The customer adds an item to the basket and saves their order.
The command handler could create an order on the customer aggregate root and add an OrderCreated event which contained the customer id, order id, item id, quantity and unit price. All pretty straight forward but what if the aggregate needed to check to see if that item was on special offer?
If this was for example a basket service would it subscribe to events from the catalog service and store it's own projections of the catalog service which it could then use, so then the basket service would comprise an event store and also some form of projection of the catalog service?
Or if in the example I've just described, if the basket and catalog functionality were part of the same application and they only held event data, then when a customer creates an order the handler would pull all ordered items from the event store via a repository, apply all events to them and then return them to the handler in order to check if the item was on special offer.
what if the aggregate needed to check to see if that item was on special offer?
It needs to execute a query to get the information it needs.
From the aggregate point of view those data are external, so it (or the handler sending the command to it) needs a query to access that information.
How the query work is up to you (there are pros and cons for each way), the query handler can:
Call a repository that loads an aggregate and check for the special offer (you can also think to have event sourcing in just one part of your system and having this part using another way to store dara, or not)
Make a remote call to the Catalog Service API to check for the special offer
Do a query to a local db, that is populated reading events emitted by the catalog service and stored "locally" to the basket service
When working on an application in microservices architecture I stumbled upon issues concerning coupling between services.
This a typical application for ordering products. It seams reasonable to have a service that will operate as a product catalog. Our JavaScript client can ask this service for available products and show them in browser. When user clicks on a product we have to create an order. We would like to manage orders in another service. So an order is created - it means that user X ordered product Y. On the technical level we are simply persisting user id and product id in a database.
To sum up we have:
Products service
Product class:
Product ID, Product Name
Orders service
Order class:
Order ID, Product ID, User ID, Order date
Now let's imagine following scenario - in JavaScript client we would like to list all products that user have ordered. Orders service provides a list of products ids for a given user. But user cares about product name, not the id. Unfortunately Orders service doesn't know anything about products names.
We could tackle this in couple of ways:
Simply assume that the client is responsible for getting the information it needs. So after it calls Orders service and gets a list of products ids, it performs another call to Products service, passing products ids and getting corresponding products names in response. Then the client assembles both responses into something useful. This approach keeps our services clean, without leaking of domain knowledge from one service to another. But it requires more work on the client side.
Orders service when asked for ordered products makes a call on the backend to the Products service. It retrieves product names, assembles a response that contains orderDate and productName and sends that to client. All that's left for client to do is to present the data. Downside of this approach is that Orders service now gains more knowledge about products than neccessary.
Duplicate information about product name in Orders service. When an order is created, we pass not only product id but also product name. That means that Order class will look like this:
Order class:
Order ID, Product ID, Product name, User ID, Order date
Now we can easly provide full information about order without additional call to Products service. Also this time Orders service has too much knowledge about products. What's beneficial tough is that Orders service can provide relevant data even if Products service is down.
Could any of these approaches be considered best practice? Or are there different solutions?
In the eShopOnContainers example( https://github.com/dotnet-architecture/eShopOnContainers ), they add the following fields at the time an order item is created:
public void AddOrderItem(int productId, string productName, decimal unitPrice, decimal discount, string pictureUrl, int units = 1)
This duplicates the catalog information, however as this is a point in time snapshot of the record. This is far safer than linking to the original data.
At this point in the user journey you are in the domain of an order, if a user is viewing an order you can provide a link to the catalogue. However, the order service should be able to operate independently. Linking back to the catalogue for the information on products prevents the Order service owning it's own data.
A nightmare scenario being that a price changes in the catalogue... What would happen to the historic orders?
I've never set a store up to use Price Alerts before, and now that I've gone through and gotten it to work, it appears as though the alert is only triggered when a product's 'Price' attribute changes.
This is nice, but what about tiered pricing? Looking through the ProductAlert core module, I am not sure where this attribute is being filtered.
I'm guessing that an additional model, say 'productalert/tierprice' will need to be created, followed by a new method in Observer.php, likely _processTierprice(). Just not sure if this concept is correct... could use a little guidance.
Thanks!
This shouldn't be too difficult; lots of options (it's Magento, after all)!
I'd add new methods to deal with tier price alerts. For products with tier pricing, you'd need to capture the relevant tier data along with the final price (either in a new table or in new columns on the existing product alert table). The alerts are sent out via scheduled job. So, in a nutshell (overrides where necessary):
Alter the product alert schema as necessary, and amend the frontend form fields to suit
In the overridden Mage_ProductAlert_AddController add a tierPriceAction() method to process the alert subscription, or adjust its existing priceAction() to handle the data being posted in / tier condition
Override Mage_ProductAlert_Model_Observer as needed; I'd include a _processesTierPrice method() similar to _processPrice().
Add a resource model method to get the tier-related prices
Add a tier price email block and template (reference Mage_ProductAlert_Block_Email_Abstract)
Profit!
As a reference for your price logic, see Mage_Catalog_Model_Product_Type_Price.
I would like to programmatically display a discounted price on the product list/page so that each customer as a personal price shown based on a customer attribute (like gender for instance, and of course let it be assigned as new price for the user session) but I can't see a viable option via the magento catalog price rules involving customer attributes other than the assigned group.
I'm using the group to do different kind of discounts and categorization of the customers, so the path of "split the customers on the gender" (or similar) is not an option unfortunately, since I can't assign more than 1 group per customer.
At the moment I was thinking about setting up a custom observer to check for calls to the price generation and then let it consider my customer attributes when calculating the price.
Is that possible? if so, any pointers about?
Would you suggest something different?
Thanks a lot to everyone for your time.
As I was thinking before, I solved my issue creating a custom module with an observer looking for catalog_product_get_final_price calls, getting the customer details from the current customer session.
It works great, I just need to let it display the correct price in the catalog product list, but is minimal, as the price seems to be calculated correctly inside the product page and the cart
We are using Microsoft CRM 4.0 to run a consulting business. Its working pretty well but we want to simplify the way we are doing some things. What we want to do is create an Order (salesorder) with multiple Order Products (salesorderdetal). So good so far.
Next I want to be able associate each Order Product (salesorderdetail) with a Service Activity (serviceappointment), this representing that this billable line item in the order is actually going to be fulfilled as a consuting engagement.
The problem is, I can't seem to be able to create an association between the Order Product (salesorderdetail) and Service Activiy (serviceappointment). It simply doesn't appear in the drop downlist.
Can anyone think of a reason for this? I've seen some posts about relating field mapping between Quote Product, Order Product, Opportunity Product and Invoice Product, but that isn't quite what I am after.
Any suggestions gratefully received - even if it is an explaination of why its not possible.
I created a simple 1:N mapping from Case to Invoice. The Case records its ID and Title in custom fields in the Invoice. Unfortunately this does not allow for product creation as children of the Invoice, so that should be created as a custom code workflow.