I have a doubt about how quotes and orders are being called in payment method. What I know is that a Quote is a set of products or services offered. In magento Quote data is created just before clicking Place Order button of Onepage Checkout. After the Order is placed Order data is created in Magento. Invoice comes next to Order if Order is confirmed.
But I was wondering why the Class Mage_Payment_Model_Method_Abstract in validate Method checks Info class Instance if it is an instance of Mage_Sales_Model_Order_Payment take getOrder() else take getQuote()
I am not clear with this. Does the Validate() function is called two time i.e first time when Quote is created and second time when Order is Created OR does the Payment Method Class itself is called two times.
Please clarify my confusion.
/**
* Validate payment method information object
*
* #param Varien_Object $info
* #return Mage_Payment_Model_Abstract
*/
public function validate()
{
/**
* to validate paymene method is allowed for billing country or not
*/
$paymentInfo = $this->getInfoInstance();
if ($paymentInfo instanceof Mage_Sales_Model_Order_Payment) {
$billingCountry = $paymentInfo->getOrder()->getBillingAddress()->getCountryId();
} else {
$billingCountry = $paymentInfo->getQuote()->getBillingAddress()->getCountryId();
}
if (!$this->canUseForCountry($billingCountry)) {
Mage::throwException($this->_getHelper()->__('Selected payment type is not allowed for billing country.'));
}
return $this;
}
A quote in Magento is basically an order that hasn't been placed yet. It contains product items (shopping cart), addresses and payment/shipping methods. It is created as soon as you add an item to cart. During checkout, billing and shipping data is added to the quote. Finally, when the user clicks place order, the quote is converted to an order.
To answer your question about the payment validation: The payment method is included in the quote as well as the order and validated in both places. A payment method may be restricted to certain countries, so in the validate method, a payment method for a quote will validate the quote country, and a payment method for an order will validate the order country.
Related
I am building a custom module in prestashop and I need to execute something after payment accepted and after the emails have been sent. In mymodule.php I have the following hooks:
public function hookActionValidateOrder($params) {
$order = $params['order'];
$customer = $params['customer'];
$valuesToinsert="";
$attrValue=array();
etc...
}
Which is executed normally. I tried actionOrderStatusPostUpdate, actionPaymentConfirmation but none of these seems to be called. I dont know whether it is relevant but I am using opc module and the product is free of charge.
This hook is call when an order is placed after a client confirm his cart. The function that triggers this hook is validateOrder from PaymentModule class. It is call by payment modules when client click en confirm button in checkout. Every payment module should call this function in some moment. But, if you don't have a payment module in your specific process due to free product this hook could maybe be never called.
Anyway, you can subscribe to actionObjectOrderAddAfter hook or similar to get notified when a new order is placed:
public function hookActionObjectOrderAddAfter($params)
{
//$params['object'] contains specific object, in this case your Order object
}
If you need information about order status you could subscribe to hook actionOrderHistoryAddAfter too. Hook actionOrderStatusUpdate is only trigger inside changeIdOrderState function. If for some reason order status change with no call to this function you will miss notification.
Good luck
As you have mentioned in your question that the order you are trying is free, in this case any hook that is called on payment, will never call.
Hence the hooks (i.e. actionOrderStatusPostUpdate, actionPaymentConfirmation, hookActionObjectOrderAddAfter etc.) will never be called as they are called from the PaymentModule.php class and it is not called at all in case of a free order.
Unfortunately, there are no hooks that are called when a free order is placed. In case you want to take any action on a Free order then you can only do that by overriding the FreeOrder class or _checkFreeOrder() function in ParentOrderController.php
Old post, but wanted to drop a comment to help others. This function calls after an order is submitted and they get the confirmation page, whether a payment was submitted with it or not:
public function hookDisplayOrderConfirmation($params) { }
Laravel Cashier makes it pretty simple to swap plans:
$user->subscription('premium')
->swapAndInvoice();
This feature is also great because it invoices the user right away, HOWEVER, it also forces the user to pay right away rather than waiting an hour like it normally would. This seems to get in the way of my invoice.created webhook because once swapAndInvoice happens, I don't seem to be able to make further changes to the invoice.
If I just use ->swap(), it doesn't appear to create an invoice at all, but rather it just creates line items waiting to be added to the next invoice. Thoughts are appreciated.
Since posting this question, I have actually submitted a pull request to the Laravel Cashier repository to add a method within the StripeGateway.php file that can perform such functionality.
/**
* Invoice the billable entity outside of regular billing cycle without charging the user immediately.
*
* #return bool
*/
public function invoiceWithoutImmediateCharge()
{
try
{
$customer = $this->getStripeCustomer();
// Removed this because it immediately charges the user which doesn't allow the invoice to be modified by webhooks
//Stripe_Invoice::create(['customer' => $customer->id], $this->getStripeKey())->pay();
Stripe_Invoice::create(['customer' => $customer->id], $this->getStripeKey());
return true;
}
catch (\Stripe_InvalidRequestError $e)
{
return false;
}
}
According to the Stripe documentation, it appears as though you can actually apply coupons to a customer as a whole, but you can also apply coupons to their subscriptions. I am trying to apply a coupon to the customer's subscription after the subscription has already been created. I am using Laravel Cashier 4.2.
Here is what I have tried:
$company = Auth::user()->company;
$customer = $company->subscription()->getStripeCustomer(); // returns a StripeGateway object
$customer->subscription->applyCoupon($input['coupon_code']);
Here is the error message:
"Call to undefined method Stripe_Subscription::updateSubscription()"
I can use the applyCoupon() method to a customer as a whole, but not an actual subscription... Ideas appreciated.
The Stripe documentation only shows how to remove a discount from a subscription:
Discount Object. The only other information I've been able to find in their documentation is:
Coupons and discounts
If you want to provide discounts to certain customers, you can create coupon codes in the Dashboard. Coupons have a discount percentage and a duration, so you could create coupons like a 10% lifetime discount, or a one month 50% discount, etc. Coupons can also have expiration dates attached, after which they can't be used. Here's an example of adding a discount to a user's subscription. In this case, we've already created a coupon called 50OFF1MONTH:
curl https://api.stripe.com/v1/customers/cus_4fdAW5ftNQow1a \
-u sk_test_4LOIhlh19aUz8yFBLwMIxnBY: \
-d coupon=50OFF1MONTH
However, this isn't very helpful. Once again, Laravel's documentation is a little to elegant, and it's missing any info on the topic.
I wonder if I just need to recreate the subscription object entirely with the new coupon... But that's not ideal because you need a card token for that.
Update 1
I can confirm that this does in fact apply a coupon to the subscription itself
$user->subscription('monthly')
->withCoupon('code')
->create($creditCardToken);
However, once again the question is how can a coupon be added after the fact.
Starting with Cashier v11.* there are new convenience methods to update the underlying Stripe subscription object. To apply a coupon to the user's Subscription model instead of the Customer model, try this in the controller:
$user->subscription('default')->updateStripeSubscription(['coupon' => $couponCode]);
To remove the coupon from the subscription, send an update request and pass an empty coupon string. As described under another question, a coupon set to an empty string removes it, while passing null is ignored.
$user->subscription('default')->updateStripeSubscription(['coupon' => '']);
It doesn't look like what I'm trying to do is possible, so I found another way. All I do is swap the users existing plan to the current plan and use the withCoupon method. This does appear to apply the coupon to the subscription and doesn't seem to charge the user or change their billing period, but I could be wrong...
$company->subscription($company->stripe_plan)
->withCoupon($input['coupon_code'])
->swap();
Adding a Coupon to an Existing Subscription.
You can also use cashier method as below:
try {
$user->applyCoupon('coupon_code');
return redirect()->back()->withMessage('Coupon Applied');
} catch (Exception $e) {
return back()->withError($e->getMessage());
}
When applying a coupon, it's best to wrap this in a try / catch block because if the user enters an invalid coupon, Stripe will return an exception with the reason for the failure.
For everyone who can't find an easy and convenient way to swap the subscriptions with a coupon, here's what I came up with recently.
First of all, we'll have to create a custom Subscription eloquent model and extend Laravel\Cashier\Subscription class.
Now we're going to create the withCoupon() method there:
public function withCoupon($coupon)
{
$this->coupon = $coupon;
return $this;
}
The next thing will be extending the original swap() method and adding the coupon part. Just copy and paste the original method and add this piece of code somewhere before the $subscription->save(); line.
...
// Applying the discount coupon if such exists
if ($this->coupon) {
$subscription->coupon = $this->coupon;
}
...
$subscription->save();
The last thing you've got to do in order to make things work properly is to create a custom Billable trait and change subscriptions() method to use your custom Subscription model.
After that, you can apply your very own Billable trait to the billable model and apply coupons while swapping plans.
$user
->subscription($product)
->withCoupon($coupon)
->swap($plan);
Using Laravel 7.x with Cashier 10 you have the applyCoupon() method on a Billable (User) model.
Something like this in the controller:
/**
* Apply Stripe coupon
*/
public function applyCoupon(Request $request){
$user = $request->user();
if ($user->subscribedToPlan('plan_name', 'default')) {
try {
$user->applyCoupon($request->couponCode);
return redirect('subscription')->withMessage('Coupon Applied');
} catch (\Exception $e) {
return redirect('subscription')->withError($e->getMessage());
}
}
}
I sell two services in my Magento store. I've disabled cart and multi-page checkout. I want to sell only one service at a time. Means I want to accomplish, if customer tries to add both services to cart so the previous service should be removed.
How can I accomplish this? I've been searching this from last 5 hours.
in the file
app/code/core/Mage/Sales/Model/Quote.php
there is a method public function addProduct($product, $request = null);
you should only add $this->removeAllItems(); to be the first line in the method, like:
public function addProduct(Mage_Catalog_Model_Product $product, $request = null)
{
$this->removeAllItems(); // new code
....
}
of course, it's better idea to be overridden in the local pool.
Does anyone know how to implement a custom "module" that is triggered when an order is paid or complete?
And how am I able to call the order data from that observer?
I am also working with the "Serial Codes" plugin, and I want to send
an email to the person who bought this product, containing the serial
code.
Is there anybody who is able to help me out?
You can write an observer for the sales_order_save_before event. In the observer method you are able to get the order by $observer->getEvent()->getOrder(). Then you can check for the order status/state and add your code when the order is completed. This is the safest way, with the small downside, that the Observer function will always be triggered when the order is saved. Example Code:
public function onCompleteOrder(Varien_Event_Observer $observer)
{
/** #var $order Mage_Sales_Model_Order */
$order = $observer->getEvent()->getOrder();
if ($order->getState() == Mage_Sales_Model_Order::STATE_COMPLETE) {
// do something
}
return $this;
}
By the way: A Magento order is usually becoming completed when
An invoice has been created AND
a shipment has been created