Magento Multiple Authorize.net Gateways - magento

I've seen this question asked with regard to currency type, but what I am asking is how to configure a second Authorize.net account on the same store for a different credit card type. So, we want some credit cards to use the first main Authorize.net gateway, but the others to use the secondary Authorize.net account so that the payments can be routed into two different bank accounts. This is for purposes of reconciliation and is a constraint; can't be modified.
I'm figuring that all I need to do is figure out once the order has been submitted (but before it has been sent via API to Authorize.net) which card type it is, to know which credentials to pass to the API, but I'm unsure as to where to add this code, or the best way in which to add it.
Any insight or advice would be greatly appreciated.

By default, there is no way to accomplish this, so you'll need to use some custom code. Specifically, override the Authnet payment class Mage_Paygate_Model_Authorizenet:
class MyNamespace_MyModule_Model_Authorizenet extends Mage_Paygate_Model_Authorizenet {
/**
* Prepare request to gateway
*
* #link http://www.authorize.net/support/AIM_guide.pdf
* #param Mage_Sales_Model_Document $order
* #return unknown
*/
protected function _buildRequest(Varien_Object $payment)
//see below
}
}
In that function, on line 277 for me, the following code is executed to set the Authnet account:
$request->setXLogin($this->getConfigData('login'))
->setXTranKey($this->getConfigData('trans_key'))
->setXType($payment->getAnetTransType())
->setXMethod($payment->getAnetTransMethod());
Instead, you want something along these lines:
if(whatever cc type) {
// set alternate gateway
} else {
// set default gateway
}
To accomplish this, you'll also want to create new options in the backend to hold the credentials in an encrypted form. Hope that helps!
Thanks,
Joe

Related

Laravel 9, send notification with preferredLocale

I am creating a bilingual application in which I have implemented database and e-mail notifications.
A notification is, for example, information that a user has started a new conversation. Unfortunately, notifications sent to the database are sent in the language of the user who sends them (set language: App::setLocale(Auth()->user->locale);) and not in the language of the recipient.
I use:
use Illuminate\Contracts\Translation\HasLocalePreference;
class User extends Model implements HasLocalePreference
{
/**
* Get the user's preferred locale.
*
* #return string
*/
public function preferredLocale()
{
return $this->locale;
}
}
Oddly enough, email notifications work this way.
I translate notifications like this:
$customer->notify(new NewMessageNotification($message, trans('notifications.new_message', ['user' => $user->name])));
I tried this way, but it didn't change anything:
https://setkyar.medium.com/fixing-laravels-notification-locale-issue-9ad74c2652ca
Although now I'm wondering if it wouldn't be better to save in the key base and translate only when reading, so that all received notifications are translated when changing the language. The only question is how to do it then.
If i understand well, you want to send notification based on destination language and not based on sender one. If yes, preferredLocale may not works, but you can try to define the language on notification trigger like this:
$customer->notify(new NewMessageNotification($message, trans('notifications.new_message', ['user' => $user->name]))->locale('pt'));
I found that I save to the database in both languages ​​and when reading, I check the language set by the user to display the appropriate version.
On second thought, it seems more logical to have notifications displayed in the currently set language rather than when sent.

Laravel - Rate limiter not bound to user

I've encountered a pretty weird problem if I say so, a user of an API is reporting that the rate limit of the API is exceeded, when checking this, it seems that the rate-limit is not bound to a specific user, but rather to all users at once.
So when user 1 does an request, the rate-limit for other users will get lowered too.
I've tested this using Postman whilst using two separate Bearer tokens (generated for two unique users)
Does anyone have an idea?
Laravel’s built in throttle middleware bases the limitation on the user’s ip address.
see https://github.com/illuminate/routing/blob/master/Middleware/ThrottleRequests.php
protected function resolveRequestSignature($request)
{
if ($user = $request->user()) {
return sha1($user->getAuthIdentifier());
}
if ($route = $request->route()) {
return sha1($route->getDomain().'|'.$request->ip());
}
throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
}
This would explain why you are seeing the limitations you are in your local test. Depending on your end user's use case, it likely explains their issues as well. Are one or more person testing it with different usernames but from the same physical location?
If you think about what the goals of a throttle like this are, this makes good sense. The use case of the throttle starting over when the same end user start using a new username to try to log in only really makes sense in a testing scenario, and is problematic in production environments.
If you do want to alter this behavior, you could make a new custom middleware in the folder app/Http/Middleware which extends the base Illuminate\Routing\Middleware\ThrottleRequests.
Within your custom middleware, you could then override the method resolveRequestSignature() and change it from ip to something else.
You don’t have an authenticated user to work with, so your choices are limited.
If you have users passing in an api key header, that is a reasonable option. Depending on how you have that set up, it would look something like this:
<?php
namespace App\Http\Middleware;
use Illuminate\Routing\Middleware\ThrottleRequests;
/**
* Class ApiKeyBasedThrottleRequests
*
*
*
* #package App\Http\Middleware
*/
class SessionBasedThrottleRequests extends ThrottleRequests
{
/**
* Override the default, which returns as signature
* sha1($route->getDomain().'|'.$request->ip());
*
* Resolve request signature.
*
* #param \Illuminate\Http\Request $request
* #return string
*
* #throws \RuntimeException
*/
protected function resolveRequestSignature($request)
{
if ($user = $request->user()) {
return sha1($user->getAuthIdentifier());
}
if ($route = $request->route()) {
return sha1($route->getDomain().'|'. $request->header('api-key'));
}
throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
}
}
You would then need to update the reference to the middleware in the file app/Http/Kernel in the array $routeMiddleware. Change the value assigned to the key throttle to point to your new custom middleware, App\Http\Middleware;\ApiKeyBasedThrottleRequests::class instead if \Illuminate\Routing\Middleware\ThrottleRequests::class
If you don't have an api key to work with you could think also about session id, but if a single user is trying different usernames from the same browser session, you will still be having the same problem. In that scenario, you could advise the user to restart their browser and try again. However, this basically creates a workaround to the intent of the throttle.
Think carefully and tread lightly with how you approach this. While it makes sense to make things flexible so you don’t block users, keep in mind one of the intents of the throttle is to stop potential malicious users from brute force attacks to discover working username/password combinations. Anything you do here could give them a potential workaround.

Laravel Cashier to synchronise payments to the first of the next month

I have been trying to integrate a payment system for a subscription service using Laravel Cashier.
I have set up my RegistrationController so that it works out how many days until the first day of the next month.
Using $user->trial_ends_at = Carbon::now()->addDays($datediff);
When creating a user it sets the trial end date for the first of the next month.
From here I want to use the $user->onTrial() method to create the actual subscription.
Please note: Even though the user is created there is no customer created in Stripe as the subscription has not yet been created.
My questions:
In the registration form the card details are taken so the users can subscribe and set up their payment method. This involves stripe validating the card and sending back a token.
Can this token be stored and used later?
Assuming I can use this token later on, to create the actual subscription in cashier I have to check whether the users trial has ended using the onTrial method.
The subscription is created using this:
$user->subscription($subscription_plan)->create($stripeToken);
Where is best to add the above code so that the user is subscribed and the billing period is started at the end of the trial?
This isn't mentioned at all in the in the documentation so I was just wondering if I create a new controller to actually start the subscription where to call the function and how to get it to run as each users trial ends.
Edit:
Would something like this be possible using Queues?
http://laravel.com/docs/4.2/queues
$start_subscription = Carbon::now()->addDays($datediff);
Queue::later($start_subscription, 'RegistrationController#subscribe',
array('stripeToken' => $stripeToken, 'details' => $otherDetails));
and then run the subscription method for each user at the set time.
I noticed some issues with creating the Stripe customer at the same time as the subscription. I was ending up with lots of extra customers inside Stripe because if the customer is created, but the subscription has an error, it doesn't connect them in Cashier, but the customer is connected in Stripe.
So to separate the two, I created a helper method in the User model. It will let me create the customer without creating a subscription. I can then create a subscription at a later time.
I think this addresses your issue.
Helper methods in user model:
/**
* Method to create stripe customer without subscription
*/
public function createStripeCustomer($token, $properties) {
$gateway = $this->subscription();
$customer = $gateway->createStripeCustomer($token, $properties);
$gateway->updateLocalStripeData($customer);
}
public function getStripeCustomer() {
$gateway = $this->subscription();
return $gateway->getStripeCustomer();
}
Then in my API controller where I handle the subscription:
if (!$user->getStripeId()) {
$user->createStripeCustomer($inputs['token'], ['email' => $user->email]);
//this can be done at a much later time, the customer is already stored.
$user->subscription($inputs['plan'])->create(null, [], $user->getStripeCustomer());
Flash::success("Subscription Success!");
} elseif (!$user->getStripeSubscription()) {
$user->subscription($inputs['plan'])->create($inputs['token'], [], $user->getStripeCustomer());
Flash::success("Subscription Success!");
}
As for the Stripe token, you'll want to use that within a few moments of its creation. It's not expected to last for longer than that.
As for your other questions, I'm not a Laravel person, so I couldn't speak to that, but PHP's strtotime() function takes a variety of strings and returns a timestamp. So if you always wanted to have billing start at noon of the first of the next month, you'd set your timestamp to:
strtotime('first day of next month 12:00');
Hope that helps,
Larry
PS I work on Support at Stripe.

Extending ion auth to only allow registrations from certain email addresses/domains

I want to extend Ion Auth to only allow certain email addresses to register.
I'm fairly sure I could hack this together and get something working, but as a newbie to codeigniter and ion auth I wish to find out if there is a "proper way" to be doing what I need?
For instance can I "extend" ion auth (so I can update ion auth core files without writing over my changes?).
I noticed there are also hooks including this one (in the register function):
$this->ci->ion_auth_model->trigger_events('pre_account_creation');
Where do these resolve and can I use this one in order to intercept registrations from email addresses which don't match a list of those I wish to register?
If so, how would I do it? I would need access to the $email variable from the register() function.
Or is it just a case of altering the base code from ion auth and not updating it in the future?
Thanks for any help you can give me. Don't worry about the email bit, I'm capable of working out whether an email address matches the required email domains, I'm more interested in what is the best way to go about extending the library.
Tom
EDIT: Hi Ben, thanks for your answer, and thanks for taking the time to have a look at my issue. Unfortunately this hasn't helped.
I guess what you're trying to do there is add a little bit to the sql query a "where in" clause? I guess that the where in bit is incorrect as there isn't a column name.
Also, at this point I can't modify the sql query satisfactorily to produce the required output. e.g. I can add a hook to a function which is literally $this->db->where('1=1') and this outputs this sql in the next query:
SELECT COUNT(*) AS `numrows` FROM (`users`) WHERE `1=1` AND `email` = 'rawr#rawr.com'
The AND email = 'rawr#rawr.com' bit will always still return no rows. It should be OR email = 'rawr#rawr.com', but without editing the Ion Auth core code then I won't be able to change this.
I am starting to suspect (from the last couple of hours of tinkering) that I may have to edit the ion auth core in order to achieve this.
Check out this example: https://gist.github.com/2881995
In the end I just wrote a little form_verification callback function which I put in the auth controller of ion_auth which checked through a list of allowed domains. :)
When you validate your form in the auth controller you add a callback:
$this->form_validation->set_rules('email', 'Email Address', required|callback_validate_email');
You create a method in the controller called validate_email:
function validate_email() {
if (strpos($this->input->post('email'), '#mycompany.com') === false) {
$this->form_validation->set_message('validate_email', 'Not official company email address.');
return false;
} else return true;
}
This will cause the creation of the user to fail, since all rules must pass. You also provide an error message. Just make sure to have this line on the form view side:
echo validation_errors();

Get customer object on an event

I’m trying to createan observer on the following event.:
‘sales_order_payment_pay’.
However according to magento doc
http://www.magentocommerce.com/wiki/5_-_modules_and_development/reference/magento_events
I don’t have so much parameters avalaible on this event..
Do you have any idea how I could retrieve the customer object (i would need info such as customer id and customer email)?
Thanks for your feedback and anyway I wish you a nice day,
Anselme
This event does expose the payment object, so you should be able to chain off of that to get the object you want:
public function yourObserverFunction($event) {
$payment = $event['payment'];
$customer = $payment->getOrder()->getCustomer();
// ... do something useful
}
Generally objects in Magento can be chained like this, and now your code doesn't rely on the event being triggered from a customer session (which is not a good assumption anyway).
Hope that helps!
Thanks,
Joe
Every event exposes different objects inside of the $observer object that is passed around. In Magento you can often get a lot of stuff by referring to any number of objects that are in the request or session. In this case there is a customer/session object (Mage_Customer_Model_Session) which has the customer attached.
if(Mage::getSingleton('customer/session')->isLoggedIn()){
Mage::getSingleton('customer/session')->getCustomer();
}

Resources