store payment gateway response on quote and persist to order - magento

I am writing a magento module for a gateway that authorizes loans as a payment system.
Since there is a relatively high probability the customer will get declined, I chose to implement this using getCheckoutRedirectURL() (placing the loan steps before 'place order' in the checkout flow) so that in the failure case, I can easily return the customer to the payment choice page.
I then do the gateway API call in my redirectAction in my controller.
As a result, I get a URL to open in a lightbox to take the customer through the loan process, as well as some id's from the loan gateway.
I would like to store these additional id's as part of the quote and later copy them to the order when I convert the quote to an order (I did the conversion similar to google checkout - based on a callback from the loan gateway).
However, I cannot figure out how to persist data on the quote.
The obvious way:
$quote->setCustId($custId);
$quote->save();
doesn't work; the additional data does not get stored in the database and hence is not available in the postback handler to convert quote to order.
The same happens for
$quote->setData('custId', $custId);
$quote->save();
(and I assume this is just a more explicit form of the first in the sense that it doesn't use the magic setter/getter)
I've seen references to setAdditionalData (for example, here) but that looks to be available only on payment objects, which I don't think I have yet on the quote (although I could be wrong ?)
Is there any way to store some fields on an order in the database without having to actually add database fields for them ?

You will need to add actual columns to sales_flat_quote table to store extra variables in quote object.
Since the stuff you are making is related to payment method instead I'd suggest you to store those variables in additional_information dataset that is stored to sales_flat_quote_payment table as serialised php array and payment methods can set data to this variable as follows:
$quote->getPayment()->getInfoInstance()->setAdditionalInformation($key, $value);
$order->getPayment()->getInfoInstance()->setAdditionalInformation($key, $value);
see more from app/code/core/Mage/Payment/Model/Info.php
the only downside for this is that it is stored as serialised array at the end which means no direct sql access later if you somehow need to depend on this data, offer filters and such.

Related

How to make an API endpoint in Laravel, that can be used to search any table we want?

Background
Let us consider a hypothetical scenario. Suppose we have five different tables in our database,
Customers
Categories
Products
Orders
OderDetails
Our client wants us to add a search bar to the frontend, where a user can search for a specific product and upon tapping the search button, matching products has to be displayed on the frontend.
My Approach for Tackling This Problem
In order to add the aforementioned functionality, I came across the following strategy.
πŸ‘‰ I would add an input box to ender the product name and a submit button.
πŸ‘‰ Upon pressing the submit button, a GET request will be sent to the backend. On the query parameters, the product name that has been entered by the user will be included
πŸ‘‰ Once the GET request is received to the backend, I will pass it down to the ProductsController and from within a method defined inside the ProductController, I will use the Product model to query the products table to see if there are any matching results.
πŸ‘‰ If there are any matching results, I will send them to the frontend inside a JSON object and if there aren't any matching results, I will set a success flag to false inside the JSON object and send it to the frontend
πŸ‘‰ In the frontend, if there are any matching results, I will display them on the screen. Else, I will display "No Results Found!"
Problem with My Approach
Everything works fine if we only want to search the products table. But what if, later our client tells us something like "Remember that search functionality you added for the products? I thought that functionality should be added to orders as well. I think as the list of orders by a user grows and grows, they should be able to search for their previous orders too."
πŸ‘‰ Now, since in our previous approach to search products was implemented in the ProductController using the Product model, when we are adding the same functionality to Orders, WE WOULD HAVE TO DO THE SAME THINGS WE DID IN THE ProductsController AGAIN INSIDE THE OrdersController USING THE Order model. It does not take seconds to understand that this leads to duplication of code.
Problem Summary
❓ How do we add an API endpoint in laravel for a search functionality that can be used to search any table in our database and get results, instead of the search functionality being scoped to a specific controller and a corresponding model?
A good start would be to create a trait called something like searchable and add it to all the models you want to search and put any shared logic between the different models in there. Possibly you'd want to manually allow different columns so in each model you have an array of searchable columns which you'd refer to in your trait.
Your controller would have to point to the related model and call a method in the trait that searches.
As others have pointed out this is a high level question so I won't go too much in detail. Of course there are a million ways to implement this, just try and keep shared logic in place.

Event Sourcing - Data supplied to Command and data saved in Events

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

RESTful API - validation of related records

I implementing RESTful API service and i have a question about saving related records.
For example i have users table and related user_emails table. User emails should be unique.
On client side i have a form with user data fields and a number of user_email fields (user can add any number of fields independently). When the user saves the form i must first make query to create record in users table to get her ID, ​​and only then i can make query to save user emails (because in now i have id of record which come with response after saving user data). But if user enters not unique email in any field then the request will fail. So I create a record in the users table but not create record in user_emails table.
What are the approaches to implement validation of all this data before saving?
This is nor related restful api but transactional processing on the backend. If you are using Java, with JPA you can persist both element in the same transaction then you can notice if there is a problem and rollback the entire transaction returning a response.
I would condense it down to a single request, if you could. Just for performance's sake, if nothing else. Use the user_email as your key, and have the request return some sort of status result: if the user_email is unique, it'll respond with a success message. Otherwise, it'd indicate failure.
It's much better to implement that check solely on the server side and not both with the ID value unless you need to. It'll offer better performance to do that, and it'll let you change your implementation later more easily.
As for the actual code you use, since I'm not one hundred percent on what you're actually asking, you could use a MERGE if you're using SQL Server. That'd make it a bit easier to import the user's email and let the database worry about duplicates.

Seed db with a particular record set with associated records

I am building a feature where when a person signs up for an account we will automatically populate their account with default categories and items to get them started.
Further, they can optionally purchase additional category sets to add/populate their accounts at anytime.
I am thinking my choices are:
1) Somehow use seeds.rb
2) Store these records in a YAML file and load in upon account creation
3) Store these records in the DB as a default set and clone/dup them.
Any help appreciated w/ code examples to get me started.
This is what I would do:
Have a flag in the DB to identify first_sign_in Store the data in a yaml file (e.g db/users.yml) and do:
def populate_user
user.update_attributes(YAML.load(Rails.root + 'db/users.yml')) if first_sign_in == 0
end
Then you can add this to an after_create hook so it is called only when a user is created
I'd do it differently. I'd have a "Registration" form object between the controller and model(s). Have this build some default categories and items at the same time as it first builds a user. How you isolate the attributes of those default items depends on how complex they are. If they're simple a default hash in the form object will suffice, if they're complex you can pull in from YML.
When I've done this in the past - had a signup which requires multiple object creation I've had a RegistrationsController, a RegistrationForm object which takes the params and validates everything, and is also responsible for knowing what to save, and sometimes in intermediate Registrar object (Struct usually) which has all the logic for callbacks. The registrations_controller initializes a registrar which is sent a message register(registration_form).
This leads to isolation of responsibilities and much cleaner code in the long run.
The answers provided are definite options, with which I experimented with. However, I decided to go a different route. I realized that I would need to manage these 'template' records and a DB would be easiest.
1) I setup a column on the table 'is_template' to mark the records that will be used to seed other accounts.
2) Created an after_create call back to seed the accounts using these records.
3) To make matters easier I used the amoeba gem which allows me to copy the records and their associated records which works great since some of them have has_many relationships.
This has been working great so far - and I also have a way for myself and the non-tech staff to update the records.

Magento: how do I determine if a customer is new?

I want to be able to send different order confirmation emails to new customers than to established customers.
I am already able to put a block in the email template to insert my own 'if' constructs based on order details.
I can get the customer data from the order id, e.g. the customer id, but how can I determine if they are a new customer?
Even if it is getting the customer creation date and checking if it is less than five minutes, I need a technique to determine if they are new from within my template code based on the order information.
Either way your going to just have to do calculations on created_at field in the customer_entity table. If not your going to have to find some specific window to consider customers as "new".
Don't think I'd put said logic in the template file but rather a model and just pass it a block to flag it or not.

Resources