Merge remote-tracking branch 'upstream/v5-develop' into v5-client-portal-tests-dusk
This commit is contained in:
commit
2be806bb8e
136 changed files with 178775 additions and 176414 deletions
29
README.md
29
README.md
|
|
@ -4,14 +4,19 @@
|
|||
|
||||

|
||||

|
||||
|
||||
[](https://www.codacy.com/app/turbo124/invoiceninja?utm_source=github.com&utm_medium=referral&utm_content=invoiceninja/invoiceninja&utm_campaign=Badge_Grade)
|
||||
[](https://www.codacy.com/gh/turbo124/invoiceninja/dashboard?utm_source=github.com&utm_medium=referral&utm_content=turbo124/invoiceninja&utm_campaign=Badge_Grade)
|
||||
|
||||
# Invoice Ninja version 5!
|
||||
|
||||
## Quick Start
|
||||
## Preamble
|
||||
|
||||
Currently the client portal and API are of alpha quality, to get started:
|
||||
Version 5 of Invoice Ninja is here! We've taken the best parts of version 4 and bolted on all of the most requested features to produce a invoicing application like no other.
|
||||
|
||||
The new interface has a lot more functionality so it isn't a carbon copy of v4, but once you get used to the new layout and functionality we are sure you will love it!
|
||||
|
||||
If you have any questions, please join us on our [forum](https://forum.invoiceninja.com) or on [slack](https://invoiceninja.slack.com)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
git clone https://github.com/invoiceninja/invoiceninja.git
|
||||
|
|
@ -69,6 +74,8 @@ To improve chances of PRs being merged please include tests to ensure your code
|
|||
|
||||
API documentation is hosted using Swagger and can be found [HERE](https://app.swaggerhub.com/apis/invoiceninja/invoiceninja)
|
||||
|
||||
Installation, Configuration and Troubleshooting documentation can be found [HERE] (https://invoiceninja.github.io)
|
||||
|
||||
## Credits
|
||||
* [Hillel Coren](https://hillelcoren.com/)
|
||||
* [David Bomba](https://github.com/turbo124)
|
||||
|
|
@ -85,10 +92,18 @@ API documentation is hosted using Swagger and can be found [HERE](https://app.sw
|
|||
|
||||
## Current work in progress
|
||||
|
||||
Invoice Ninja is currently being written in a combination of Laravel for the API and Client Portal and Flutter for the front end management console. This will allow an immersive and consistent experience across any device: mobile, tablet or desktop.
|
||||
Invoice Ninja is written in a combination of technologies:
|
||||
|
||||
To manage our workflow we will be creating separate branches for the client (Flutter) and server (Laravel API / Client Portal) and merge these into a release branch for deployments.
|
||||
API - Laravel
|
||||
Client Portal - Laravel + Tailwind
|
||||
Admin Portal - Flutter
|
||||
|
||||
This allows an immersive and consistent experience across any device: mobile, tablet or desktop.
|
||||
|
||||
## Security
|
||||
|
||||
If you find a security issue with this application please send an email to contact@invoiceninja.com Please follow responsible disclosure procedures if you detect an issue. For further information on responsible disclosure please read [here](https://cheatsheetseries.owasp.org/cheatsheets/Vulnerability_Disclosure_Cheat_Sheet.html)
|
||||
|
||||
## License
|
||||
Invoice Ninja is released under the Attribution Assurance License.
|
||||
Invoice Ninja is released under the Elastic License.
|
||||
See [LICENSE](LICENSE) for details.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
5.2.7
|
||||
5.2.11
|
||||
|
|
@ -234,38 +234,38 @@ class CheckData extends Command
|
|||
}
|
||||
}
|
||||
|
||||
// check for more than one primary contact
|
||||
$clients = DB::table('clients')
|
||||
->leftJoin('client_contacts', function ($join) {
|
||||
$join->on('client_contacts.client_id', '=', 'clients.id')
|
||||
->where('client_contacts.is_primary', '=', true)
|
||||
->whereNull('client_contacts.deleted_at');
|
||||
})
|
||||
->groupBy('clients.id')
|
||||
->havingRaw('count(client_contacts.id) != 1');
|
||||
// // check for more than one primary contact
|
||||
// $clients = DB::table('clients')
|
||||
// ->leftJoin('client_contacts', function ($join) {
|
||||
// $join->on('client_contacts.client_id', '=', 'clients.id')
|
||||
// ->where('client_contacts.is_primary', '=', true)
|
||||
// ->whereNull('client_contacts.deleted_at');
|
||||
// })
|
||||
// ->groupBy('clients.id')
|
||||
// ->havingRaw('count(client_contacts.id) != 1');
|
||||
|
||||
if ($this->option('client_id')) {
|
||||
$clients->where('clients.id', '=', $this->option('client_id'));
|
||||
}
|
||||
// if ($this->option('client_id')) {
|
||||
// $clients->where('clients.id', '=', $this->option('client_id'));
|
||||
// }
|
||||
|
||||
$clients = $clients->get(['clients.id', 'clients.user_id', 'clients.company_id']);
|
||||
$this->logMessage($clients->count().' clients without a single primary contact');
|
||||
// $clients = $clients->get(['clients.id', 'clients.user_id', 'clients.company_id']);
|
||||
// // $this->logMessage($clients->count().' clients without a single primary contact');
|
||||
|
||||
if ($this->option('fix') == 'true') {
|
||||
foreach ($clients as $client) {
|
||||
$this->logMessage("Fixing missing primary contacts #{$client->id}");
|
||||
// // if ($this->option('fix') == 'true') {
|
||||
// // foreach ($clients as $client) {
|
||||
// // $this->logMessage("Fixing missing primary contacts #{$client->id}");
|
||||
|
||||
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
||||
$new_contact->client_id = $client->id;
|
||||
$new_contact->contact_key = Str::random(40);
|
||||
$new_contact->is_primary = true;
|
||||
$new_contact->save();
|
||||
}
|
||||
}
|
||||
// // $new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
||||
// // $new_contact->client_id = $client->id;
|
||||
// // $new_contact->contact_key = Str::random(40);
|
||||
// // $new_contact->is_primary = true;
|
||||
// // $new_contact->save();
|
||||
// // }
|
||||
// // }
|
||||
|
||||
if ($clients->count() > 0) {
|
||||
$this->isValid = false;
|
||||
}
|
||||
// if ($clients->count() > 0) {
|
||||
// $this->isValid = false;
|
||||
// }
|
||||
}
|
||||
|
||||
private function checkFailedJobs()
|
||||
|
|
@ -365,7 +365,7 @@ class CheckData extends Command
|
|||
/* Due to accounting differences we need to perform a second loop here to ensure there actually is an issue */
|
||||
$clients->each(function ($client_record) use ($credit_total_applied) {
|
||||
|
||||
$client = Client::find($client_record->id);
|
||||
$client = Client::withTrashed()->find($client_record->id);
|
||||
|
||||
$total_invoice_payments = 0;
|
||||
|
||||
|
|
@ -594,6 +594,7 @@ class CheckData extends Command
|
|||
'client',
|
||||
'client_contact',
|
||||
'payment',
|
||||
'recurring_invoice',
|
||||
],
|
||||
'invoices' => [
|
||||
'client',
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class Kernel extends ConsoleKernel
|
|||
|
||||
$schedule->job(new AutoBillCron)->dailyAt('00:30')->withoutOverlapping();
|
||||
|
||||
$schedule->job(new SchedulerCheck)->everyFiveMinutes();
|
||||
$schedule->job(new SchedulerCheck)->daily()->withoutOverlapping();
|
||||
|
||||
/* Run hosted specific jobs */
|
||||
if (Ninja::isHosted()) {
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ class CompanySettings extends BaseSettings
|
|||
public $font_size = 7; //@implemented
|
||||
public $primary_font = 'Roboto';
|
||||
public $secondary_font = 'Roboto';
|
||||
public $primary_color = '#142cb5';
|
||||
public $primary_color = '#298AAB';
|
||||
public $secondary_color = '#7081e0';
|
||||
|
||||
public $hide_paid_to_date = false; //@TODO where?
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ class InvoiceItem
|
|||
|
||||
public $product_key = '';
|
||||
|
||||
public $product_cost = 0;
|
||||
|
||||
public $notes = '';
|
||||
|
||||
public $discount = 0;
|
||||
|
|
@ -57,6 +59,7 @@ class InvoiceItem
|
|||
'type_id' => 'string',
|
||||
'quantity' => 'float',
|
||||
'cost' => 'float',
|
||||
'product_cost' => 'float',
|
||||
'product_key' => 'string',
|
||||
'notes' => 'string',
|
||||
'discount' => 'float',
|
||||
|
|
|
|||
|
|
@ -81,17 +81,23 @@ class Handler extends ExceptionHandler
|
|||
|
||||
app('sentry')->configureScope(function (Scope $scope): void {
|
||||
|
||||
if(auth()->guard('contact') && auth()->guard('contact')->user())
|
||||
$name = 'hosted@invoiceninja.com';
|
||||
|
||||
if(auth()->guard('contact') && auth()->guard('contact')->user()){
|
||||
$name = "Contact = ".auth()->guard('contact')->user()->email;
|
||||
$key = auth()->guard('contact')->user()->company->account->key;
|
||||
elseif (auth()->guard('user') && auth()->guard('user')->user())
|
||||
}
|
||||
elseif (auth()->guard('user') && auth()->guard('user')->user()){
|
||||
$name = "Admin = ".auth()->guard('user')->user()->email;
|
||||
$key = auth()->user()->account->key;
|
||||
}
|
||||
else
|
||||
$key = 'Anonymous';
|
||||
|
||||
$scope->setUser([
|
||||
'id' => 'Hosted_User',
|
||||
'id' => $key,
|
||||
'email' => 'hosted@invoiceninja.com',
|
||||
'name' => $key,
|
||||
'name' => $name,
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
@ -120,8 +126,7 @@ class Handler extends ExceptionHandler
|
|||
}
|
||||
}
|
||||
|
||||
// if(config('ninja.expanded_logging'))
|
||||
parent::report($exception);
|
||||
parent::report($exception);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +196,7 @@ class Handler extends ExceptionHandler
|
|||
} elseif ($exception instanceof GenericPaymentDriverFailure && $request->expectsJson()) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
} elseif ($exception instanceof GenericPaymentDriverFailure) {
|
||||
$data['message'] = $exception->getMessage();
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
}
|
||||
|
||||
return parent::render($request, $exception);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class ExpenseCategoryFactory
|
|||
$expense->company_id = $company_id;
|
||||
$expense->name = '';
|
||||
$expense->is_deleted = false;
|
||||
$expense->color = '#fff';
|
||||
$expense->color = '';
|
||||
|
||||
return $expense;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class TaskStatusFactory
|
|||
$task_status->user_id = $user_id;
|
||||
$task_status->company_id = $company_id;
|
||||
$task_status->name = '';
|
||||
$task_status->color = '#fff';
|
||||
$task_status->color = '';
|
||||
$task_status->status_order = 9999;
|
||||
|
||||
return $task_status;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ClientPortal\Contact\ContactPasswordResetRequest;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
|
|
@ -73,9 +74,8 @@ class ContactForgotPasswordController extends Controller
|
|||
return Password::broker('contacts');
|
||||
}
|
||||
|
||||
public function sendResetLinkEmail(Request $request)
|
||||
public function sendResetLinkEmail(ContactPasswordResetRequest $request)
|
||||
{
|
||||
//MultiDB::userFindAndSetDb($request->input('email'));
|
||||
|
||||
$user = MultiDB::hasContact($request->input('email'));
|
||||
|
||||
|
|
|
|||
|
|
@ -35,10 +35,16 @@ class ContactLoginController extends Controller
|
|||
|
||||
public function showLoginForm(Request $request)
|
||||
{
|
||||
if (strpos($request->getHost(), 'invoicing.co') !== false) {
|
||||
//if we are on the root domain invoicing.co do not show any company logos
|
||||
if(Ninja::isHosted() && count(explode('.', request()->getHost())) == 2){
|
||||
$company = null;
|
||||
}elseif (strpos($request->getHost(), 'invoicing.co') !== false) {
|
||||
$subdomain = explode('.', $request->getHost())[0];
|
||||
$company = Company::where('subdomain', $subdomain)->first();
|
||||
} elseif (Ninja::isSelfHost()) {
|
||||
} elseif(Ninja::isHosted() && $company = Company::where('portal_domain', $request->getSchemeAndHttpHost())->first()){
|
||||
|
||||
}
|
||||
elseif (Ninja::isSelfHost()) {
|
||||
$company = Account::first()->default_company;
|
||||
} else {
|
||||
$company = null;
|
||||
|
|
|
|||
|
|
@ -488,6 +488,8 @@ class LoginController extends BaseController
|
|||
auth()->user()->email_verified_at = now();
|
||||
auth()->user()->save();
|
||||
|
||||
auth()->user()->setCompany(auth()->user()->account->default_company);
|
||||
|
||||
$this->setLoginCache(auth()->user());
|
||||
|
||||
$cu = CompanyUser::whereUserId(auth()->user()->id);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use Illuminate\Contracts\View\Factory;
|
|||
use Illuminate\View\View;
|
||||
use ZipStream\Option\Archive;
|
||||
use ZipStream\ZipStream;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class InvoiceController extends Controller
|
||||
{
|
||||
|
|
@ -170,8 +171,10 @@ class InvoiceController extends Controller
|
|||
$invitation = $invoice->invitations->first();
|
||||
//$file = $invoice->pdf_file_path($invitation);
|
||||
$file = $invoice->service()->getInvoicePdf(auth()->user());
|
||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);;
|
||||
|
||||
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);;
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
}
|
||||
|
||||
// enable output of HTTP headers
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use Illuminate\View\View;
|
|||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use ZipStream\Option\Archive;
|
||||
use ZipStream\ZipStream;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class QuoteController extends Controller
|
||||
{
|
||||
|
|
@ -89,8 +90,11 @@ class QuoteController extends Controller
|
|||
|
||||
if ($quotes->count() == 1) {
|
||||
|
||||
$file = $quotes->first()->pdf_file_path();
|
||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
$file = $quotes->first()->service()->getQuotePdf();
|
||||
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
}
|
||||
|
||||
// enable output of HTTP headers
|
||||
|
|
|
|||
|
|
@ -474,6 +474,10 @@ class CompanyController extends BaseController
|
|||
*/
|
||||
public function destroy(DestroyCompanyRequest $request, Company $company)
|
||||
{
|
||||
|
||||
if(Ninja::isHosted() && config('ninja.ninja_default_company_id') == $company->id)
|
||||
return response()->json(['message' => 'Cannot purge this company'], 400);
|
||||
|
||||
$company_count = $company->account->companies->count();
|
||||
$account = $company->account;
|
||||
$account_key = $account->key;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ use App\Utils\TempFile;
|
|||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\SavesDocuments;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class CreditController.
|
||||
|
|
@ -536,8 +537,14 @@ class CreditController extends BaseController
|
|||
}
|
||||
break;
|
||||
case 'download':
|
||||
$file = $credit->pdf_file_path();
|
||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
// $file = $credit->pdf_file_path();
|
||||
$file = $credit->service()->getCreditPdf($credit->invitations->first());
|
||||
|
||||
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
break;
|
||||
case 'archive':
|
||||
$this->credit_repository->archive($credit);
|
||||
|
|
@ -585,9 +592,12 @@ class CreditController extends BaseController
|
|||
// $contact = $invitation->contact;
|
||||
$credit = $invitation->credit;
|
||||
|
||||
$file_path = $credit->service()->getCreditPdf($invitation);
|
||||
|
||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
$file = $credit->service()->getCreditPdf($invitation);
|
||||
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
// return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -672,8 +672,17 @@ class InvoiceController extends BaseController
|
|||
break;
|
||||
case 'download':
|
||||
|
||||
$file = $invoice->pdf_file_path();
|
||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
// $file = $invoice->pdf_file_path();
|
||||
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
|
||||
$file = $invoice->service()->getInvoicePdf();
|
||||
|
||||
// return response()->download(Storage::get($file), basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
|
||||
|
||||
break;
|
||||
case 'restore':
|
||||
|
|
@ -722,10 +731,11 @@ class InvoiceController extends BaseController
|
|||
}
|
||||
|
||||
//touch reminder1,2,3_sent + last_sent here if the email is a reminder.
|
||||
$invoice->service()->touchReminder($this->reminder_template)->deletePdf()->save();
|
||||
//$invoice->service()->touchReminder($this->reminder_template)->deletePdf()->save();
|
||||
$invoice->service()->touchReminder($this->reminder_template)->markSent()->save();
|
||||
|
||||
$invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($invoice) {
|
||||
EmailEntity::dispatch($invitation, $invoice->company, $this->reminder_template);
|
||||
EmailEntity::dispatch($invitation, $invoice->company, $this->reminder_template)->delay(now()->addSeconds(30));
|
||||
});
|
||||
|
||||
if ($invoice->invitations->count() >= 1) {
|
||||
|
|
@ -795,8 +805,11 @@ class InvoiceController extends BaseController
|
|||
|
||||
$file = $invoice->service()->getInvoicePdf($contact);
|
||||
|
||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
// return response()->download(Storage::get($file), basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -848,7 +861,10 @@ class InvoiceController extends BaseController
|
|||
|
||||
$file = $invoice->service()->getInvoiceDeliveryNote($invoice, $invoice->invitations->first()->contact);
|
||||
|
||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use App\Utils\CurlUtils;
|
|||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use stdClass;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class LicenseController extends BaseController
|
||||
{
|
||||
|
|
@ -152,7 +153,7 @@ class LicenseController extends BaseController
|
|||
{
|
||||
$account = auth()->user()->company()->account;
|
||||
|
||||
if($account->plan == 'white_label' && $account->plan_expires->lt(now())){
|
||||
if($account->plan == 'white_label' && Carbon::parse($account->plan_expires)->lt(now())){
|
||||
$account->plan = null;
|
||||
$account->plan_expires = null;
|
||||
$account->save();
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ class MigrationController extends BaseController
|
|||
*/
|
||||
public function purgeCompany(Company $company)
|
||||
{
|
||||
if(Ninja::isHosted() && config('ninja.ninja_default_company_id') == $company->id)
|
||||
return response()->json(['message' => 'Cannot purge this company'], 400);
|
||||
|
||||
$account = $company->account;
|
||||
$company_id = $company->id;
|
||||
|
||||
|
|
@ -102,6 +105,9 @@ class MigrationController extends BaseController
|
|||
|
||||
private function purgeCompanyWithForceFlag(Company $company)
|
||||
{
|
||||
if(Ninja::isHosted() && config('ninja.ninja_default_company_id') == $company->id)
|
||||
return response()->json(['message' => 'Cannot purge this company'], 400);
|
||||
|
||||
$account = $company->account;
|
||||
$company_id = $company->id;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\Payments\PaymentNotificationWebhookRequest;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Auth;
|
||||
|
||||
class PaymentNotificationWebhookController extends Controller
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public function __invoke(PaymentNotificationWebhookRequest $request, string $company_key, string $company_gateway_id, string $client_hash)
|
||||
{
|
||||
|
||||
$company_gateway = CompanyGateway::find($this->decodePrimaryKey($company_gateway_id));
|
||||
$client = Client::find($this->decodePrimaryKey($client_hash));
|
||||
|
||||
return $company_gateway
|
||||
->driver($client)
|
||||
->processWebhookRequest($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ use App\Utils\Traits\MakesHash;
|
|||
use App\Utils\Traits\SavesDocuments;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class QuoteController.
|
||||
|
|
@ -676,8 +677,14 @@ class QuoteController extends BaseController
|
|||
break;
|
||||
case 'download':
|
||||
|
||||
$file = $quote->pdf_file_path();
|
||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
//$file = $quote->pdf_file_path();
|
||||
$file = $quote->service()->getQuotePdf();
|
||||
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
|
||||
//return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
|
||||
break;
|
||||
case 'restore':
|
||||
|
|
@ -728,9 +735,14 @@ class QuoteController extends BaseController
|
|||
$contact = $invitation->contact;
|
||||
$quote = $invitation->quote;
|
||||
|
||||
$file_path = $quote->service()->getQuotePdf($contact);
|
||||
$file = $quote->service()->getQuotePdf($contact);
|
||||
nlog($file);
|
||||
|
||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
|
||||
// return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ use App\Utils\Traits\SavesDocuments;
|
|||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class RecurringInvoiceController.
|
||||
|
|
@ -500,9 +501,12 @@ class RecurringInvoiceController extends BaseController
|
|||
$contact = $invitation->contact;
|
||||
$recurring_invoice = $invitation->recurring_invoice;
|
||||
|
||||
$file_path = $recurring_invoice->service()->getInvoicePdf($contact);
|
||||
$file = $recurring_invoice->service()->getInvoicePdf($contact);
|
||||
|
||||
return response()->streamDownload(function () use($file) {
|
||||
echo Storage::get($file);
|
||||
}, basename($file));
|
||||
|
||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -241,6 +241,11 @@ class SetupController extends Controller
|
|||
$pdf->setChromiumPath(config('ninja.snappdf_chromium_path'));
|
||||
}
|
||||
|
||||
if (config('ninja.snappdf_chromium_arguments')) {
|
||||
$pdf->clearChromiumArguments();
|
||||
$pdf->addChromiumArguments(config('ninja.snappdf_chromium_arguments'));
|
||||
}
|
||||
|
||||
$pdf = $pdf
|
||||
->setHtml('GENERATING PDFs WORKS! Thank you for using Invoice Ninja!')
|
||||
->generate();
|
||||
|
|
|
|||
|
|
@ -60,12 +60,6 @@ class StripeConnectController extends BaseController
|
|||
$redirect_uri = 'https://invoicing.co/stripe/completed';
|
||||
$endpoint = "https://connect.stripe.com/oauth/authorize?response_type=code&client_id={$stripe_client_id}&redirect_uri={$redirect_uri}&scope=read_write&state={$token}";
|
||||
|
||||
// if($email = $request->getContact()->email)
|
||||
// $endpoint .= "&stripe_user[email]={$email}";
|
||||
|
||||
// $company_name = str_replace(" ", "_", $company->present()->name());
|
||||
// $endpoint .= "&stripe_user[business_name]={$company_name}";
|
||||
|
||||
return redirect($endpoint);
|
||||
}
|
||||
|
||||
|
|
@ -87,18 +81,24 @@ class StripeConnectController extends BaseController
|
|||
|
||||
}
|
||||
|
||||
// nlog($response);
|
||||
|
||||
$company = Company::where('company_key', $request->getTokenContent()['company_key'])->first();
|
||||
|
||||
$company_gateway = CompanyGatewayFactory::create($company->id, $company->owner()->id);
|
||||
$fees_and_limits = new \stdClass;
|
||||
$fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits;
|
||||
$company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34';
|
||||
$company_gateway->fees_and_limits = $fees_and_limits;
|
||||
$company_gateway->setConfig([]);
|
||||
$company_gateway->token_billing = 'always';
|
||||
// $company_gateway->save();
|
||||
$company_gateway = CompanyGateway::query()
|
||||
->where('gateway_key', 'd14dd26a47cecc30fdd65700bfb67b34')
|
||||
->where('company_id', $company->id)
|
||||
->first();
|
||||
|
||||
if(!$company_gateway)
|
||||
{
|
||||
$company_gateway = CompanyGatewayFactory::create($company->id, $company->owner()->id);
|
||||
$fees_and_limits = new \stdClass;
|
||||
$fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits;
|
||||
$company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34';
|
||||
$company_gateway->fees_and_limits = $fees_and_limits;
|
||||
$company_gateway->setConfig([]);
|
||||
$company_gateway->token_billing = 'always';
|
||||
// $company_gateway->save();
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'account_id' => $response->stripe_user_id,
|
||||
|
|
@ -111,18 +111,6 @@ class StripeConnectController extends BaseController
|
|||
"access_token" => $response->access_token
|
||||
];
|
||||
|
||||
/* Link account if existing account exists */
|
||||
// if($account_id = $this->checkAccountAlreadyLinkToEmail($company_gateway, $request->getContact()->email)) {
|
||||
|
||||
// $payload['account_id'] = $account_id;
|
||||
// $payload['stripe_user_id'] = $account_id;
|
||||
// $company_gateway->setConfig($payload);
|
||||
// $company_gateway->save();
|
||||
|
||||
// return view('auth.connect.existing');
|
||||
|
||||
// }
|
||||
|
||||
$company_gateway->setConfig($payload);
|
||||
$company_gateway->save();
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ class StripeController extends BaseController
|
|||
public function import()
|
||||
{
|
||||
|
||||
return response()->json(['message' => 'Processing'], 200);
|
||||
|
||||
|
||||
if(auth()->user()->isAdmin())
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -34,11 +34,15 @@ class CreditsTable extends Component
|
|||
|
||||
public function render()
|
||||
{
|
||||
|
||||
$query = Credit::query()
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->where('status_id', '<>', Credit::STATUS_DRAFT)
|
||||
->whereDate('due_date', '<=', now())
|
||||
->orWhere('due_date', NULL)
|
||||
->where(function ($query){
|
||||
$query->whereDate('due_date', '<=', now())
|
||||
->orWhereNull('due_date');
|
||||
})
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->paginate($this->per_page);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class InvoicesTable extends Component
|
|||
|
||||
$query = Invoice::query()
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', false);
|
||||
|
||||
if (in_array('paid', $this->status)) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class PaymentMethodsTable extends Component
|
|||
{
|
||||
$query = ClientGatewayToken::query()
|
||||
->with('gateway_type')
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', $this->client->id)
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->paginate($this->per_page);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class PaymentsTable extends Component
|
|||
{
|
||||
$query = Payment::query()
|
||||
->with('type', 'client')
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->paginate($this->per_page);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class QuotesTable extends Component
|
|||
}
|
||||
|
||||
$query = $query
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('status_id', '<>', Quote::STATUS_DRAFT)
|
||||
->paginate($this->per_page);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Utils\Traits\WithSorting;
|
||||
use Livewire\Component;
|
||||
|
|
@ -23,8 +24,12 @@ class RecurringInvoicesTable extends Component
|
|||
|
||||
public $per_page = 10;
|
||||
|
||||
public $company;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
$this->sort_asc = false;
|
||||
|
||||
$this->sort_field = 'date';
|
||||
|
|
@ -36,6 +41,7 @@ class RecurringInvoicesTable extends Component
|
|||
|
||||
$query = $query
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->whereIn('status_id', [RecurringInvoice::STATUS_PENDING, RecurringInvoice::STATUS_ACTIVE, RecurringInvoice::STATUS_PAUSED,RecurringInvoice::STATUS_COMPLETED])
|
||||
->orderBy('status_id', 'asc')
|
||||
->with('client')
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class SubscriptionRecurringInvoicesTable extends Component
|
|||
{
|
||||
$query = RecurringInvoice::query()
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->whereNotNull('subscription_id')
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->paginate($this->per_page);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class TasksTable extends Component
|
|||
public function render()
|
||||
{
|
||||
$query = Task::query()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', auth('contact')->user()->client->id);
|
||||
|
||||
if ($this->company->getSetting('show_all_tasks_client_portal') === 'invoiced') {
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ class QueryLogging
|
|||
$count = count($queries);
|
||||
$timeEnd = microtime(true);
|
||||
$time = $timeEnd - $timeStart;
|
||||
|
||||
//nlog($request->method().' - '.urldecode($request->url()).": $count queries - ".$time);
|
||||
// if($count > 50)
|
||||
//nlog($queries);
|
||||
|
||||
if($count > 150)
|
||||
nlog($queries);
|
||||
|
||||
$ip = '';
|
||||
|
||||
if(request()->header('Cf-Connecting-Ip'))
|
||||
|
|
|
|||
|
|
@ -30,17 +30,22 @@ class UrlSetDb
|
|||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
|
||||
if (config('ninja.db.multi_db_enabled')) {
|
||||
$hashids = new Hashids('', 10); //decoded output is _always_ an array.
|
||||
$hashids = new Hashids(config('ninja.hash_salt'), 10);
|
||||
|
||||
//parse URL hash and set DB
|
||||
$segments = explode('-', $request->route('confirmation_code'));
|
||||
|
||||
if(!is_array($segments))
|
||||
return response()->json(['message' => 'Invalid confirmation code'], 403);
|
||||
|
||||
$hashed_db = $hashids->decode($segments[0]);
|
||||
|
||||
MultiDB::setDB(MultiDB::DB_PREFIX.str_pad($hashed_db[0], 2, '0', STR_PAD_LEFT));
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\ClientPortal\Contact;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ContactPasswordResetRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'email' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -67,8 +67,8 @@ class UpdateCompanyRequest extends Request
|
|||
{
|
||||
$input = $this->all();
|
||||
|
||||
// if(array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
|
||||
// $input['portal_domain'] = str_replace("http:", "https:", $input['portal_domain']);
|
||||
if(Ninja::isHosted() && array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
|
||||
$input['portal_domain'] = $this->addScheme($input['portal_domain']);
|
||||
|
||||
if (array_key_exists('settings', $input)) {
|
||||
$input['settings'] = $this->filterSaveableSettings($input['settings']);
|
||||
|
|
@ -105,4 +105,15 @@ class UpdateCompanyRequest extends Request
|
|||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
private function addScheme($url, $scheme = 'https://')
|
||||
{
|
||||
|
||||
$url = str_replace("http://", "", $url);
|
||||
|
||||
$url = parse_url($url, PHP_URL_SCHEME) === null ? $scheme . $url : $url;
|
||||
|
||||
return rtrim($url, '/');
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class StoreExpenseRequest extends Request
|
|||
}
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class StoreExpenseCategoryRequest extends Request
|
|||
$input = $this->decodePrimaryKeys($input);
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class UpdateExpenseCategoryRequest extends Request
|
|||
$input = $this->all();
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,7 @@ class ImportJsonRequest extends Request
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
// 'import_type' => 'required',
|
||||
// 'files' => 'required_without:hash|array|min:1|max:6',
|
||||
// 'hash' => 'nullable|string',
|
||||
// 'column_map' => 'required_with:hash|array',
|
||||
// 'skip_header' => 'required_with:hash|boolean',
|
||||
// 'files.*' => 'file|mimes:csv,txt',
|
||||
'files' => 'file|mimes:zip',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Payments;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class PaymentNotificationWebhookRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
MultiDB::findAndSetDbByCompanyKey($this->company_key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ class StoreProjectRequest extends Request
|
|||
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class UpdateProjectRequest extends Request
|
|||
}
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class UpdateTaskRequest extends Request
|
|||
}
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class StoreTaskStatusRequest extends Request
|
|||
$input = $this->all();
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class UpdateTaskStatusRequest extends Request
|
|||
$input = $this->all();
|
||||
|
||||
if(array_key_exists('color', $input) && is_null($input['color']))
|
||||
$input['color'] = '#fff';
|
||||
$input['color'] = '';
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use App\Models\Account;
|
|||
use App\Models\Timezone;
|
||||
use App\Notifications\Ninja\NewAccountCreated;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\User\LoginCache;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
|
@ -39,6 +40,7 @@ use Turbo124\Beacon\Facades\LightLogs;
|
|||
class CreateAccount
|
||||
{
|
||||
use Dispatchable;
|
||||
use LoginCache;
|
||||
|
||||
protected $request;
|
||||
|
||||
|
|
@ -77,9 +79,6 @@ class CreateAccount
|
|||
|
||||
$sp794f3f->save();
|
||||
|
||||
if(Ninja::isHosted())
|
||||
$sp794f3f->startTrial('pro');
|
||||
|
||||
$sp035a66 = CreateCompany::dispatchNow($this->request, $sp794f3f);
|
||||
$sp035a66->load('account');
|
||||
$sp794f3f->default_company_id = $sp035a66->id;
|
||||
|
|
@ -95,6 +94,8 @@ class CreateAccount
|
|||
}
|
||||
|
||||
$spaa9f78->setCompany($sp035a66);
|
||||
$this->setLoginCache($spaa9f78);
|
||||
|
||||
$spafe62e = isset($this->request['token_name']) ? $this->request['token_name'] : request()->server('HTTP_USER_AGENT');
|
||||
$sp2d97e8 = CreateCompanyToken::dispatchNow($sp035a66, $spaa9f78, $spafe62e);
|
||||
|
||||
|
|
|
|||
|
|
@ -221,8 +221,8 @@ class CompanyImport implements ShouldQueue
|
|||
private function unzipFile()
|
||||
{
|
||||
|
||||
if(mime_content_type(Storage::path($this->file_location)) == 'text/plain')
|
||||
return Storage::path($this->file_location);
|
||||
// if(mime_content_type(Storage::path($this->file_location)) == 'text/plain')
|
||||
// return Storage::path($this->file_location);
|
||||
|
||||
$path = TempFile::filePath(Storage::get($this->file_location), basename($this->file_location));
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class SubscriptionCron
|
|||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('balance', '>', 0)
|
||||
->whereDate('due_date', '<=', now()->addDay()->startOfDay())
|
||||
->whereNull('deleted_at')
|
||||
->whereNotNull('subscription_id')
|
||||
->cursor();
|
||||
|
||||
|
|
|
|||
|
|
@ -86,9 +86,8 @@ class CreateEntityPdf implements ShouldQueue
|
|||
|
||||
$this->contact = $invitation->contact;
|
||||
|
||||
$this->disk = $disk;
|
||||
|
||||
// $this->disk = $disk ?? config('filesystems.default');
|
||||
$this->disk = Ninja::isHosted() ? config('filesystems.default') : $disk;
|
||||
|
||||
}
|
||||
|
||||
public function handle()
|
||||
|
|
@ -201,11 +200,9 @@ class CreateEntityPdf implements ShouldQueue
|
|||
|
||||
if(!Storage::disk($this->disk)->exists($path))
|
||||
Storage::disk($this->disk)->makeDirectory($path, 0775);
|
||||
|
||||
Storage::disk($this->disk)->put($file_path, $pdf);
|
||||
|
||||
nlog($file_path);
|
||||
|
||||
Storage::disk($this->disk)->put($file_path, $pdf);
|
||||
|
||||
}
|
||||
catch(\Exception $e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -190,6 +190,9 @@ class Import implements ShouldQueue
|
|||
{
|
||||
set_time_limit(0);
|
||||
|
||||
nlog("Starting Migration");
|
||||
nlog($this->user->email);
|
||||
|
||||
auth()->login($this->user, false);
|
||||
auth()->user()->setCompany($this->company);
|
||||
|
||||
|
|
@ -333,7 +336,7 @@ class Import implements ShouldQueue
|
|||
|
||||
$data = $this->transformCompanyData($data);
|
||||
|
||||
if(Ninja::isHosted() && strlen($data['subdomain']) > 1) {
|
||||
if(Ninja::isHosted()) {
|
||||
|
||||
if(!MultiDB::checkDomainAvailable($data['subdomain']))
|
||||
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
||||
|
|
@ -364,6 +367,10 @@ class Import implements ShouldQueue
|
|||
unset($data['referral_code']);
|
||||
}
|
||||
|
||||
if (isset($data['custom_fields']) && is_array($data['custom_fields'])) {
|
||||
$data['custom_fields'] = $this->parseCustomFields($data['custom_fields']);
|
||||
}
|
||||
|
||||
$company_repository = new CompanyRepository();
|
||||
$company_repository->save($data, $this->company);
|
||||
|
||||
|
|
@ -385,6 +392,34 @@ class Import implements ShouldQueue
|
|||
$company_repository = null;
|
||||
}
|
||||
|
||||
private function parseCustomFields($fields) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('account1', $fields))
|
||||
$fields['company1'] = $fields['account1'];
|
||||
|
||||
if(array_key_exists('account2', $fields))
|
||||
$fields['company2'] = $fields['account2'];
|
||||
|
||||
if(array_key_exists('invoice1', $fields))
|
||||
$fields['surcharge1'] = $fields['invoice1'];
|
||||
|
||||
if(array_key_exists('invoice2', $fields))
|
||||
$fields['surcharge2'] = $fields['invoice2'];
|
||||
|
||||
if(array_key_exists('invoice_text1', $fields))
|
||||
$fields['invoice1'] = $fields['invoice_text1'];
|
||||
|
||||
if(array_key_exists('invoice_text2', $fields))
|
||||
$fields['invoice2'] = $fields['invoice_text2'];
|
||||
|
||||
foreach ($fields as &$value) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
private function transformCompanyData(array $data): array
|
||||
{
|
||||
$company_settings = CompanySettings::defaults();
|
||||
|
|
@ -1321,7 +1356,7 @@ class Import implements ShouldQueue
|
|||
$modified['fees_and_limits'] = $this->cleanFeesAndLimits($modified['fees_and_limits']);
|
||||
}
|
||||
|
||||
else if(Ninja::isHosted() && $modified['gateway_key'] == 'd14dd26a37cecc30fdd65700bfb55b23'){
|
||||
if(Ninja::isHosted() && $modified['gateway_key'] == 'd14dd26a37cecc30fdd65700bfb55b23'){
|
||||
$modified['gateway_key'] = 'd14dd26a47cecc30fdd65700bfb67b34';
|
||||
$modified['fees_and_limits'] = [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
|||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class VersionCheck implements ShouldQueue
|
||||
{
|
||||
|
|
@ -49,7 +50,7 @@ class VersionCheck implements ShouldQueue
|
|||
if(!$account)
|
||||
return;
|
||||
|
||||
if($account->plan == 'white_label' && $account->plan_expires && $account->plan_expires->lt(now())){
|
||||
if($account->plan == 'white_label' && $account->plan_expires && Carbon::parse($account->plan_expires)->lt(now())){
|
||||
$account->plan = null;
|
||||
$account->plan_expires = null;
|
||||
$account->save();
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars[
|
|||
$fields->subscription_id = $subscription->id;
|
||||
$fields->user_id = $user_id;
|
||||
$fields->company_id = $subscription->company_id;
|
||||
$fields->activity_type_id = Activity::ARCHIVE_SUBSCRIPTIOn;
|
||||
$fields->activity_type_id = Activity::ARCHIVE_SUBSCRIPTION;
|
||||
|
||||
$this->activity_repo->save($fields, $subscription, $event->event_vars);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ class PaymentNotification implements ShouldQueue
|
|||
|
||||
}
|
||||
|
||||
|
||||
/*Google Analytics Track Revenue*/
|
||||
if (isset($payment->company->google_analytics_key)) {
|
||||
$this->trackRevenue($event);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace App\Mail\Engine;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
namespace App\Mail\Engine;
|
||||
|
||||
use App\DataMapper\EmailTemplateDefaults;
|
||||
use App\Jobs\Entity\CreateEntityPdf;
|
||||
use App\Models\Account;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
|
|
@ -116,8 +117,6 @@ class InvoiceEmailEngine extends BaseEmailEngine
|
|||
else
|
||||
$this->setAttachments([$this->invoice->pdf_file_path($this->invitation)]);
|
||||
|
||||
// $this->setAttachments(['path' => $this->invoice->pdf_file_path(), 'name' => basename($this->invoice->pdf_file_path())]);
|
||||
|
||||
}
|
||||
|
||||
//attach third party documents
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class SupportMessageSent extends Mailable
|
|||
|
||||
$account = auth()->user()->account;
|
||||
|
||||
$plan = $account->plan ?: 'Free Self Hosted';
|
||||
$plan = $account->plan ?: 'Forever Free';
|
||||
|
||||
$company = auth()->user()->company();
|
||||
$user = auth()->user();
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class Account extends BaseModel
|
|||
'promo_expires',
|
||||
'discount_expires',
|
||||
'trial_started',
|
||||
'plan_expires'
|
||||
// 'plan_expires'
|
||||
];
|
||||
|
||||
const PLAN_FREE = 'free';
|
||||
|
|
@ -120,6 +120,11 @@ class Account extends BaseModel
|
|||
return $this->hasMany(CompanyUser::class);
|
||||
}
|
||||
|
||||
public function owner()
|
||||
{
|
||||
return $this->hasMany(CompanyUser::class)->where('is_owner', true)->first() ? $this->hasMany(CompanyUser::class)->where('is_owner', true)->first()->user : false;
|
||||
}
|
||||
|
||||
public function getPlan()
|
||||
{
|
||||
return $this->plan ?: '';
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ namespace App\Models;
|
|||
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\Presenters\ClientPresenter;
|
||||
use App\Services\Client\ClientService;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
|
|
@ -396,61 +398,131 @@ class Client extends BaseModel implements HasLocalePreference
|
|||
*/
|
||||
public function getCreditCardGateway() :?CompanyGateway
|
||||
{
|
||||
$company_gateways = $this->getSetting('company_gateway_ids');
|
||||
// $company_gateways = $this->getSetting('company_gateway_ids');
|
||||
|
||||
/* It is very important to respect the order of the company_gateway_ids as they are ordered by priority*/
|
||||
if (strlen($company_gateways) >= 1) {
|
||||
$transformed_ids = $this->transformKeys(explode(',', $company_gateways));
|
||||
$gateways = $this->company
|
||||
->company_gateways
|
||||
->whereIn('id', $transformed_ids)
|
||||
->sortby(function ($model) use ($transformed_ids) {
|
||||
return array_search($model->id, $transformed_ids);
|
||||
});
|
||||
} else {
|
||||
$gateways = $this->company->company_gateways;
|
||||
}
|
||||
// /* It is very important to respect the order of the company_gateway_ids as they are ordered by priority*/
|
||||
// if (strlen($company_gateways) >= 1) {
|
||||
// $transformed_ids = $this->transformKeys(explode(',', $company_gateways));
|
||||
// $gateways = $this->company
|
||||
// ->company_gateways
|
||||
// ->whereIn('id', $transformed_ids)
|
||||
// ->sortby(function ($model) use ($transformed_ids) {
|
||||
// return array_search($model->id, $transformed_ids);
|
||||
// });
|
||||
// } else {
|
||||
// $gateways = $this->company->company_gateways;
|
||||
// }
|
||||
|
||||
foreach ($gateways as $gateway) {
|
||||
if (in_array(GatewayType::CREDIT_CARD, $gateway->driver($this)->gatewayTypeEnabled(GatewayType::CREDIT_CARD))) {
|
||||
return $gateway;
|
||||
// foreach ($gateways as $gateway) {
|
||||
// if (in_array(GatewayType::CREDIT_CARD, $gateway->driver($this)->gatewayTypeEnabled($gateway, GatewayType::CREDIT_CARD))) {
|
||||
// return $gateway;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return null;
|
||||
//
|
||||
|
||||
$pms = $this->service()->getPaymentMethods(0);
|
||||
|
||||
foreach($pms as $pm)
|
||||
{
|
||||
|
||||
if($pm['gateway_type_id'] == GatewayType::CREDIT_CARD)
|
||||
{
|
||||
$cg = CompanyGateway::find($pm['company_gateway_id']);
|
||||
|
||||
if($cg && !property_exists($cg->fees_and_limits, GatewayType::CREDIT_CARD)){
|
||||
$fees_and_limits = $cg->fees_and_limits;
|
||||
$fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits;
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
if($cg && $cg->fees_and_limits->{GatewayType::CREDIT_CARD}->is_enabled)
|
||||
return $cg;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
|
||||
|
||||
}
|
||||
|
||||
//todo refactor this - it is only searching for existing tokens
|
||||
public function getBankTransferGateway() :?CompanyGateway
|
||||
{
|
||||
$company_gateways = $this->getSetting('company_gateway_ids');
|
||||
$pms = $this->service()->getPaymentMethods(0);
|
||||
|
||||
if($this->currency()->code == 'USD' && in_array(GatewayType::BANK_TRANSFER, array_column($pms, 'gateway_type_id'))){
|
||||
|
||||
foreach($pms as $pm){
|
||||
|
||||
if($pm['gateway_type_id'] == GatewayType::BANK_TRANSFER)
|
||||
{
|
||||
$cg = CompanyGateway::find($pm['company_gateway_id']);
|
||||
|
||||
if($cg && !property_exists($cg->fees_and_limits, GatewayType::BANK_TRANSFER)){
|
||||
$fees_and_limits = $cg->fees_and_limits;
|
||||
$fees_and_limits->{GatewayType::BANK_TRANSFER} = new FeesAndLimits;
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
if($cg && $cg->fees_and_limits->{GatewayType::BANK_TRANSFER}->is_enabled)
|
||||
return $cg;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($company_gateways) >= 1) {
|
||||
$transformed_ids = $this->transformKeys(explode(',', $company_gateways));
|
||||
$gateways = $this->company
|
||||
->company_gateways
|
||||
->whereIn('id', $transformed_ids)
|
||||
->sortby(function ($model) use ($transformed_ids) {
|
||||
return array_search($model->id, $transformed_ids);
|
||||
});
|
||||
} else {
|
||||
$gateways = $this->company->company_gateways;
|
||||
}
|
||||
|
||||
foreach ($gateways as $gateway) {
|
||||
if ($this->currency()->code == 'USD' && in_array(GatewayType::BANK_TRANSFER, $gateway->driver($this)->gatewayTypeEnabled(GatewayType::BANK_TRANSFER))) {
|
||||
return $gateway;
|
||||
if($this->currency()->code == 'EUR' && in_array(GatewayType::BANK_TRANSFER, array_column($pms, 'gateway_type_id'))){
|
||||
|
||||
foreach($pms as $pm){
|
||||
|
||||
if($pm['gateway_type_id'] == GatewayType::SEPA)
|
||||
{
|
||||
$cg = CompanyGateway::find($pm['company_gateway_id']);
|
||||
|
||||
if($cg && $cg->fees_and_limits->{GatewayType::SEPA}->is_enabled)
|
||||
return $cg;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->currency()->code == 'EUR' && in_array(GatewayType::SEPA, $gateway->driver($this)->gatewayTypeEnabled(GatewayType::SEPA))) {
|
||||
return $gateway;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
// $company_gateways = $this->getSetting('company_gateway_ids');
|
||||
|
||||
// if (strlen($company_gateways) >= 1) {
|
||||
// $transformed_ids = $this->transformKeys(explode(',', $company_gateways));
|
||||
// $gateways = $this->company
|
||||
// ->company_gateways
|
||||
// ->whereIn('id', $transformed_ids)
|
||||
// ->sortby(function ($model) use ($transformed_ids) {
|
||||
// return array_search($model->id, $transformed_ids);
|
||||
// });
|
||||
// } else {
|
||||
// $gateways = $this->company->company_gateways;
|
||||
// }
|
||||
|
||||
// foreach ($gateways as $gateway) {
|
||||
// if ($this->currency()->code == 'USD' && in_array(GatewayType::BANK_TRANSFER, $gateway->driver($this)->gatewayTypeEnabled(GatewayType::BANK_TRANSFER))) {
|
||||
// return $gateway;
|
||||
// }
|
||||
|
||||
// if ($this->currency()->code == 'EUR' && in_array(GatewayType::SEPA, $gateway->driver($this)->gatewayTypeEnabled(GatewayType::SEPA))) {
|
||||
// return $gateway;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return null;
|
||||
}
|
||||
|
||||
public function getBankTransferMethodType()
|
||||
{
|
||||
|
||||
if ($this->currency()->code == 'USD') {
|
||||
return GatewayType::BANK_TRANSFER;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use App\Models\Presenters\CompanyPresenter;
|
|||
use App\Models\User;
|
||||
use App\Services\Notification\NotificationService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use App\Utils\Traits\CompanySettingsSaver;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\ThrottlesEmail;
|
||||
|
|
@ -31,6 +32,7 @@ class Company extends BaseModel
|
|||
use MakesHash;
|
||||
use CompanySettingsSaver;
|
||||
use ThrottlesEmail;
|
||||
use AppSetup;
|
||||
|
||||
const ENTITY_RECURRING_INVOICE = 'recurring_invoice';
|
||||
const ENTITY_CREDIT = 'credit';
|
||||
|
|
@ -311,7 +313,17 @@ class Company extends BaseModel
|
|||
|
||||
public function timezone()
|
||||
{
|
||||
return Timezone::find($this->settings->timezone_id);
|
||||
|
||||
$timezones = Cache::get('timezones');
|
||||
|
||||
if(!$timezones)
|
||||
$this->buildCache(true);
|
||||
|
||||
return $timezones->filter(function ($item) {
|
||||
return $item->id == $this->settings->timezone_id;
|
||||
})->first();
|
||||
|
||||
// return Timezone::find($this->settings->timezone_id);
|
||||
}
|
||||
|
||||
public function designs()
|
||||
|
|
@ -339,7 +351,18 @@ class Company extends BaseModel
|
|||
*/
|
||||
public function language()
|
||||
{
|
||||
return Language::find($this->settings->language_id);
|
||||
|
||||
$languages = Cache::get('languages');
|
||||
|
||||
if(!$languages)
|
||||
$this->buildCache(true);
|
||||
|
||||
return $languages->filter(function ($item) {
|
||||
return $item->id == $this->settings->language_id;
|
||||
})->first();
|
||||
|
||||
|
||||
// return Language::find($this->settings->language_id);
|
||||
}
|
||||
|
||||
public function getLocale()
|
||||
|
|
|
|||
|
|
@ -59,6 +59,17 @@ class CompanyGateway extends BaseModel
|
|||
16 => ['card' => 'images/credit_cards/Test-Discover-Icon.png', 'text' => 'Discover'],
|
||||
];
|
||||
|
||||
|
||||
// const TYPE_PAYPAL = 300;
|
||||
// const TYPE_STRIPE = 301;
|
||||
// const TYPE_LEDGER = 302;
|
||||
// const TYPE_FAILURE = 303;
|
||||
// const TYPE_CHECKOUT = 304;
|
||||
// const TYPE_AUTHORIZE = 305;
|
||||
// const TYPE_CUSTOM = 306;
|
||||
// const TYPE_BRAINTREE = 307;
|
||||
// const TYPE_WEPAY = 309;
|
||||
|
||||
public $gateway_consts = [
|
||||
'38f2c48af60c7dd69e04248cbb24c36e' => 300,
|
||||
'd14dd26a37cecc30fdd65700bfb55b23' => 301,
|
||||
|
|
@ -66,6 +77,8 @@ class CompanyGateway extends BaseModel
|
|||
'3b6621f970ab18887c4f6dca78d3f8bb' => 305,
|
||||
'54faab2ab6e3223dbe848b1686490baa' => 306,
|
||||
'd14dd26a47cecc30fdd65700bfb67b34' => 301,
|
||||
'8fdeed552015b3c7b44ed6c8ebd9e992' => 309,
|
||||
'f7ec488676d310683fb51802d076d713' => 307,
|
||||
];
|
||||
|
||||
protected $touches = [];
|
||||
|
|
@ -358,6 +371,11 @@ class CompanyGateway extends BaseModel
|
|||
return $fee;
|
||||
}
|
||||
|
||||
public function webhookUrl()
|
||||
{
|
||||
return route('payment_webhook', ['company_key' => $this->company->company_key, 'company_gateway_id' => $this->hashed_id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* we need to average out the gateway fees across all the invoices
|
||||
* so lets iterate.
|
||||
|
|
@ -399,4 +417,6 @@ class CompanyGateway extends BaseModel
|
|||
return $this
|
||||
->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ class UserPresenter extends EntityPresenter
|
|||
*/
|
||||
public function name()
|
||||
{
|
||||
|
||||
if(!$this->entity)
|
||||
return "No User Object Available";
|
||||
|
||||
$first_name = isset($this->entity->first_name) ? $this->entity->first_name : '';
|
||||
$last_name = isset($this->entity->last_name) ? $this->entity->last_name : '';
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class SystemLog extends Model
|
|||
const TYPE_CUSTOM = 306;
|
||||
const TYPE_BRAINTREE = 307;
|
||||
const TYPE_WEPAY = 309;
|
||||
const TYPE_PAYFAST = 310;
|
||||
|
||||
|
||||
const TYPE_QUOTA_EXCEEDED = 400;
|
||||
|
|
|
|||
|
|
@ -161,6 +161,8 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||
public function setCompany($company)
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ class AuthorizeCreditCard
|
|||
'data' => $this->formatGatewayResponse($data, $vars),
|
||||
];
|
||||
|
||||
SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_AUTHORIZE, $this->authorize->client);
|
||||
SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_AUTHORIZE, $this->authorize->client, $this->authorize->client->company);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
|
@ -202,6 +202,7 @@ class AuthorizeCreditCard
|
|||
private function processFailedResponse($data, $request)
|
||||
{
|
||||
$response = $data['response'];
|
||||
$amount = array_key_exists('amount_with_fee', $data) ? $data['amount_with_fee'] : 0;
|
||||
|
||||
PaymentFailureMailer::dispatch($this->authorize->client, $response->getTransactionResponse()->getTransId(), $this->authorize->client->company, $data['amount_with_fee']);
|
||||
|
||||
|
|
|
|||
|
|
@ -548,6 +548,15 @@ class BaseDriver extends AbstractPaymentDriver
|
|||
);
|
||||
}
|
||||
|
||||
public function genericWebhookUrl()
|
||||
{
|
||||
return route('payment_notification_webhook', [
|
||||
'company_key' => $this->client->company->company_key,
|
||||
'company_gateway_id' => $this->encodePrimaryKey($this->company_gateway->id),
|
||||
'client' => $this->encodePrimaryKey($this->client->id),
|
||||
]);
|
||||
}
|
||||
|
||||
/* Performs an extra iterate on the gatewayTypes() array and passes back only the enabled gateways*/
|
||||
public function gatewayTypeEnabled($type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
|
|
@ -39,6 +40,22 @@ class DriverTemplate extends BaseDriver
|
|||
|
||||
const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model
|
||||
|
||||
public function init()
|
||||
{
|
||||
return $this; /* This is where you boot the gateway with your auth credentials*/
|
||||
}
|
||||
|
||||
/* Returns an array of gateway types for the payment gateway */
|
||||
public function gatewayTypes(): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
$types[] = GatewayType::CREDIT_CARD;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/* Sets the payment method initialized */
|
||||
public function setPaymentMethod($payment_method_id)
|
||||
{
|
||||
$class = self::$methods[$payment_method_id];
|
||||
|
|
@ -75,4 +92,8 @@ class DriverTemplate extends BaseDriver
|
|||
{
|
||||
return $this->payment_method->yourTokenBillingImplmentation(); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
282
app/PaymentDrivers/PayFast/CreditCard.php
Normal file
282
app/PaymentDrivers/PayFast/CreditCard.php
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\PayFast;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\PayFastPaymentDriver;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CreditCard
|
||||
{
|
||||
|
||||
public $payfast;
|
||||
|
||||
public function __construct(PayFastPaymentDriver $payfast)
|
||||
{
|
||||
$this->payfast = $payfast;
|
||||
}
|
||||
|
||||
/*
|
||||
$data = array();
|
||||
$data['merchant_id'] = $this->getMerchantId();
|
||||
$data['merchant_key'] = $this->getMerchantKey();
|
||||
$data['return_url'] = $this->getReturnUrl();
|
||||
$data['cancel_url'] = $this->getCancelUrl();
|
||||
$data['notify_url'] = $this->getNotifyUrl();
|
||||
|
||||
if ($this->getCard()) {
|
||||
$data['name_first'] = $this->getCard()->getFirstName();
|
||||
$data['name_last'] = $this->getCard()->getLastName();
|
||||
$data['email_address'] = $this->getCard()->getEmail();
|
||||
}
|
||||
|
||||
$data['m_payment_id'] = $this->getTransactionId();
|
||||
$data['amount'] = $this->getAmount();
|
||||
$data['item_name'] = $this->getDescription();
|
||||
$data['custom_int1'] = $this->getCustomInt1();
|
||||
$data['custom_int2'] = $this->getCustomInt2();
|
||||
$data['custom_int3'] = $this->getCustomInt3();
|
||||
$data['custom_int4'] = $this->getCustomInt4();
|
||||
$data['custom_int5'] = $this->getCustomInt5();
|
||||
$data['custom_str1'] = $this->getCustomStr1();
|
||||
$data['custom_str2'] = $this->getCustomStr2();
|
||||
$data['custom_str3'] = $this->getCustomStr3();
|
||||
$data['custom_str4'] = $this->getCustomStr4();
|
||||
$data['custom_str5'] = $this->getCustomStr5();
|
||||
|
||||
if ($this->getPaymentMethod()) {
|
||||
$data['payment_method'] = $this->getPaymentMethod();
|
||||
}
|
||||
|
||||
if (1 == $this->getSubscriptionType()) {
|
||||
$data['subscription_type'] = $this->getSubscriptionType();
|
||||
$data['billing_date'] = $this->getBillingDate();
|
||||
$data['recurring_amount'] = $this->getRecurringAmount();
|
||||
$data['frequency'] = $this->getFrequency();
|
||||
$data['cycles'] = $this->getCycles();
|
||||
}
|
||||
if (2 == $this->getSubscriptionType()) {
|
||||
$data['subscription_type'] = $this->getSubscriptionType();
|
||||
}
|
||||
|
||||
$data['passphrase'] = $this->getParameter('passphrase'); 123456789012aV
|
||||
$data['signature'] = $this->generateSignature($data);
|
||||
*/
|
||||
|
||||
public function authorizeView($data)
|
||||
{
|
||||
$hash = Str::random(32);
|
||||
|
||||
Cache::put($hash, 'cc_auth', 300);
|
||||
|
||||
$data = [
|
||||
'merchant_id' => $this->payfast->company_gateway->getConfigField('merchantId'),
|
||||
'merchant_key' => $this->payfast->company_gateway->getConfigField('merchantKey'),
|
||||
'return_url' => route('client.payment_methods.index'),
|
||||
'cancel_url' => route('client.payment_methods.index'),
|
||||
'notify_url' => $this->payfast->genericWebhookUrl(),
|
||||
'm_payment_id' => $hash,
|
||||
'amount' => 5,
|
||||
'item_name' => 'pre-auth',
|
||||
'item_description' => 'Credit Card Pre Authorization',
|
||||
'subscription_type' => 2,
|
||||
'passphrase' => $this->payfast->company_gateway->getConfigField('passphrase'),
|
||||
];
|
||||
|
||||
$data['signature'] = $this->payfast->generateSignature($data);
|
||||
$data['gateway'] = $this->payfast;
|
||||
$data['payment_endpoint_url'] = $this->payfast->endpointUrl();
|
||||
|
||||
return render('gateways.payfast.authorize', $data);
|
||||
}
|
||||
|
||||
/*
|
||||
'm_payment_id' => NULL,
|
||||
'pf_payment_id' => '1409993',
|
||||
'payment_status' => 'COMPLETE',
|
||||
'item_name' => 'pre-auth',
|
||||
'item_description' => NULL,
|
||||
'amount_gross' => '5.00',
|
||||
'amount_fee' => '-2.53',
|
||||
'amount_net' => '2.47',
|
||||
'custom_str1' => NULL,
|
||||
'custom_str2' => NULL,
|
||||
'custom_str3' => NULL,
|
||||
'custom_str4' => NULL,
|
||||
'custom_str5' => NULL,
|
||||
'custom_int1' => NULL,
|
||||
'custom_int2' => NULL,
|
||||
'custom_int3' => NULL,
|
||||
'custom_int4' => NULL,
|
||||
'custom_int5' => NULL,
|
||||
'name_first' => NULL,
|
||||
'name_last' => NULL,
|
||||
'email_address' => NULL,
|
||||
'merchant_id' => '10023100',
|
||||
'token' => '34b66bc2-3c54-9590-03ea-42ee8b89922a',
|
||||
'billing_date' => '2021-07-05',
|
||||
'signature' => 'ebdb4ca937d0e3f43462841c0afc6ad9',
|
||||
'q' => '/payment_notification_webhook/EhbnVYyzJZyccY85hcHIkIzNPI2rtHzznAyyyG73oSxZidAdN9gf8BvAKDomqeHp/4openRe7Az/WPe99p3eLy',
|
||||
*/
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
$data = $request->all();
|
||||
|
||||
$cgt = [];
|
||||
$cgt['token'] = $data['token'];
|
||||
$cgt['payment_method_id'] = GatewayType::CREDIT_CARD;
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->exp_month = 'xx';
|
||||
$payment_meta->exp_year = 'xx';
|
||||
$payment_meta->brand = 'CC';
|
||||
$payment_meta->last4 = 'xxxx';
|
||||
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||
|
||||
$cgt['payment_meta'] = $payment_meta;
|
||||
|
||||
$token = $this->payfast->storeGatewayToken($cgt, []);
|
||||
|
||||
return response()->json([], 200);
|
||||
|
||||
}
|
||||
|
||||
public function paymentView($data)
|
||||
{
|
||||
|
||||
$payfast_data = [
|
||||
'merchant_id' => $this->payfast->company_gateway->getConfigField('merchantId'),
|
||||
'merchant_key' => $this->payfast->company_gateway->getConfigField('merchantKey'),
|
||||
'return_url' => route('client.payments.index'),
|
||||
'cancel_url' => route('client.payment_methods.index'),
|
||||
'notify_url' => $this->payfast->genericWebhookUrl(),
|
||||
'm_payment_id' => $data['payment_hash'],
|
||||
'amount' => $data['amount_with_fee'],
|
||||
'item_name' => 'purchase',
|
||||
'item_description' => ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number'),
|
||||
'passphrase' => $this->payfast->company_gateway->getConfigField('passphrase'),
|
||||
];
|
||||
|
||||
$payfast_data['signature'] = $this->payfast->generateSignature($payfast_data);
|
||||
$payfast_data['gateway'] = $this->payfast;
|
||||
$payfast_data['payment_endpoint_url'] = $this->payfast->endpointUrl();
|
||||
|
||||
return render('gateways.payfast.pay', array_merge($data, $payfast_data));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
[2021-07-05 11:21:24] local.INFO: array (
|
||||
'm_payment_id' => 'B7G9Q2vPhqkLEoMwwY1paXvPGuFxpbDe',
|
||||
'pf_payment_id' => '1410364',
|
||||
'payment_status' => 'COMPLETE',
|
||||
'item_name' => 'purchase',
|
||||
'item_description' => 'Invoices: ["0001"]',
|
||||
'amount_gross' => '100.00',
|
||||
'amount_fee' => '-2.30',
|
||||
'amount_net' => '97.70',
|
||||
'custom_str1' => NULL,
|
||||
'custom_str2' => NULL,
|
||||
'custom_str3' => NULL,
|
||||
'custom_str4' => NULL,
|
||||
'custom_str5' => NULL,
|
||||
'custom_int1' => NULL,
|
||||
'custom_int2' => NULL,
|
||||
'custom_int3' => NULL,
|
||||
'custom_int4' => NULL,
|
||||
'custom_int5' => NULL,
|
||||
'name_first' => NULL,
|
||||
'name_last' => NULL,
|
||||
'email_address' => NULL,
|
||||
'merchant_id' => '10023100',
|
||||
'signature' => '3ed27638479fd65cdffb0f4910679d10',
|
||||
'q' => '/payment_notification_webhook/EhbnVYyzJZyccY85hcHIkIzNPI2rtHzznAyyyG73oSxZidAdN9gf8BvAKDomqeHp/4openRe7Az/WPe99p3eLy',
|
||||
)
|
||||
|
||||
*/
|
||||
public function paymentResponse(Request $request)
|
||||
{
|
||||
$response_array = $request->all();
|
||||
|
||||
$state = [
|
||||
'server_response' => $request->all(),
|
||||
'payment_hash' => $request->input('m_payment_id'),
|
||||
];
|
||||
|
||||
$this->payfast->payment_hash->data = array_merge((array) $this->payfast->payment_hash->data, $state);
|
||||
$this->payfast->payment_hash->save();
|
||||
|
||||
if($response_array['payment_status'] == 'COMPLETE') {
|
||||
|
||||
$this->payfast->logSuccessfulGatewayResponse(['response' => $response_array, 'data' => $this->payfast->payment_hash], SystemLog::TYPE_PAYFAST);
|
||||
|
||||
return $this->processSuccessfulPayment($response_array);
|
||||
}
|
||||
else {
|
||||
$this->processUnsuccessfulPayment($response_array);
|
||||
}
|
||||
}
|
||||
|
||||
private function processSuccessfulPayment($response_array)
|
||||
{
|
||||
|
||||
$payment_record = [];
|
||||
$payment_record['amount'] = $response_array['amount_gross'];
|
||||
$payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER;
|
||||
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
|
||||
$payment_record['transaction_reference'] = $response_array['pf_payment_id'];
|
||||
|
||||
$payment = $this->payfast->createPayment($payment_record, Payment::STATUS_COMPLETED);
|
||||
|
||||
return redirect()->route('client.payments.show', ['payment' => $this->payfast->encodePrimaryKey($payment->id)]);
|
||||
}
|
||||
|
||||
private function processUnsuccessfulPayment($server_response)
|
||||
{
|
||||
PaymentFailureMailer::dispatch($this->payfast->client, $server_response->cancellation_reason, $this->payfast->client->company, $server_response->amount);
|
||||
|
||||
PaymentFailureMailer::dispatch(
|
||||
$this->payfast->client,
|
||||
$server_response,
|
||||
$this->payfast->client->company,
|
||||
$server_response['amount_gross']
|
||||
);
|
||||
|
||||
$message = [
|
||||
'server_response' => $server_response,
|
||||
'data' => $this->payfast->payment_hash->data,
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_PAYFAST,
|
||||
$this->payfast->client,
|
||||
$this->payfast->client->company,
|
||||
);
|
||||
|
||||
throw new PaymentFailed('Failed to process the payment.', 500);
|
||||
}
|
||||
|
||||
}
|
||||
184
app/PaymentDrivers/PayFast/Token.php
Normal file
184
app/PaymentDrivers/PayFast/Token.php
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\PayFast;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\PayFastPaymentDriver;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
|
||||
class Token
|
||||
{
|
||||
|
||||
public $payfast;
|
||||
|
||||
//https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/adhoc
|
||||
|
||||
public function __construct(PayFastPaymentDriver $payfast)
|
||||
{
|
||||
$this->payfast = $payfast;
|
||||
}
|
||||
|
||||
// Attributes
|
||||
// merchant-id
|
||||
// integer, 8 char | REQUIRED
|
||||
// Header, the Merchant ID as given by the PayFast system.
|
||||
// version
|
||||
// string | REQUIRED
|
||||
// Header, the PayFast API version (i.e. v1).
|
||||
// timestamp
|
||||
// ISO-8601 date and time | REQUIRED
|
||||
// Header, the current timestamp (YYYY-MM-DDTHH:MM:SS[+HH:MM]).
|
||||
// signature
|
||||
// string | REQUIRED
|
||||
// Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Characters must be in lower case.
|
||||
// amount
|
||||
// integer | REQUIRED
|
||||
// Body, the amount which the buyer must pay, in cents (ZAR), no decimals.
|
||||
// item_name
|
||||
// string, 100 char | REQUIRED
|
||||
// Body, the name of the item being charged for.
|
||||
// item_description
|
||||
// string, 255 char | OPTIONAL
|
||||
// Body, the description of the item being charged for.
|
||||
// itn
|
||||
// boolean | OPTIONAL
|
||||
// Body, specify whether an ITN must be sent for the tokenization payment (true by default).
|
||||
// m_payment_id
|
||||
// string, 100 char | OPTIONAL
|
||||
// Body, unique payment ID on the merchant’s system.
|
||||
// cc_cvv
|
||||
// numeric | OPTIONAL
|
||||
|
||||
|
||||
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||
{
|
||||
|
||||
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
||||
$amount = round(($amount * pow(10, $this->payfast->client->currency()->precision)),0);
|
||||
|
||||
$header =[
|
||||
'merchant-id' => $this->payfast->company_gateway->getConfigField('merchantId'),
|
||||
'timestamp' => now()->format('c'),
|
||||
'version' => 'v1',
|
||||
];
|
||||
|
||||
nlog($header);
|
||||
|
||||
$body = [
|
||||
'amount' => $amount,
|
||||
'item_name' => 'purchase',
|
||||
'item_description' => ctrans('texts.invoices') . ': ' . collect($payment_hash->invoices())->pluck('invoice_number'),
|
||||
'm_payment_id' => $payment_hash->hash,
|
||||
'passphrase' => $this->payfast->company_gateway->getConfigField('passphrase'),
|
||||
];
|
||||
|
||||
$header['signature'] = $this->genSig(array_merge($header, $body));
|
||||
|
||||
nlog($header['signature']);
|
||||
nlog($header['timestamp']);
|
||||
nlog($this->payfast->company_gateway->getConfigField('merchantId'));
|
||||
|
||||
$result = $this->send($header, $body, $cgt->token);
|
||||
|
||||
nlog($result);
|
||||
|
||||
// /*Refactor and push to BaseDriver*/
|
||||
// if ($data['response'] != null && $data['response']->getMessages()->getResultCode() == 'Ok') {
|
||||
|
||||
// $response = $data['response'];
|
||||
|
||||
// $this->storePayment($payment_hash, $data);
|
||||
|
||||
// $vars = [
|
||||
// 'invoices' => $payment_hash->invoices(),
|
||||
// 'amount' => $amount,
|
||||
// ];
|
||||
|
||||
// $logger_message = [
|
||||
// 'server_response' => $response->getTransactionResponse()->getTransId(),
|
||||
// 'data' => $this->formatGatewayResponse($data, $vars),
|
||||
// ];
|
||||
|
||||
// SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_AUTHORIZE, $this->authorize->client, $this->authorize->client->company);
|
||||
|
||||
// return true;
|
||||
// } else {
|
||||
|
||||
// $vars = [
|
||||
// 'invoices' => $payment_hash->invoices(),
|
||||
// 'amount' => $amount,
|
||||
// ];
|
||||
|
||||
// $logger_message = [
|
||||
// 'server_response' => $response->getTransactionResponse()->getTransId(),
|
||||
// 'data' => $this->formatGatewayResponse($data, $vars),
|
||||
// ];
|
||||
|
||||
// PaymentFailureMailer::dispatch($this->authorize->client, $response->getTransactionResponse()->getTransId(), $this->authorize->client->company, $amount);
|
||||
|
||||
// SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_AUTHORIZE, $this->authorize->client, $this->authorize->client->company);
|
||||
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
|
||||
private function genSig($data)
|
||||
{
|
||||
$fields = [];
|
||||
|
||||
ksort($data);
|
||||
|
||||
foreach($data as $key => $value)
|
||||
{
|
||||
if (!empty($data[$key])) {
|
||||
$fields[$key] = $data[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return md5(http_build_query($fields));
|
||||
}
|
||||
|
||||
private function send($headers, $body, $token)
|
||||
{
|
||||
$client = new \GuzzleHttp\Client(
|
||||
[
|
||||
'headers' => $headers,
|
||||
]);
|
||||
|
||||
try {
|
||||
$response = $client->post("https://api.payfast.co.za/subscriptions/{$token}/adhoc?testing=true",[
|
||||
RequestOptions::JSON => ['body' => $body], RequestOptions::ALLOW_REDIRECTS => false
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(),true);
|
||||
}
|
||||
catch(\Exception $e)
|
||||
{
|
||||
|
||||
nlog($e->getMessage());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
202
app/PaymentDrivers/PayFastPaymentDriver.php
Normal file
202
app/PaymentDrivers/PayFastPaymentDriver.php
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\PayFast\CreditCard;
|
||||
use App\PaymentDrivers\PayFast\Token;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class PayFastPaymentDriver extends BaseDriver
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $refundable = false; //does this gateway support refunds?
|
||||
|
||||
public $token_billing = false; //does this gateway support token billing?
|
||||
|
||||
public $can_authorise_credit_card = true; //does this gateway support authorizations?
|
||||
|
||||
public $payfast; //initialized gateway
|
||||
|
||||
public $payment_method; //initialized payment method
|
||||
|
||||
public static $methods = [
|
||||
GatewayType::CREDIT_CARD => CreditCard::class,
|
||||
];
|
||||
|
||||
const SYSTEM_LOG_TYPE = SystemLog::TYPE_PAYFAST;
|
||||
|
||||
//developer resources
|
||||
//https://sandbox.payfast.co.za/
|
||||
|
||||
public function gatewayTypes(): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
if($this->client->currency()->code == 'ZAR')
|
||||
$types[] = GatewayType::CREDIT_CARD;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
public function endpointUrl()
|
||||
{
|
||||
if($this->company_gateway->getConfigField('testMode'))
|
||||
return 'https://sandbox.payfast.co.za/eng/process';
|
||||
|
||||
return 'https://www.payfast.co.za/eng/process';
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
|
||||
try{
|
||||
|
||||
$this->payfast = new \PayFast\PayFastPayment(
|
||||
[
|
||||
'merchantId' => $this->company_gateway->getConfigField('merchantId'),
|
||||
'merchantKey' => $this->company_gateway->getConfigField('merchantKey'),
|
||||
'passPhrase' => $this->company_gateway->getConfigField('passPhrase'),
|
||||
'testMode' => $this->company_gateway->getConfigField('testMode')
|
||||
]
|
||||
);
|
||||
|
||||
} catch(Exception $e) {
|
||||
|
||||
echo '##PAYFAST## There was an exception: '.$e->getMessage();
|
||||
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPaymentMethod($payment_method_id)
|
||||
{
|
||||
$class = self::$methods[$payment_method_id];
|
||||
$this->payment_method = new $class($this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function authorizeView(array $data)
|
||||
{
|
||||
return $this->payment_method->authorizeView($data);
|
||||
}
|
||||
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
return $this->payment_method->authorizeResponse($request);
|
||||
}
|
||||
|
||||
public function processPaymentView(array $data)
|
||||
{
|
||||
return $this->payment_method->paymentView($data); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
return $this->payment_method->paymentResponse($request); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||
{
|
||||
return (new Token($this))->tokenBilling($cgt, $payment_hash);
|
||||
}
|
||||
|
||||
public function generateSignature($data)
|
||||
{
|
||||
$fields = array();
|
||||
|
||||
// specific order required by PayFast
|
||||
// @see https://developers.payfast.co.za/documentation/#checkout-page
|
||||
foreach (array('merchant_id', 'merchant_key', 'return_url', 'cancel_url', 'notify_url', 'name_first',
|
||||
'name_last', 'email_address', 'cell_number',
|
||||
/**
|
||||
* Transaction Details
|
||||
*/
|
||||
'm_payment_id', 'amount', 'item_name', 'item_description',
|
||||
/**
|
||||
* Custom return data
|
||||
*/
|
||||
'custom_int1', 'custom_int2', 'custom_int3', 'custom_int4', 'custom_int5',
|
||||
'custom_str1', 'custom_str2', 'custom_str3', 'custom_str4', 'custom_str5',
|
||||
/**
|
||||
* Email confirmation
|
||||
*/
|
||||
'email_confirmation', 'confirmation_address',
|
||||
/**
|
||||
* Payment Method
|
||||
*/
|
||||
'payment_method',
|
||||
/**
|
||||
* Subscriptions
|
||||
*/
|
||||
'subscription_type', 'billing_date', 'recurring_amount', 'frequency', 'cycles',
|
||||
/**
|
||||
* Passphrase for md5 signature generation
|
||||
*/
|
||||
'passphrase') as $key) {
|
||||
if (!empty($data[$key])) {
|
||||
$fields[$key] = $data[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return md5(http_build_query($fields));
|
||||
}
|
||||
|
||||
|
||||
public function processWebhookRequest(Request $request, Payment $payment = null)
|
||||
{
|
||||
|
||||
$data = $request->all();
|
||||
nlog($data);
|
||||
|
||||
if(array_key_exists('m_payment_id', $data))
|
||||
{
|
||||
|
||||
$hash = Cache::get($data['m_payment_id']);
|
||||
|
||||
switch ($hash)
|
||||
{
|
||||
case 'cc_auth':
|
||||
return $this->setPaymentMethod(GatewayType::CREDIT_CARD)
|
||||
->authorizeResponse($request);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$data['m_payment_id']])->first();
|
||||
|
||||
return $this->setPaymentMethod(GatewayType::CREDIT_CARD)
|
||||
->setPaymentHash($payment_hash)
|
||||
->processPaymentResponse($request);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return response()->json([], 200);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ class StripePaymentDriver extends BaseDriver
|
|||
public function gatewayTypes(): array
|
||||
{
|
||||
$types = [
|
||||
GatewayType::CRYPTO,
|
||||
// GatewayType::CRYPTO,
|
||||
GatewayType::CREDIT_CARD
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ use WePayCommon;
|
|||
nlog("authorize the card first!");
|
||||
|
||||
$response = $this->wepay_payment_driver->wepay->request('credit_card/authorize', array(
|
||||
// 'callback_uri' => route('payment_webhook', ['company_key' => $this->wepay_payment_driver->company_gateway->company->company_key, 'company_gateway_id' => $this->wepay_payment_driver->company_gateway->hashed_id]),
|
||||
'client_id' => config('ninja.wepay.client_id'),
|
||||
'client_secret' => config('ninja.wepay.client_secret'),
|
||||
'credit_card_id' => (int)$request->input('credit_card_id'),
|
||||
|
|
|
|||
|
|
@ -49,28 +49,11 @@ class CompanyRepository extends BaseRepository
|
|||
private function parseCustomFields($fields) :array
|
||||
{
|
||||
|
||||
if(array_key_exists('account1', $fields))
|
||||
$fields['company1'] = $fields['account1'];
|
||||
|
||||
if(array_key_exists('account2', $fields))
|
||||
$fields['company2'] = $fields['account2'];
|
||||
|
||||
if(array_key_exists('invoice1', $fields))
|
||||
$fields['surcharge1'] = $fields['invoice1'];
|
||||
|
||||
if(array_key_exists('invoice2', $fields))
|
||||
$fields['surcharge2'] = $fields['invoice2'];
|
||||
|
||||
if(array_key_exists('invoice_text1', $fields))
|
||||
$fields['invoice1'] = $fields['invoice_text1'];
|
||||
|
||||
if(array_key_exists('invoice_text2', $fields))
|
||||
$fields['invoice2'] = $fields['invoice_text2'];
|
||||
|
||||
foreach ($fields as &$value) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,21 +51,25 @@ class ClientService
|
|||
$credits = $this->client->credits()
|
||||
->where('is_deleted', false)
|
||||
->where('balance', '>', 0)
|
||||
->whereDate('due_date', '<=', now()->format('Y-m-d'))
|
||||
->orWhere('due_date', NULL)
|
||||
->where(function ($query){
|
||||
$query->whereDate('due_date', '<=', now()->format('Y-m-d'))
|
||||
->orWhereNull('due_date');
|
||||
})
|
||||
->orderBy('created_at','ASC');
|
||||
|
||||
return Number::roundValue($credits->sum('balance'), $this->client->currency()->precision);
|
||||
}
|
||||
|
||||
public function getCredits() :Collection
|
||||
public function getCredits()
|
||||
{
|
||||
return $this->client->credits()
|
||||
->where('is_deleted', false)
|
||||
->where('balance', '>', 0)
|
||||
->whereDate('due_date', '<=', now()->format('Y-m-d'))
|
||||
->orWhere('due_date', NULL)
|
||||
->orderBy('created_at','ASC');
|
||||
->where(function ($query){
|
||||
$query->whereDate('due_date', '<=', now()->format('Y-m-d'))
|
||||
->orWhereNull('due_date');
|
||||
})
|
||||
->orderBy('created_at','ASC')->get();
|
||||
}
|
||||
|
||||
public function getPaymentMethods(float $amount)
|
||||
|
|
|
|||
|
|
@ -41,10 +41,13 @@ class GetCreditPdf extends AbstractService
|
|||
|
||||
$file_path = $path.$this->credit->numberFormatter().'.pdf';
|
||||
|
||||
$disk = 'public';
|
||||
// $disk = 'public';
|
||||
$disk = config('filesystems.default');
|
||||
|
||||
$file_path = CreateEntityPdf::dispatchNow($this->invitation);
|
||||
|
||||
return Storage::disk($disk)->path($file_path);
|
||||
nlog($file_path);
|
||||
return $file_path;
|
||||
// return Storage::disk($disk)->path($file_path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ class GenerateDeliveryNote
|
|||
|
||||
$this->contact = $contact;
|
||||
|
||||
$this->disk = 'public';
|
||||
// $this->disk = 'public';
|
||||
|
||||
// $this->disk = $disk ?? config('filesystems.default');
|
||||
$this->disk = $disk ?? config('filesystems.default');
|
||||
}
|
||||
|
||||
public function run()
|
||||
|
|
@ -111,7 +111,8 @@ class GenerateDeliveryNote
|
|||
|
||||
Storage::disk($this->disk)->put($file_path, $pdf);
|
||||
|
||||
return Storage::disk($this->disk)->path($file_path);
|
||||
//return Storage::disk($this->disk)->path($file_path);
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ class GetInvoicePdf extends AbstractService
|
|||
|
||||
$file_path = $path.$this->invoice->numberFormatter().'.pdf';
|
||||
|
||||
$disk = 'public';
|
||||
// $disk = 'public';
|
||||
$disk = config('filesystems.default');
|
||||
|
||||
$file = Storage::disk($disk)->exists($file_path);
|
||||
|
||||
|
|
@ -47,6 +48,8 @@ class GetInvoicePdf extends AbstractService
|
|||
$file_path = CreateEntityPdf::dispatchNow($invitation);
|
||||
}
|
||||
|
||||
return Storage::disk($disk)->path($file_path);
|
||||
// return Storage::disk($disk)->path($file_path);
|
||||
//
|
||||
return $file_path;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ class HandleReversal extends AbstractService
|
|||
$credit = CreditFactory::create($this->invoice->company_id, $this->invoice->user_id);
|
||||
$credit->client_id = $this->invoice->client_id;
|
||||
$credit->invoice_id = $this->invoice->id;
|
||||
|
||||
$credit->date = now();
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = (float) $total_paid;
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ class PaymentService
|
|||
->service()
|
||||
->getCredits();
|
||||
|
||||
|
||||
foreach ($credits as $credit) {
|
||||
//starting invoice balance
|
||||
$invoice_balance = $invoice->balance;
|
||||
|
|
|
|||
|
|
@ -39,10 +39,12 @@ class GetQuotePdf extends AbstractService
|
|||
|
||||
$file_path = $path.$this->quote->numberFormatter().'.pdf';
|
||||
|
||||
$disk = 'public';
|
||||
|
||||
// $disk = 'public';
|
||||
$disk = config('filesystems.default');
|
||||
|
||||
$file_path = CreateEntityPdf::dispatchNow($invitation);
|
||||
|
||||
return Storage::disk($disk)->path($file_path);
|
||||
return $file_path;
|
||||
//return Storage::disk($disk)->path($file_path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@ class QuoteService
|
|||
|
||||
$this->quote->fresh();
|
||||
|
||||
if ($this->quote->client->getSetting('auto_archive_quote')) {
|
||||
$quote_repo = new QuoteRepository();
|
||||
$quote_repo->archive($this->quote);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -129,10 +134,6 @@ class QuoteService
|
|||
public function convertToInvoice()
|
||||
{
|
||||
|
||||
//to prevent circular references we need to explicit call this here.
|
||||
// $mark_approved = new MarkApproved($this->quote->client);
|
||||
// $this->quote = $mark_approved->run($this->quote);
|
||||
|
||||
$this->convert();
|
||||
|
||||
$this->invoice->service()->createInvitations();
|
||||
|
|
|
|||
|
|
@ -41,14 +41,14 @@ class GetInvoicePdf extends AbstractService
|
|||
|
||||
$file_path = $path.$this->entity->hashed_id.'.pdf';
|
||||
|
||||
$disk = 'public';
|
||||
$disk = config('filesystems.default');
|
||||
|
||||
$file = Storage::disk($disk)->exists($file_path);
|
||||
|
||||
if (! $file) {
|
||||
$file_path = CreateEntityPdf::dispatchNow($invitation);
|
||||
}
|
||||
|
||||
return Storage::disk($disk)->path($file_path);
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ class SubscriptionService
|
|||
$recurring_invoice->next_send_date = now();
|
||||
$recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice);
|
||||
$recurring_invoice->next_send_date = $recurring_invoice->nextSendDate();
|
||||
|
||||
$recurring_invoice->auto_bill = $this->subscription->auto_bill;
|
||||
|
||||
/* Start the recurring service */
|
||||
$recurring_invoice->service()
|
||||
->start()
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ use App\Utils\CurlUtils;
|
|||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Phantom
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ trait AppSetup
|
|||
$orderBy = 'num_days';
|
||||
} elseif ($name == 'fonts') {
|
||||
$orderBy = 'sort_order';
|
||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks', 'timezones'])) {
|
||||
$orderBy = 'name';
|
||||
} else {
|
||||
$orderBy = 'id';
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ trait PdfMaker
|
|||
$pdf->setChromiumPath(config('ninja.snappdf_chromium_path'));
|
||||
}
|
||||
|
||||
if (config('ninja.snappdf_chromium_arguments')) {
|
||||
$pdf->clearChromiumArguments();
|
||||
$pdf->addChromiumArguments(config('ninja.snappdf_chromium_arguments'));
|
||||
}
|
||||
|
||||
$generated = $pdf
|
||||
->setHtml($html)
|
||||
->generate();
|
||||
|
|
|
|||
|
|
@ -35,8 +35,15 @@ trait SubscriptionHooker
|
|||
'headers' => $headers,
|
||||
]);
|
||||
|
||||
nlog("method name must be a string");
|
||||
nlog($subscription->webhook_configuration['post_purchase_rest_method']);
|
||||
nlog($subscription->webhook_configuration['post_purchase_url']);
|
||||
|
||||
$post_purchase_rest_method = (string)$subscription->webhook_configuration['post_purchase_rest_method'];
|
||||
$post_purchase_url = (string)$subscription->webhook_configuration['post_purchase_url'];
|
||||
|
||||
try {
|
||||
$response = $client->{$subscription->webhook_configuration['post_purchase_rest_method']}($subscription->webhook_configuration['post_purchase_url'],[
|
||||
$response = $client->{$post_purchase_rest_method}($post_purchase_url,[
|
||||
RequestOptions::JSON => ['body' => $body], RequestOptions::ALLOW_REDIRECTS => false
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
"asm/php-ansible": "dev-main",
|
||||
"authorizenet/authorizenet": "^2.0",
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"beganovich/snappdf": "^1.0",
|
||||
"beganovich/snappdf": "^1.7",
|
||||
"braintree/braintree_php": "^6.0",
|
||||
"checkout/checkout-sdk-php": "^1.0",
|
||||
"cleverit/ubl_invoice": "^1.3",
|
||||
|
|
@ -47,6 +47,7 @@
|
|||
"google/apiclient": "^2.7",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"hashids/hashids": "^4.0",
|
||||
"hedii/laravel-gelf-logger": "^6.0",
|
||||
"intervention/image": "^2.5",
|
||||
"laracasts/presenter": "^0.2.1",
|
||||
"laravel/framework": "^8.0",
|
||||
|
|
@ -63,6 +64,7 @@
|
|||
"maennchen/zipstream-php": "^1.2",
|
||||
"nwidart/laravel-modules": "^8.0",
|
||||
"omnipay/paypal": "^3.0",
|
||||
"payfast/payfast-php-sdk": "^1.1",
|
||||
"pragmarx/google2fa": "^8.0",
|
||||
"predis/predis": "^1.1",
|
||||
"sentry/sentry-laravel": "^2",
|
||||
|
|
|
|||
772
composer.lock
generated
772
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -102,8 +102,71 @@ return [
|
|||
|
||||
'invoiceninja' => [
|
||||
'driver' => 'single',
|
||||
'level' => 'debug',
|
||||
'path' => storage_path('logs/invoiceninja.log'),
|
||||
],
|
||||
|
||||
'gelf' => [
|
||||
'driver' => 'custom',
|
||||
|
||||
'via' => \Hedii\LaravelGelfLogger\GelfLoggerFactory::class,
|
||||
|
||||
// This optional option determines the processors that should be
|
||||
// pushed to the handler. This option is useful to modify a field
|
||||
// in the log context (see NullStringProcessor), or to add extra
|
||||
// data. Each processor must be a callable or an object with an
|
||||
// __invoke method: see monolog documentation about processors.
|
||||
// Default is an empty array.
|
||||
'processors' => [
|
||||
\Hedii\LaravelGelfLogger\Processors\NullStringProcessor::class,
|
||||
// another processor...
|
||||
],
|
||||
|
||||
// This optional option determines the minimum "level" a message
|
||||
// must be in order to be logged by the channel. Default is 'debug'
|
||||
'level' => 'debug',
|
||||
|
||||
// This optional option determines the channel name sent with the
|
||||
// message in the 'facility' field. Default is equal to app.env
|
||||
// configuration value
|
||||
'name' => 'my-custom-name',
|
||||
|
||||
// This optional option determines the system name sent with the
|
||||
// message in the 'source' field. When forgotten or set to null,
|
||||
// the current hostname is used.
|
||||
'system_name' => null,
|
||||
|
||||
// This optional option determines if you want the UDP, TCP or HTTP
|
||||
// transport for the gelf log messages. Default is UDP
|
||||
'transport' => 'udp',
|
||||
|
||||
// This optional option determines the host that will receive the
|
||||
// gelf log messages. Default is 127.0.0.1
|
||||
'host' => env('GRAYLOG_SERVER', '127.0.0.1'),
|
||||
|
||||
// This optional option determines the port on which the gelf
|
||||
// receiver host is listening. Default is 12201
|
||||
'port' => 12201,
|
||||
|
||||
// This optional option determines the path used for the HTTP
|
||||
// transport. When forgotten or set to null, default path '/gelf'
|
||||
// is used.
|
||||
'path' => null,
|
||||
|
||||
// This optional option determines the maximum length per message
|
||||
// field. When forgotten or set to null, the default value of
|
||||
// \Monolog\Formatter\GelfMessageFormatter::DEFAULT_MAX_LENGTH is
|
||||
// used (currently this value is 32766)
|
||||
'max_length' => null,
|
||||
|
||||
// This optional option determines the prefix for 'context' fields
|
||||
// from the Monolog record. Default is null (no context prefix)
|
||||
'context_prefix' => null,
|
||||
|
||||
// This optional option determines the prefix for 'extra' fields
|
||||
// from the Monolog record. Default is null (no extra prefix)
|
||||
'extra_prefix' => null,
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ return [
|
|||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.2.8',
|
||||
'app_tag' => '5.2.8',
|
||||
'app_version' => '5.2.11',
|
||||
'app_tag' => '5.2.11',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
|
@ -144,6 +144,7 @@ return [
|
|||
'log_pdf_html' => env('LOG_PDF_HTML', false),
|
||||
'expanded_logging' => env('EXPANDED_LOGGING', false),
|
||||
'snappdf_chromium_path' => env('SNAPPDF_CHROMIUM_PATH', false),
|
||||
'snappdf_chromium_arguments' => env('SNAPPDF_CHROMIUM_ARGUMENTS', false),
|
||||
'v4_migration_version' => '4.5.35',
|
||||
'flutter_renderer' => env('FLUTTER_RENDERER', 'selfhosted-html'),
|
||||
'webcron_secret' => env('WEBCRON_SECRET', false),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class UpdateDesigns extends Migration
|
||||
{
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Gateway;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ActivatePayfastPaymentDriver extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Gateway::whereIn('id', [11])->update(['visible' => 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
2
public/css/app.css
vendored
2
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
4
public/flutter_service_worker.js
vendored
4
public/flutter_service_worker.js
vendored
|
|
@ -4,7 +4,7 @@ const TEMP = 'flutter-temp-cache';
|
|||
const CACHE_NAME = 'flutter-app-cache';
|
||||
const RESOURCES = {
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"main.dart.js": "ec0d23274ffa0ea4b6743fe88c16ccaa",
|
||||
"main.dart.js": "3b486fb6ff9ff8c688f498feb859535a",
|
||||
"/": "23224b5e03519aaa87594403d54412cf",
|
||||
"manifest.json": "ce1b79950eb917ea619a0a30da27c6a3",
|
||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
||||
|
|
@ -29,7 +29,7 @@ const RESOURCES = {
|
|||
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
|
||||
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
|
||||
"assets/AssetManifest.json": "7e49562f32e24a9e2557fe4178a84b79",
|
||||
"version.json": "4d10e2258012cbb88b24009334a24f24",
|
||||
"version.json": "d5a91f8fb6852f3ca9a9199e65eb6dbd",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628"
|
||||
|
|
|
|||
175643
public/main.dart.js
vendored
175643
public/main.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
176083
public/main.foss.dart.js
vendored
176083
public/main.foss.dart.js
vendored
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue