I am creating a payment module for our payment gateway...
So far I have 1) set up the back-end and 2) used the hookPayment() method to display a hidden form at part 5 of the checkout process (http://prestashop.dev/order). This will then redirect off to my gateway with all the required information. Good job.
The next part is the part I am struggling with. I don't understand what the return URIs are for payment-confirmation - just to give the customer some information on the status of the order (and maybe also update the back-office?).
For now, I have just a very simple method;
public function hookPaymentReturn()
{
// if (!$this->active) {
// return null;
// }
return $this->display(__FILE__, 'views/templates/front/confirmation.tpl');
}
in my main module file. I just want to get to this on the browser... I'll start worrying about POST'ed values after this. But for now I just don't know the URI. What will it be?? Do I need to register the route somehow?
Most payment modules confirmation.tpl get hooked into the order-confirmation.tpl of your theme which in turn gets called by the OrderConfirmationController.php.
This can be accessed by:
[YOUR_BASE_URL]/index.php?controller=order-confirmation&[some_stuff].
The [some_stuff] part is important though since the controller performs a series of validations and will redirect you somewhere else if these are not met
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) { }
i was trying to setup a general service which handles common function i use very often everywhere in my project. For example if a user wants to purchase something for virtual currency there would be a function which checks, if the user has enough virtual currency in his account.
If the user doesnt have enough virtual currency I want this function to make a JSOn Response, but of cource, only controllers are allowed to response. But this means i have to check in every action I use this function, whether the purchase is valid or not.
Here is the function call in my Controller:
$purchaes= $this->get('global_functions')->payVirtualCurrency($user_id, $currency_amount);
if($change instanceof JsonResponse){
return $change;
}
And the function:
public function payVirtualCurrency($user_id, $currency_amount){
$user = $this->dm->getRepository('LoginBundle:User')->findOneById($user_id);
if($user->getVirtualCurrency() < $currency_amount){
return new JsonResponse(array('error' => $this->trans->trans('Insufficient amount of virtual Currency')));
}
return true;
}
Is there a better way to do this? I really want to avoid doing the same thing in the controller over and over again.
Thanks in advance!
Two options come to my mind, both are quite elegant solutions but both require little work:
1. Create custom exception listener
Create custom exception, let's call it InsufficientMoneyException. Then, your sevice can be as it is, but instead of returning response it throws your custom exception (in case user does not have enough money). Then, you create custom exception listener which listenes to InsufficientMoneyException custom exception and returns your desired JsonResponse.
2. Create custom annotation
You can create custom annotation and flag a controller action with this annotation. It would look something like this
/**
* #MinimumMoneyRequired("50")
*/
public function buyAction()
{
(...)
}
This option is really nice and decoupled but it require quite a lot of configuration. This is nice blog post with detailed description how to create custom annotations
I am currently building a web app which has two models, Donor and Donation Models respectively. It has multiple user roles. When the staff user first registers a donor, I want him to be redirected to another form which allows him to fill in the Donation details(the donor is registered once the first donation is successful).
Firs of all, should I create a donation controller, from which I would redirect the user using:
return $this->redirect(array('controller'=>'donations','action'=>'add'));
For the above to work, it requires me to save the newly registered donor's id in a session like so :
$this->Session->write('id', $this->Donor->id);
So the user is redirected to 'donations/add' in the url, and this works fine.. However I think this has some flaws. I was wandering whether I should create another action inside the Donor controller called 'add_donation', which will have its respective 'View'. The idea is to be able to form a url of the sort : 'donors/add_donation/4' (4 being the donor_id ! )
This URL follows this construct: 'controller/action/id'
If anyone could shed some light on best practices, or describe any caveats to my solution(the former, using session etc.) , please do help a brother out! Ill be deeply indebted to you! Thanks in advance!
After you saved the data you can do this in the DonorsController:
$this->redirect(array(
'controller' => 'donations',
'action' => 'add',
$this->Donor->getLastInsertId()
));
There is no need to return a redirect, it's useless because you get redirected. Notice that we pass the last inserted record id as get param in the redirect. The redirect method of the controller calls by default _stop() which calls exit().
CakePHP3: There is a discussion about changing that default behavior in 3.0. Looks like in CakePHP 3.0 the redirect() won't exit() by default any more.
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
I would not use the session here, specially not by saving it to a totally meaningless and generic value named "id". If at all I would use always meaningful names and namespaces, for example Donor.lastInsertId as session key.
It's not always clear where to put things if they're related but the rule of thumb goes that things should go into the domain they belong to, which is pretty clear in this case IMHO.
Edit:
Leaving this edit here just if someone else needs it - it does not comply with the usage scenario of the asker.
If you have the user logged in at this stage, modify the add function to check if the userId passed is the same as the one logged in:
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
if ($this->Auth->user('id') != $donorId) {
throw new InvalidArgumentException();
}
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
You can use also the same controller using more models with uses.
Or you can also to ask to another controller with Ajax and morover to get response with Json.
I am building a prestashop site
The corporate buyers cannot register for an account to view the products unless they can enter a valid EIN number or a valid Duns & Brandstreet number in registration.
How to make it possible?
Also any other e-commerce software that can help me solve this by switching to it?
All you really need to do is add the field to the template and then override the AuthController with additional code to handle you new field. e.g.
<?php
class AuthController extends AuthControllerCore
{
public function preProcess()
{
// Additional pre-processing for the new form field
if (Tools::isSubmit('submitAccount'))
{
if (!MyDBNumberValidationClass::verifyvalidnumber(Tools::getValue('db_number_field', 0)))
$this->errors[] = Tools::displayError('The Dun and Bradstreet number you entered is invalid.');
}
parent::preProcess();
}
}
I'm assuming that you're doing complex verification of the number which is why the static call to MyDBNumberValidationClass::verifyvalidnumber() is in the above, but it could equally by any simple test or an additional function in your AuthController override class definition above that validates. If you add two fields (i.e. the EIN number too) then just alter the logic to handle generating an error only if both are invalid; success of the form validation is based on $this->errors being empty.
This is only part of a general solution since it only handles validating the extra fields. If you need to actually do something with the data entered then the best way is to write a little handler module that installs itself on hookCreateAccount e.g.
public function hookCreateAccount($params)
{
// Get the field data entered on the form
$DB_number = $params['_POST']['db_number_field'];
// Your custom processing...
}
Note that there's no way to back out of the account creation from here so you will want to add code to email the store owner should there be a problem.
Why do controller action predispatch events not fire if the controller is rewritten? Here is a snippet of store/app/code/core/Mage/Core/Controller/Varien/Action.php:
abstract class Mage_Core_Controller_Varien_Action
{
// [...]
public function preDispatch()
{
// [...]
if ($this->_rewrite()) {
return; // [What is the purpose if this?]
}
// [...]
// [This is where my event needs to be firing, but this code never gets
// executed because the controller is rewritten]
Mage::dispatchEvent(
'controller_action_predispatch_'.$this->getFullActionName(),
array('controller_action'=>$this)
);
}
// [...]
}
I don't know where to start fixing this problem. Anyone out there ever dealt with this before?
No time to test if the the behavior you're describing is accurate, but if it is I imagine it's what happens in the _rewrite function duplicates the actions of other non-event code after that call, and allowing preDispatch to continue after the rewrite would have made "bad things" happen.
In other words, it's a bug in the implementation of controller re-writing that's been ignored, because the preferred way of handling this is now at the routing level. In general, when a system level bug like this makes it into Magento, it tends to stay there, because cart owners start to rely on the broken behavior and scream loudly when anything changes, even if it's a bug fix.
If you can't re-factor your solution as described in the link above, you can still fire the event yourself in the controller class with old fashion Object Oriented Programming. Add the following to your custom controller (the one you're rewriting to)
protected function _rewrite()
{
//call the parent rewrite method so every that needs
//to happen happens
$original_result = parent::_rewrite();
//fire the event ourselve, since magento isn't firing it
Mage::dispatchEvent(
'controller_action_predispatch_'.$this->getFullActionName(),
array('controller_action'=>$this)
);
//return the original result in case another method is relying on it
return $original_result;
}
Hey, I'm not sure (as I'm not very familiar with the inner workings of Magento), but it occurs to me that _rewrite() checks whether a call to this specific action is being redirected (rewritten in a mod_rewrite kind of way) to a different controller/action. In this light, it would make sense that events for the original action would not be fired, since the whole request gets handled by a different action.