Possibly wrong transaction status in Shopware 6 mails? - shopware6

All e-mail templates in Shopware 6 reference the transactions payment name and current state by using the first collection entry order.transactions.first.paymentMethod.translated.name and
order.transactions.first.stateMachineState.translated.name.
Is the transaction sorting for e-mails different that the default sorting by createdAt?
Because according to all code examples I have found so far (e.g. AccountOrderPageLoader) the transactions are normally sorted by createdAt.
Based on the sortings I would expect e-mails to show a wrong payment method if the customer switches the payment method after ordering.
So my question is:
Shouldn't all e-mail templates reference the last entry of the transactions collection to really show the latest state? Or is the sorting for e-mails changed somewhere else?
Thanks for clarification.

I think this is a valid concern but given the standard procedures shouldn't become an issue. This is because when using the StateMachineRegistry to transition from one state to another, the existing state entity is being updated instead of a new one being inserted. So if the transition model is being used as it is intended, there should only be one state per combination of order and payment/delivery method that gets updated, with the former states being persisted as state_machine_history entities to retrace state changes.
Technically however, given that the associations are instances of OneToManyAssociationField, it is obviously possible to persist multiple entities of order_transaction or order_delivery per order when using the corresponding repositories. I think the reason for this relation model being used was to, in the future, potentially allow multiple delivery/payment methods when placing a single order. However this currently isn't implemented which is why it is important to use the proper services to transition between states as explained.

Related

GraphQL: Modeling evolving types / state transitions

This is an issue we have ran into multiple times now... very much looking forward to others' opinions!
Scenario Description (for illustration purposes):
Somebody visits our website, perhaps they fill out some forms, whatever. To us, this person is a prospect/lead. They have not been fully onboarded as a customer; they are simply a potential future customer.
Certain actions can be performed on these Prospects, such as adding certain data to their profile. Let's call this add_foobar_data. Of course, if they become a real customer (somebody consuming our service), we still need to be able to add/remove said data from their account.
Scenario (tl;dr):
Prospects can become Customers
Mutation add_foobar_data conceptually applies to both Prospects and Customers
Prospects only have a subset of data of Customers (they are a true subset; currently Customers have a lot of non-nullable fields Prospects do not have)
Options:
Create a union type, e.g. Customerable. add_foobar_data would return a Customerable (or backref to a Customerable) rather than a specific type.
Create separate mutations for modifying Prospects and Customers (add_foobar_data_to_prospect, add_foobar_data_to_customer)
Everybody is a Customer! Make all those non-nullable fields on Customer that are not in Prospect nullable and add a new flag called isProspect (or isDraft if we want to change how we think about the flow).
Perhaps some other approach I did not think of...
Anybody have thoughts on what is the best approach to this situation and why?
Ended up using an Interface since Prospect is a direct subset of Customer, and not by coincidence.

How can we treat different meanings of delete in our domain model

I have two questions related to Udi Dahan's article : Don’t Delete – Just Don’t
Sometimes we do need delete, the user (domain expert) request the delete functionality(the real meaning) for wrong data, Say the HR user has a form to add employees and he inserted wrong employee data, He wants to delete this data, It's not used in business yet and it's totally different from Retire or Fire an employee. How to handle the two cases in implementation?
How to make the UI more representative for this case ? using two buttons One shown only if we can DELETE employee and the other if we want to RETIRE employee ?
If the business wants this functionality and if they speak this words then it means they are part of the Ubiquitous language. In this case you may add the delete command. It is however recommended to make the intention clearer; you can name the command as deleteUserBecauseOfInvalidRegistration or so. In this case the delete command is part of the domain model; this means that you can easily restrict the deletion of the user depending on the other properties; for example, a user cannot be deleted anymore if it has approved by the HR manager or so. Then the UI can easily reflect this behavior by hiding the delete button if the operation is not permitted.
An alternative, when the business specialists have heard the word "delete" used by the IT guys so its not from the real domain, you may expose this functionality only in the Admin UI, as a low level command that deletes the rows from the database. The Admin UI could then be accessed only by some higher level persons, like the HR manager.

Immovable customer appointment time windows for vehicle routing

I read the following question and the proposed solution:
Immovable planning entities for chained entities
In our problem we would like to send a set of technicians and customer with their appointment windows to optaplanner with the following condition:
Some customers were already served or are being served, so all of them are already belonging to a certain technician who did (is doing) the work there.
It is similar to the following example:
I start the time dependent vehicle routing example and stop it far before the "best" solution is obtained.
Then I want to use this solution as input, whereby from each technician in the simplest case only the very first customer of the chain has to be set immovable (because he was already served), but all the others are still available for the rest optimization.
In the 6.2 reference manual, take a look at:
immovable planning entities: don't change the entities which are already assigned (= by locking them)
non-volatile replanning: prefer not to change the entities which are already assigned, unless the gain is worth it

RESTfully creating object graphs

I'm trying to wrap my head around how to design a RESTful API for creating object graphs. For example, think of an eCommerce API, where resources have the following relationships:
Order (the main object)
Has-many Addresses
Has-many Order Line items (what does the order consist of)
Has-many Payments
Has-many Contact Info
The Order resource usually makes sense along with it's associations. In isolation, it's just a dumb container with no business significance. However, each of the associated objects has a life of it's own and may need to be manipulated independently, eg. editing the shipping address of an order, changing the contact info against an order, removing a line-item from an order after it has been placed, etc.
There are two options for designing the API:
The Order API endpoint intelligently creates itself AND its associated resources by processing "nested resource" in the content sent to POST /orders
The Order resource only creates itself and the client has to make follow-up POST requests to newly created endpoints, like POST /orders/123/addresses, PUT /orders/123/line-items/987, etc.
While the second option is simpler to implement at the server-side, it makes the client do extra work for 80% of the use-cases.
The first option has the following open questions:
How does one communicate the URL for the newly created resource? The Location header can communicate only one URL, however the server would've potentially created multiple resources.
How does one deal with errors? What if one of the associons has an error? Do we reject the entire object graph? How is that error communicated to the client?
What's the RESTful + pragmatic way of dealing with this?
How I handle this is the first way. You should not assume that a client will make all the requests it needs to. Create all the entities on the one request.
Depending on your use case you may also want to enforce an 'all-or-nothing' approach in creating the entities; ie, if something falls, everything rolls back. You can do this by using a transaction on your database (which you also can't do if everything is done through separate requests). Determining if this is the behavior you want is very specific to your situation. For instance, if you are creating an order statement you may which to employ this (you dont want to create an order that's missing items), however if you are uploading photos it may be fine.
For returning the links to the client, I always return a JSON object. You could easily populate this object with links to each of the resources created. This way the client can determine how to behave after a successful post.
Both options can be implemented RESTful. You ask:
How does one communicate the URL for the newly created resource? The Location header can communicate only one URL, however the server would've potentially created multiple resources.
This would be done the same way you communicate linkss to other Resources in the GET case. Use link elements or what ever your method is to embed the URL of a Resource into a Representation.

Data Mapper API - unsure about organisation

Let's say we have "User" and a "Hotel" model classes. I'd use a User_Mapper and Hotel_Mapper to load/save/delete etc. I want to then have the user be able to mark their "favourite" hotels. In the database I have my user_favourite_hotels table which is a simple link table along with say a field for subscribing to hotel updates.
When listing out the user's favourite hotels, how would you expect this to work from an API point of view? A part of me thinks that this should be a "findFavouritesByUserId" method on the Hotel_Mapper, but other than saying it "feels" right - however a colleague suggests that the "favourites" is owned by the user and should therefore be on the User_Mapper.
Perhaps I should have a User_Hotel_Favourites_Mapper? I was thinking of incorporating the "favourites" data in to the User object so it's saved and loaded whenever the User object is. I'm not sure whether it'd be better to split it out in to it's own object and mapper however.
I'd appreciate any advice on how best to setup the API for the above and any pros/cons/experiences.
Thanks very much,
James.
This (admittedly retired) patterns&practices guide to designing data tier components suggests that you put the method in the mapper of the type of object that you're getting back from the call.
If you have methods that return a particular type of business entity, place these methods in the Data Access Logic Component for that type. For example, if you are retrieving all orders for a customer, implement that function in the Order Data Access Logic Component because your return value is of the type Order. Conversely, if you are retrieving all customers that have ordered a specific product, implement that function in the Customer Data Access Logic Component.
So, in your example, it would go in the Hotel Mapper as it is returning Hotels.
If you want to store favorite hotels for the user, you are using the UserMapper, which notices that domain object for User has changes favorites, and updates both tables for users and for user_favorite_hotels ( you just need the hotel IDs ).
When you are retrieving favorite hotels of some user, you use HotelMapper and set filter to be based on User, because you will be working with instances of Hotel.
Considering that this was asked more than 2 years ago, I'm not sure if an answer matters to you now. But here's what I think anyway.
If User could have multiple types of favourites (including Hotels), it may make sense to have a UserFavourites abstraction to cover all possible types of favourites. UserFavourites could expose a getItems() method to get the underlying Favourites.
This could be managed with the help of a manager class to return the appropriate Favourites object(FavouriteHotels for example) on which the getItems() method can be called.