1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-11 05:32:39 +01:00

Merge pull request #7710 from turbo124/v5-stable

Fixes for payment emails
This commit is contained in:
David Bomba 2022-08-04 16:30:47 +10:00 committed by GitHub
commit ca60e9635c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 319 additions and 16 deletions

View File

@ -12,6 +12,7 @@
namespace App\Factory;
use App\Models\VendorContact;
use Illuminate\Support\Str;
class VendorContactFactory
{
@ -21,6 +22,7 @@ class VendorContactFactory
$vendor_contact->first_name = '';
$vendor_contact->user_id = $user_id;
$vendor_contact->company_id = $company_id;
$vendor_contact->contact_key = Str::random(40);
$vendor_contact->id = 0;
return $vendor_contact;

View File

@ -119,7 +119,6 @@ class InvitationController extends Controller
return redirect()->route('client.login');
} else {
nlog("else - default - login contact");
request()->session()->invalidate();
auth()->guard('contact')->loginUsingId($client_contact->id, true);
}
@ -195,7 +194,7 @@ class InvitationController extends Controller
$file_name = $invitation->{$entity}->numberFormatter().'.pdf';
$file = CreateRawPdf::dispatchNow($invitation, $invitation->company->db);
$file = (new CreateRawPdf($invitation, $invitation->company->db))->handle();
$headers = ['Content-Type' => 'application/pdf'];

View File

@ -613,7 +613,6 @@ class PaymentController extends BaseController
// code...
break;
case 'email':
//dispatch email to queue
$payment->service()->sendEmail();
if (! $bulk) {

View File

@ -73,7 +73,6 @@ class InvitationController extends Controller
auth()->guard('vendor')->loginUsingId($vendor_contact->id, true);
} else {
nlog("else - default - login contact");
request()->session()->invalidate();
auth()->guard('vendor')->loginUsingId($vendor_contact->id, true);
}

View File

@ -0,0 +1,42 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Controllers\VendorPortal;
use App\Http\Controllers\Controller;
use App\Http\ViewComposers\PortalComposer;
use App\Models\RecurringInvoice;
use Auth;
class VendorContactHashLoginController extends Controller
{
/**
* Logs a user into the client portal using their contact_key
* @param string $contact_key The contact key
* @return Auth|Redirect
*/
public function login(string $contact_key)
{
return redirect('/vendors/purchase_orders');
}
public function magicLink(string $magic_link)
{
return redirect($this->setRedirectPath());
}
public function errorPage()
{
return render('generic.error', ['title' => session()->get('title'), 'notification' => session()->get('notification')]);
}
}

View File

@ -42,6 +42,7 @@ use App\Http\Middleware\TrimStrings;
use App\Http\Middleware\TrustProxies;
use App\Http\Middleware\UrlSetDb;
use App\Http\Middleware\UserVerified;
use App\Http\Middleware\VendorContactKeyLogin;
use App\Http\Middleware\VendorLocale;
use App\Http\Middleware\VerifyCsrfToken;
use App\Http\Middleware\VerifyHash;
@ -166,6 +167,7 @@ class Kernel extends HttpKernel
'shop_token_auth' => ShopTokenAuth::class,
'phantom_secret' => PhantomSecret::class,
'contact_key_login' => ContactKeyLogin::class,
'vendor_contact_key_login' => VendorContactKeyLogin::class,
'check_client_existence' => CheckClientExistence::class,
'user_verified' => UserVerified::class,
'document_db' => SetDocumentDb::class,

View File

@ -50,7 +50,6 @@ class SetDomainNameDb
];
if ($company = MultiDB::findAndSetDbByDomain($query)) {
//$request->merge(['company_key' => $company->company_key]);
session()->put('company_key', $company->company_key);
} else {
if ($request->json) {
@ -68,7 +67,6 @@ class SetDomainNameDb
];
if ($company = MultiDB::findAndSetDbByDomain($query)) {
//$request->merge(['company_key' => $company->company_key]);
session()->put('company_key', $company->company_key);
} else {
if ($request->json) {

View File

@ -0,0 +1,155 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Middleware;
use App\Http\ViewComposers\PortalComposer;
use App\Libraries\MultiDB;
use App\Models\Vendor;
use App\Models\VendorContact;
use Auth;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
class VendorContactKeyLogin
{
/**
* Handle an incoming request.
*
* Sets a contact LOGGED IN if an appropriate vendor_hash is provided as a query parameter
* OR
* If the contact_key is provided in the route
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::guard('vendor')->check()) {
Auth::guard('vendor')->logout();
$request->session()->invalidate();
}
if ($request->segment(2) && $request->segment(2) == 'magic_link' && $request->segment(3)) {
$payload = Cache::get($request->segment(3));
if (! $payload) {
abort(403, 'Link expired.');
}
$contact_email = $payload['email'];
if ($vendor_contact = VendorContact::where('email', $contact_email)->where('company_id', $payload['company_id'])->first()) {
if (empty($vendor_contact->email)) {
$vendor_contact->email = Str::random(15).'@example.com';
}
$vendor_contact->save();
auth()->guard('vendor')->loginUsingId($vendor_contact->id, true);
if ($request->query('redirect') && ! empty($request->query('redirect'))) {
return redirect()->to($request->query('redirect'));
}
return redirect($this->setRedirectPath());
}
} elseif ($request->segment(3) && config('ninja.db.multi_db_enabled')) {
if (MultiDB::findAndSetDbByContactKey($request->segment(3))) {
if ($vendor_contact = VendorContact::where('contact_key', $request->segment(3))->first()) {
if (empty($vendor_contact->email)) {
$vendor_contact->email = Str::random(6).'@example.com';
}
$vendor_contact->save();
auth()->guard('vendor')->loginUsingId($vendor_contact->id, true);
if ($request->query('next')) {
return redirect()->to($request->query('next'));
}
return redirect($this->setRedirectPath());
}
}
} elseif ($request->segment(2) && $request->segment(2) == 'key_login' && $request->segment(3)) {
if ($vendor_contact = VendorContact::where('contact_key', $request->segment(3))->first()) {
if (empty($vendor_contact->email)) {
$vendor_contact->email = Str::random(6).'@example.com';
$vendor_contact->save();
}
auth()->guard('vendor')->loginUsingId($vendor_contact->id, true);
if ($request->query('next')) {
return redirect($request->query('next'));
}
return redirect($this->setRedirectPath());
}
} elseif ($request->has('vendor_hash') && config('ninja.db.multi_db_enabled')) {
if (MultiDB::findAndSetDbByClientHash($request->input('vendor_hash'))) {
if ($client = Vendor::where('vendor_hash', $request->input('vendor_hash'))->first()) {
$primary_contact = $client->primary_contact()->first();
if (empty($primary_contact->email)) {
$primary_contact->email = Str::random(6).'@example.com';
}
$primary_contact->save();
auth()->guard('vendor')->loginUsingId($primary_contact->id, true);
return redirect($this->setRedirectPath());
}
}
} elseif ($request->has('vendor_hash')) {
if ($client = Vendor::where('vendor_hash', $request->input('vendor_hash'))->first()) {
$primary_contact = $client->primary_contact()->first();
if (empty($primary_contact->email)) {
$primary_contact->email = Str::random(6).'@example.com';
}
$primary_contact->save();
auth()->guard('vendor')->loginUsingId($primary_contact->id, true);
return redirect($this->setRedirectPath());
}
} elseif ($request->segment(3)) {
if ($vendor_contact = VendorContact::where('contact_key', $request->segment(3))->first()) {
if (empty($vendor_contact->email)) {
$vendor_contact->email = Str::random(6).'@example.com';
$vendor_contact->save();
}
auth()->guard('vendor')->loginUsingId($vendor_contact->id, true);
if ($request->query('next')) {
return redirect($request->query('next'));
}
return redirect($this->setRedirectPath());
}
}
//28-02-2022 middleware should not allow this to progress as we should have redirected by this stage.
abort(404, 'Unable to authenticate.');
return $next($request);
}
private function setRedirectPath()
{
return 'vendor/purchase_orders';
}
}

View File

@ -97,10 +97,6 @@ class UpdateClientRequest extends Request
{
$input = $this->all();
if (isset($input['group_settings_id'])) {
$input['group_settings_id'] = $this->decodePrimaryKey($input['group_settings_id']);
}
/* If the user removes the currency we must always set the default */
if (array_key_exists('settings', $input) && ! array_key_exists('currency_id', $input['settings'])) {
$input['settings']['currency_id'] = (string) auth()->user()->company()->settings->currency_id;

View File

@ -23,7 +23,8 @@ class BlackListRule implements Rule
'candassociates.com',
'vusra.com',
'fourthgenet.com',
'arxxwalls.com'
'arxxwalls.com',
'superhostforumla.com'
];
/**

View File

@ -51,6 +51,9 @@ class Backup extends BaseModel
{
nlog('deleting => '.$this->filename);
if(!$this->filename)
return;
try {
Storage::disk(config('filesystems.default'))->delete($this->filename);
} catch (\Exception $e) {

View File

@ -154,4 +154,13 @@ class VendorContact extends Authenticatable implements HasLocalePreference
{
return $this->hasMany(PurchaseOrderInvitation::class);
}
public function getLoginLink()
{
$domain = isset($this->company->portal_domain) ? $this->company->portal_domain : $this->company->domain();
return $domain.'/vendor/key_login/'.$this->contact_key;
}
}

View File

@ -20,6 +20,7 @@ use App\Models\Payment;
use App\Models\PaymentType;
use App\Models\SystemLog;
use App\PaymentDrivers\StripePaymentDriver;
use App\PaymentDrivers\Stripe\Jobs\UpdateCustomer;
use Stripe\PaymentIntent;
use Stripe\PaymentMethod;
@ -129,6 +130,8 @@ class CreditCard
public function processSuccessfulPayment()
{
UpdateCustomer::dispatch($this->stripe->company_gateway->company->company_key, $this->stripe->company_gateway->id, $this->stripe->client->id);
$stripe_method = $this->stripe->getStripePaymentMethod($this->stripe->payment_hash->data->server_response->payment_method);
$data = [

View File

@ -0,0 +1,92 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\PaymentDrivers\Stripe\Jobs;
use App\Jobs\Mail\PaymentFailedMailer;
use App\Jobs\Util\SystemLogger;
use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\Company;
use App\Models\CompanyGateway;
use App\Models\GatewayType;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use App\Models\SystemLog;
use App\PaymentDrivers\Stripe\Utilities;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class UpdateCustomer implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Utilities;
public $tries = 1;
public $deleteWhenMissingModels = true;
public int $company_gateway_id;
public string $company_key;
private int $client_id;
public function __construct(string $company_key, int $company_gateway_id, int $client_id)
{
$this->company_key = $company_key;
$this->company_gateway_id = $company_gateway_id;
$this->client_id = $client_id;
}
public function handle()
{
MultiDB::findAndSetDbByCompanyKey($this->company_key);
$company = Company::where('company_key', $this->company_key)->first();
if($company->id !== config('ninja.ninja_default_company_id'))
return;
$company_gateway = CompanyGateway::find($this->company_gateway_id);
$client = Client::withTrashed()->find($this->client_id);
$stripe = $company_gateway->driver($client)->init();
$customer = $stripe->findOrCreateCustomer();
//Else create a new record
$data['name'] = $client->present()->name();
$data['phone'] = substr($client->present()->phone(), 0, 20);
$data['address']['line1'] = $client->address1;
$data['address']['line2'] = $client->address2;
$data['address']['city'] = $client->city;
$data['address']['postal_code'] = $client->postal_code;
$data['address']['state'] = $client->state;
$data['address']['country'] = $client->country ? $client->country->iso_3166_2 : '';
$data['shipping']['name'] = $client->present()->name();
$data['shipping']['address']['line1'] = $client->shipping_address1;
$data['shipping']['address']['line2'] = $client->shipping_address2;
$data['shipping']['address']['city'] = $client->shipping_city;
$data['shipping']['address']['postal_code'] = $client->shipping_postal_code;
$data['shipping']['address']['state'] = $client->shipping_state;
$data['shipping']['address']['country'] = $client->shipping_country ? $client->shipping_country->iso_3166_2 : '';
\Stripe\Customer::update($customer->id, $data, $stripe->stripe_connect_auth);
}
}

View File

@ -34,10 +34,10 @@ class SendEmail
{
$this->payment->load('company', 'client.contacts');
$this->payment->client->contacts->each(function ($contact) {
if ($contact->email) {
EmailPayment::dispatch($this->payment, $this->payment->company, $contact);
}
});
$contact = $this->payment->client->contacts()->first();
if ($contact->email)
EmailPayment::dispatch($this->payment, $this->payment->company, $contact);
}
}

View File

@ -42,6 +42,7 @@ class VendorContactTransformer extends EntityTransformer
'custom_value2' => $vendor->custom_value2 ?: '',
'custom_value3' => $vendor->custom_value3 ?: '',
'custom_value4' => $vendor->custom_value4 ?: '',
'link' => $vendor->getLoginLink(),
];
}
}

View File

@ -15,9 +15,11 @@ use App\Http\Controllers\VendorPortal\InvitationController;
use App\Http\Controllers\VendorPortal\PurchaseOrderController;
use App\Http\Controllers\VendorPortal\UploadController;
use App\Http\Controllers\VendorPortal\VendorContactController;
use App\Http\Controllers\VendorPortal\VendorContactHashLoginController;
use Illuminate\Support\Facades\Route;
Route::get('vendors', [VendorContactLoginController::class, 'catch'])->name('vendor.catchall')->middleware(['domain_db', 'contact_account','vendor_locale']); //catch all
Route::get('vendor/key_login/{contact_key}', [VendorContactHashLoginController::class, 'login'])->name('contact_login')->middleware(['domain_db','vendor_contact_key_login']);
Route::group(['middleware' => ['invite_db'], 'prefix' => 'vendor', 'as' => 'vendor.'], function () {
/*Invitation catches*/