mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
commit
19cb845c41
@ -1 +1 @@
|
|||||||
5.3.61
|
5.3.62
|
@ -77,10 +77,10 @@ class BackupUpdate extends Command
|
|||||||
{
|
{
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
|
||||||
Backup::whereRaw('html_backup != "" OR html_backup IS NOT NULL')->chunk(5000, function ($backups) {
|
Backup::whereRaw('html_backup IS NOT NULL')->chunk(5000, function ($backups) {
|
||||||
foreach ($backups as $backup) {
|
foreach ($backups as $backup) {
|
||||||
|
|
||||||
if($backup->activity->client()->exists()){
|
if(strlen($backup->html_backup) > 1 && $backup->activity->client()->exists()){
|
||||||
|
|
||||||
$client = $backup->activity->client;
|
$client = $backup->activity->client;
|
||||||
$backup->storeRemotely($backup->html_backup, $client);
|
$backup->storeRemotely($backup->html_backup, $client);
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use App;
|
use App;
|
||||||
use App\Factory\ClientContactFactory;
|
use App\Factory\ClientContactFactory;
|
||||||
|
use App\Factory\VendorContactFactory;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
@ -27,6 +28,7 @@ use App\Models\Payment;
|
|||||||
use App\Models\Paymentable;
|
use App\Models\Paymentable;
|
||||||
use App\Models\QuoteInvitation;
|
use App\Models\QuoteInvitation;
|
||||||
use App\Models\RecurringInvoiceInvitation;
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
use App\Models\Vendor;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
@ -72,7 +74,7 @@ class CheckData extends Command
|
|||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=} {--paid_to_date=} {--client_balance=}';
|
protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
@ -112,6 +114,7 @@ class CheckData extends Command
|
|||||||
$this->checkClientBalances();
|
$this->checkClientBalances();
|
||||||
|
|
||||||
$this->checkContacts();
|
$this->checkContacts();
|
||||||
|
$this->checkVendorContacts();
|
||||||
$this->checkEntityInvitations();
|
$this->checkEntityInvitations();
|
||||||
$this->checkCompanyData();
|
$this->checkCompanyData();
|
||||||
|
|
||||||
@ -248,6 +251,68 @@ class CheckData extends Command
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkVendorContacts()
|
||||||
|
{
|
||||||
|
// check for contacts with the contact_key value set
|
||||||
|
$contacts = DB::table('vendor_contacts')
|
||||||
|
->whereNull('contact_key')
|
||||||
|
->orderBy('id')
|
||||||
|
->get(['id']);
|
||||||
|
$this->logMessage($contacts->count().' contacts without a contact_key');
|
||||||
|
|
||||||
|
if ($contacts->count() > 0) {
|
||||||
|
$this->isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->option('fix') == 'true') {
|
||||||
|
foreach ($contacts as $contact) {
|
||||||
|
DB::table('vendor_contacts')
|
||||||
|
->where('id', '=', $contact->id)
|
||||||
|
->whereNull('contact_key')
|
||||||
|
->update([
|
||||||
|
'contact_key' => Str::random(config('ninja.key_length')),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for missing contacts
|
||||||
|
$vendors = DB::table('vendors')
|
||||||
|
->leftJoin('vendor_contacts', function ($join) {
|
||||||
|
$join->on('vendor_contacts.vendor_id', '=', 'vendors.id')
|
||||||
|
->whereNull('vendor_contacts.deleted_at');
|
||||||
|
})
|
||||||
|
->groupBy('vendors.id', 'vendors.user_id', 'vendors.company_id')
|
||||||
|
->havingRaw('count(vendor_contacts.id) = 0');
|
||||||
|
|
||||||
|
if ($this->option('vendor_id')) {
|
||||||
|
$vendors->where('vendors.id', '=', $this->option('vendor_id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$vendors = $vendors->get(['vendors.id', 'vendors.user_id', 'vendors.company_id']);
|
||||||
|
$this->logMessage($vendors->count().' vendors without any contacts');
|
||||||
|
|
||||||
|
if ($vendors->count() > 0) {
|
||||||
|
$this->isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->option('fix') == 'true') {
|
||||||
|
|
||||||
|
$vendors = Vendor::withTrashed()->doesntHave('contacts')->get();
|
||||||
|
|
||||||
|
foreach ($vendors as $vendor) {
|
||||||
|
$this->logMessage("Fixing missing vendor contacts #{$vendor->id}");
|
||||||
|
|
||||||
|
$new_contact = VendorContactFactory::create($vendor->company_id, $vendor->user_id);
|
||||||
|
$new_contact->vendor_id = $vendor->id;
|
||||||
|
$new_contact->contact_key = Str::random(40);
|
||||||
|
$new_contact->is_primary = true;
|
||||||
|
$new_contact->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private function checkFailedJobs()
|
private function checkFailedJobs()
|
||||||
{
|
{
|
||||||
if (config('ninja.testvars.travis')) {
|
if (config('ninja.testvars.travis')) {
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use App\Events\Contact\ContactLoggedIn;
|
use App\Events\Contact\ContactLoggedIn;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\ViewComposers\PortalComposer;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
@ -20,10 +21,10 @@ use App\Models\Company;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Route;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Route;
|
||||||
|
|
||||||
class ContactLoginController extends Controller
|
class ContactLoginController extends Controller
|
||||||
{
|
{
|
||||||
@ -131,6 +132,8 @@ class ContactLoginController extends Controller
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setRedirectPath();
|
||||||
|
|
||||||
return $request->wantsJson()
|
return $request->wantsJson()
|
||||||
? new JsonResponse([], 204)
|
? new JsonResponse([], 204)
|
||||||
: redirect()->intended($this->redirectPath());
|
: redirect()->intended($this->redirectPath());
|
||||||
@ -156,4 +159,22 @@ class ContactLoginController extends Controller
|
|||||||
|
|
||||||
return redirect('/client/login');
|
return redirect('/client/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setRedirectPath()
|
||||||
|
{
|
||||||
|
|
||||||
|
if(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_INVOICES)
|
||||||
|
$this->redirectTo = '/client/invoices';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_RECURRING_INVOICES)
|
||||||
|
$this->redirectTo = '/client/recurring_invoices';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_QUOTES)
|
||||||
|
$this->redirectTo = '/client/quotes';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_CREDITS)
|
||||||
|
$this->redirectTo = '/client/credits';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_TASKS)
|
||||||
|
$this->redirectTo = '/client/tasks';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_EXPENSES)
|
||||||
|
$this->redirectTo = '/client/expenses';
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ class LoginController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function refresh(Request $request)
|
public function refresh(Request $request)
|
||||||
{
|
{
|
||||||
$company_token = CompanyToken::whereRaw('BINARY `token`= ?', [$request->header('X-API-TOKEN')])->first();
|
$company_token = CompanyToken::where('token', $request->header('X-API-TOKEN'))->first();
|
||||||
|
|
||||||
$cu = CompanyUser::query()
|
$cu = CompanyUser::query()
|
||||||
->where('user_id', $company_token->user_id);
|
->where('user_id', $company_token->user_id);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Http\Controllers\ClientPortal;
|
namespace App\Http\Controllers\ClientPortal;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\ViewComposers\PortalComposer;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use Auth;
|
use Auth;
|
||||||
|
|
||||||
@ -36,16 +37,36 @@ class ContactHashLoginController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect('/client/invoices');
|
return redirect($this->setRedirectPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function magicLink(string $magic_link)
|
public function magicLink(string $magic_link)
|
||||||
{
|
{
|
||||||
return redirect('/client/invoices');
|
|
||||||
|
return redirect($this->setRedirectPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function errorPage()
|
public function errorPage()
|
||||||
{
|
{
|
||||||
return render('generic.error', ['title' => session()->get('title'), 'notification' => session()->get('notification')]);
|
return render('generic.error', ['title' => session()->get('title'), 'notification' => session()->get('notification')]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setRedirectPath()
|
||||||
|
{
|
||||||
|
|
||||||
|
if(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_INVOICES)
|
||||||
|
return '/client/invoices';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_RECURRING_INVOICES)
|
||||||
|
return '/client/recurring_invoices';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_QUOTES)
|
||||||
|
return '/client/quotes';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_CREDITS)
|
||||||
|
return '/client/credits';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_TASKS)
|
||||||
|
return '/client/tasks';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_EXPENSES)
|
||||||
|
return '/client/expenses';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,10 +45,15 @@ class EntityViewController extends Controller
|
|||||||
|
|
||||||
$key = $entity_type.'_id';
|
$key = $entity_type.'_id';
|
||||||
|
|
||||||
$invitation = $invitation_entity::whereRaw('BINARY `key`= ?', [$invitation_key])
|
|
||||||
|
$invitation = $invitation_entity::where('key', $invitation_key)
|
||||||
->with('contact.client')
|
->with('contact.client')
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
|
|
||||||
|
// $invitation = $invitation_entity::whereRaw('BINARY `key`= ?', [$invitation_key])
|
||||||
|
// ->with('contact.client')
|
||||||
|
// ->firstOrFail();
|
||||||
|
|
||||||
$contact = $invitation->contact;
|
$contact = $invitation->contact;
|
||||||
$client = $contact->client;
|
$client = $contact->client;
|
||||||
$entity = $invitation->{$entity_type};
|
$entity = $invitation->{$entity_type};
|
||||||
@ -105,7 +110,8 @@ class EntityViewController extends Controller
|
|||||||
|
|
||||||
$key = $entity_type.'_id';
|
$key = $entity_type.'_id';
|
||||||
|
|
||||||
$invitation = $invitation_entity::whereRaw('BINARY `key`= ?', [$invitation_key])->firstOrFail();
|
$invitation = $invitation_entity::where('key', $invitation_key)->firstOrFail();
|
||||||
|
// $invitation = $invitation_entity::whereRaw('BINARY `key`= ?', [$invitation_key])->firstOrFail();
|
||||||
|
|
||||||
$contact = $invitation->contact;
|
$contact = $invitation->contact;
|
||||||
|
|
||||||
|
@ -19,8 +19,10 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Jobs\Entity\CreateRawPdf;
|
use App\Jobs\Entity\CreateRawPdf;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
use App\Services\ClientPortal\InstantPayment;
|
use App\Services\ClientPortal\InstantPayment;
|
||||||
use App\Utils\CurlUtils;
|
use App\Utils\CurlUtils;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
@ -179,10 +181,6 @@ class InvitationController extends Controller
|
|||||||
|
|
||||||
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
||||||
|
|
||||||
// $invitation = $entity_obj::whereRaw('BINARY `key`= ?', [$invitation_key])
|
|
||||||
// ->with('contact.client')
|
|
||||||
// ->firstOrFail();
|
|
||||||
|
|
||||||
$invitation = $entity_obj::where('key', $invitation_key)
|
$invitation = $entity_obj::where('key', $invitation_key)
|
||||||
->with('contact.client')
|
->with('contact.client')
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
@ -265,4 +263,26 @@ class InvitationController extends Controller
|
|||||||
|
|
||||||
abort(404, "Invoice not found");
|
abort(404, "Invoice not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function unsubscribe(Request $request, string $invitation_key)
|
||||||
|
{
|
||||||
|
if($invite = InvoiceInvitation::withTrashed()->where('key', $invitation_key)->first()){
|
||||||
|
$invite->contact->send_email = false;
|
||||||
|
$invite->contact->save();
|
||||||
|
}elseif($invite = QuoteInvitation::withTrashed()->where('key', $invitation_key)->first()){
|
||||||
|
$invite->contact->send_email = false;
|
||||||
|
$invite->contact->save();
|
||||||
|
}elseif($invite = CreditInvitation::withTrashed()->where('key', $invitation_key)->first()){
|
||||||
|
$invite->contact->send_email = false;
|
||||||
|
$invite->contact->save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return abort(404);
|
||||||
|
|
||||||
|
$data['logo'] = $invite->company->present()->logo();
|
||||||
|
|
||||||
|
return $this->render('generic.unsubscribe', $data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,15 +12,19 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\ClientPortal;
|
namespace App\Http\Controllers\ClientPortal;
|
||||||
|
|
||||||
|
use App\Factory\RecurringInvoiceFactory;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\ClientPortal\Uploads\StoreUploadRequest;
|
use App\Http\Requests\ClientPortal\Uploads\StoreUploadRequest;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Models\CompanyGateway;
|
||||||
|
use App\Models\GatewayType;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Models\Subscription;
|
use App\Models\Subscription;
|
||||||
|
use App\Repositories\SubscriptionRepository;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||||
@ -35,6 +39,7 @@ class NinjaPlanController extends Controller
|
|||||||
|
|
||||||
public function index(string $contact_key, string $account_or_company_key)
|
public function index(string $contact_key, string $account_or_company_key)
|
||||||
{
|
{
|
||||||
|
|
||||||
MultiDB::findAndSetDbByCompanyKey($account_or_company_key);
|
MultiDB::findAndSetDbByCompanyKey($account_or_company_key);
|
||||||
$company = Company::where('company_key', $account_or_company_key)->first();
|
$company = Company::where('company_key', $account_or_company_key)->first();
|
||||||
|
|
||||||
@ -67,8 +72,108 @@ class NinjaPlanController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function trial()
|
||||||
|
{
|
||||||
|
|
||||||
|
$gateway = CompanyGateway::where('gateway_key', 'd14dd26a37cecc30fdd65700bfb55b23')->first();
|
||||||
|
|
||||||
|
$data['gateway'] = $gateway;
|
||||||
|
|
||||||
|
$gateway_driver = $gateway->driver(auth()->guard('contact')->user()->client)->init();
|
||||||
|
|
||||||
|
$customer = $gateway_driver->findOrCreateCustomer();
|
||||||
|
|
||||||
|
$setupIntent = \Stripe\SetupIntent::create([
|
||||||
|
'payment_method_types' => ['card'],
|
||||||
|
'usage' => 'off_session',
|
||||||
|
'customer' => $customer->id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data['intent'] = $setupIntent;
|
||||||
|
// $data['account'] = $account;
|
||||||
|
$data['client'] = Auth::guard('contact')->user()->client;
|
||||||
|
|
||||||
|
return $this->render('plan.trial', $data);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function trial_confirmation(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$client = auth()->guard('contact')->user()->client;
|
||||||
|
$client->fill($request->all());
|
||||||
|
$client->save();
|
||||||
|
|
||||||
|
//store payment method
|
||||||
|
|
||||||
|
$gateway = CompanyGateway::where('gateway_key', 'd14dd26a37cecc30fdd65700bfb55b23')->first();
|
||||||
|
$gateway_driver = $gateway->driver(auth()->guard('contact')->user()->client)->init();
|
||||||
|
|
||||||
|
$stripe_response = json_decode($request->input('gateway_response'));
|
||||||
|
$customer = $gateway_driver->findOrCreateCustomer();
|
||||||
|
|
||||||
|
$gateway_driver->attach($stripe_response->payment_method, $customer);
|
||||||
|
$method = $gateway_driver->getStripePaymentMethod($stripe_response->payment_method);
|
||||||
|
|
||||||
|
$payment_meta = new \stdClass;
|
||||||
|
$payment_meta->exp_month = (string) $method->card->exp_month;
|
||||||
|
$payment_meta->exp_year = (string) $method->card->exp_year;
|
||||||
|
$payment_meta->brand = (string) $method->card->brand;
|
||||||
|
$payment_meta->last4 = (string) $method->card->last4;
|
||||||
|
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'payment_meta' => $payment_meta,
|
||||||
|
'token' => $method->id,
|
||||||
|
'payment_method_id' => GatewayType::CREDIT_CARD,
|
||||||
|
];
|
||||||
|
|
||||||
|
$gateway_driver->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]);
|
||||||
|
|
||||||
|
//set free trial
|
||||||
|
$account = auth()->guard('contact')->user()->company->account;
|
||||||
|
$account->trial_started = now();
|
||||||
|
$account->trial_plan = 'pro';
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
//create recurring invoice
|
||||||
|
$subscription_repo = new SubscriptionRepository();
|
||||||
|
$subscription = Subscription::find(6);
|
||||||
|
|
||||||
|
$recurring_invoice = RecurringInvoiceFactory::create($subscription->company_id, $subscription->user_id);
|
||||||
|
$recurring_invoice->client_id = $client->id;
|
||||||
|
$recurring_invoice->line_items = $subscription_repo->generateLineItems($subscription, true, false);
|
||||||
|
$recurring_invoice->subscription_id = $subscription->id;
|
||||||
|
$recurring_invoice->frequency_id = $subscription->frequency_id ?: RecurringInvoice::FREQUENCY_MONTHLY;
|
||||||
|
$recurring_invoice->date = now()->addDays(14);
|
||||||
|
$recurring_invoice->remaining_cycles = -1;
|
||||||
|
$recurring_invoice->auto_bill = $client->getSetting('auto_bill');
|
||||||
|
$recurring_invoice->auto_bill_enabled = $this->setAutoBillFlag($recurring_invoice->auto_bill);
|
||||||
|
$recurring_invoice->due_date_days = 'terms';
|
||||||
|
$recurring_invoice->next_send_date = now()->addDays(14)->format('Y-m-d');
|
||||||
|
|
||||||
|
$recurring_invoice->save();
|
||||||
|
$recurring_invoice->service()->start();
|
||||||
|
|
||||||
|
return redirect('/');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function setAutoBillFlag($auto_bill)
|
||||||
|
{
|
||||||
|
if ($auto_bill == 'always' || $auto_bill == 'optout') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function plan()
|
public function plan()
|
||||||
{
|
{
|
||||||
|
|
||||||
//harvest the current plan
|
//harvest the current plan
|
||||||
$data = [];
|
$data = [];
|
||||||
$data['late_invoice'] = false;
|
$data['late_invoice'] = false;
|
||||||
@ -79,6 +184,9 @@ class NinjaPlanController extends Controller
|
|||||||
|
|
||||||
if($account)
|
if($account)
|
||||||
{
|
{
|
||||||
|
//offer the option to have a free trial
|
||||||
|
if(!$account->trial_started)
|
||||||
|
return $this->trial();
|
||||||
|
|
||||||
if(Carbon::parse($account->plan_expires)->lt(now())){
|
if(Carbon::parse($account->plan_expires)->lt(now())){
|
||||||
//expired get the most recent invoice for payment
|
//expired get the most recent invoice for payment
|
||||||
|
@ -114,7 +114,7 @@ class PaymentController extends Controller
|
|||||||
public function credit_response(Request $request)
|
public function credit_response(Request $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->first();
|
$payment_hash = PaymentHash::where('hash', $request->input('payment_hash'))->first();
|
||||||
|
|
||||||
/* Hydrate the $payment */
|
/* Hydrate the $payment */
|
||||||
if ($payment_hash->payment()->exists()) {
|
if ($payment_hash->payment()->exists()) {
|
||||||
|
@ -112,7 +112,8 @@ class StripeConnectController extends BaseController
|
|||||||
"livemode" => $response->livemode,
|
"livemode" => $response->livemode,
|
||||||
"stripe_user_id" => $response->stripe_user_id,
|
"stripe_user_id" => $response->stripe_user_id,
|
||||||
"refresh_token" => $response->refresh_token,
|
"refresh_token" => $response->refresh_token,
|
||||||
"access_token" => $response->access_token
|
"access_token" => $response->access_token,
|
||||||
|
"appleDomainVerification" => '',
|
||||||
];
|
];
|
||||||
|
|
||||||
$company_gateway->setConfig($payload);
|
$company_gateway->setConfig($payload);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Http\ViewComposers\PortalComposer;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
@ -59,7 +60,7 @@ class ContactKeyLogin
|
|||||||
return redirect()->to($request->query('redirect'));
|
return redirect()->to($request->query('redirect'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to('client/dashboard');
|
return redirect($this->setRedirectPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif ($request->segment(3) && config('ninja.db.multi_db_enabled')) {
|
elseif ($request->segment(3) && config('ninja.db.multi_db_enabled')) {
|
||||||
@ -77,8 +78,8 @@ class ContactKeyLogin
|
|||||||
return redirect()->to($request->query('next'));
|
return redirect()->to($request->query('next'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to('client/dashboard');
|
return redirect($this->setRedirectPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} elseif ($request->segment(2) && $request->segment(2) == 'key_login' && $request->segment(3)) {
|
} elseif ($request->segment(2) && $request->segment(2) == 'key_login' && $request->segment(3)) {
|
||||||
@ -93,7 +94,7 @@ class ContactKeyLogin
|
|||||||
return redirect($request->query('next'));
|
return redirect($request->query('next'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to('client/dashboard');
|
return redirect($this->setRedirectPath());
|
||||||
}
|
}
|
||||||
} elseif ($request->has('client_hash') && config('ninja.db.multi_db_enabled')) {
|
} elseif ($request->has('client_hash') && config('ninja.db.multi_db_enabled')) {
|
||||||
if (MultiDB::findAndSetDbByClientHash($request->input('client_hash'))) {
|
if (MultiDB::findAndSetDbByClientHash($request->input('client_hash'))) {
|
||||||
@ -106,7 +107,7 @@ class ContactKeyLogin
|
|||||||
$primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save();
|
$primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save();
|
||||||
|
|
||||||
auth()->guard('contact')->loginUsingId($primary_contact->id, true);
|
auth()->guard('contact')->loginUsingId($primary_contact->id, true);
|
||||||
return redirect()->to('client/dashboard');
|
return redirect($this->setRedirectPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($request->has('client_hash')) {
|
} elseif ($request->has('client_hash')) {
|
||||||
@ -119,10 +120,28 @@ class ContactKeyLogin
|
|||||||
|
|
||||||
auth()->guard('contact')->loginUsingId($primary_contact->id, true);
|
auth()->guard('contact')->loginUsingId($primary_contact->id, true);
|
||||||
|
|
||||||
return redirect()->to('client/dashboard');
|
return redirect($this->setRedirectPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setRedirectPath()
|
||||||
|
{
|
||||||
|
|
||||||
|
if(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_INVOICES)
|
||||||
|
return '/client/invoices';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_RECURRING_INVOICES)
|
||||||
|
return '/client/recurring_invoices';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_QUOTES)
|
||||||
|
return '/client/quotes';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_CREDITS)
|
||||||
|
return '/client/credits';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_TASKS)
|
||||||
|
return '/client/tasks';
|
||||||
|
elseif(auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_EXPENSES)
|
||||||
|
return '/client/expenses';
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ class ContactTokenAuth
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
if ($request->header('X-API-TOKEN') && ($client_contact = ClientContact::with(['company'])->whereRaw('BINARY `token`= ?', [$request->header('X-API-TOKEN')])->first())) {
|
if ($request->header('X-API-TOKEN') && ($client_contact = ClientContact::with(['company'])->where('token', $request->header('X-API-TOKEN'))->first())) {
|
||||||
$error = [
|
$error = [
|
||||||
'message' => 'Authentication disabled for user.',
|
'message' => 'Authentication disabled for user.',
|
||||||
'errors' => new stdClass,
|
'errors' => new stdClass,
|
||||||
|
@ -30,7 +30,7 @@ class TokenAuth
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
if ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with(['user', 'company'])->whereRaw('BINARY `token`= ?', [$request->header('X-API-TOKEN')])->first())) {
|
if ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with(['user', 'company'])->where('token', $request->header('X-API-TOKEN'))->first())) {
|
||||||
$user = $company_token->user;
|
$user = $company_token->user;
|
||||||
|
|
||||||
$error = [
|
$error = [
|
||||||
|
@ -34,7 +34,7 @@ class PaymentResponseRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
return PaymentHash::whereRaw('BINARY `hash`= ?', [$input['payment_hash']])->first();
|
return PaymentHash::where('hash', $input['payment_hash'])->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shouldStoreToken(): bool
|
public function shouldStoreToken(): bool
|
||||||
|
@ -29,7 +29,7 @@ class StoreTaxRateRequest extends Request
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
//'name' => 'required',
|
//'name' => 'required',
|
||||||
'name' => 'required|unique:tax_rates,name,null,null,company_id,'.auth()->user()->companyId(),
|
'name' => 'required|unique:tax_rates,name,null,null,company_id,'.auth()->user()->companyId().',deleted_at,NULL',
|
||||||
'rate' => 'required|numeric',
|
'rate' => 'required|numeric',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -78,10 +78,10 @@ class PaymentAmountsBalanceRule implements Rule
|
|||||||
// nlog(request()->input('invoices'));
|
// nlog(request()->input('invoices'));
|
||||||
// nlog($payment_amounts);
|
// nlog($payment_amounts);
|
||||||
// nlog($invoice_amounts);
|
// nlog($invoice_amounts);
|
||||||
|
// nlog(request()->all());
|
||||||
nlog($payment_amounts ." >= " . $invoice_amounts);
|
nlog($payment_amounts ." >= " . $invoice_amounts);
|
||||||
|
|
||||||
return $payment_amounts >= $invoice_amounts;
|
return round($payment_amounts,2) >= round($invoice_amounts,2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +84,8 @@ class CreateAccount
|
|||||||
{
|
{
|
||||||
$sp794f3f->hosted_client_count = config('ninja.quotas.free.clients');
|
$sp794f3f->hosted_client_count = config('ninja.quotas.free.clients');
|
||||||
$sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies');
|
$sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies');
|
||||||
$sp794f3f->trial_started = now();
|
// $sp794f3f->trial_started = now();
|
||||||
$sp794f3f->trial_plan = 'pro';
|
// $sp794f3f->trial_plan = 'pro';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sp794f3f->save();
|
$sp794f3f->save();
|
||||||
|
@ -168,10 +168,10 @@ class CreateEntityPdf implements ShouldQueue
|
|||||||
]),
|
]),
|
||||||
'variables' => $variables,
|
'variables' => $variables,
|
||||||
'options' => [
|
'options' => [
|
||||||
'all_pages_header' => $this->client->getSetting('all_pages_header'),
|
'all_pages_header' => $this->entity->client->getSetting('all_pages_header'),
|
||||||
'all_pages_footer' => $this->client->getSetting('all_pages_footer'),
|
'all_pages_footer' => $this->entity->client->getSetting('all_pages_footer'),
|
||||||
],
|
],
|
||||||
'process_markdown' => $this->client->company->markdown_enabled,
|
'process_markdown' => $this->entity->client->company->markdown_enabled,
|
||||||
];
|
];
|
||||||
|
|
||||||
$maker = new PdfMakerService($state);
|
$maker = new PdfMakerService($state);
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace App\Jobs\Import;
|
namespace App\Jobs\Import;
|
||||||
|
|
||||||
|
use App\Factory\ClientContactFactory;
|
||||||
|
use App\Factory\VendorContactFactory;
|
||||||
use App\Import\Providers\Csv;
|
use App\Import\Providers\Csv;
|
||||||
use App\Import\Providers\Freshbooks;
|
use App\Import\Providers\Freshbooks;
|
||||||
use App\Import\Providers\Invoice2Go;
|
use App\Import\Providers\Invoice2Go;
|
||||||
@ -18,12 +20,15 @@ use App\Import\Providers\Invoicely;
|
|||||||
use App\Import\Providers\Wave;
|
use App\Import\Providers\Wave;
|
||||||
use App\Import\Providers\Zoho;
|
use App\Import\Providers\Zoho;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Models\Vendor;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class CSVIngest implements ShouldQueue {
|
class CSVIngest implements ShouldQueue {
|
||||||
|
|
||||||
@ -70,6 +75,33 @@ class CSVIngest implements ShouldQueue {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->checkContacts();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkContacts()
|
||||||
|
{
|
||||||
|
$vendors = Vendor::withTrashed()->where('company_id', $this->company->id)->doesntHave('contacts')->get();
|
||||||
|
|
||||||
|
foreach ($vendors as $vendor) {
|
||||||
|
|
||||||
|
$new_contact = VendorContactFactory::create($vendor->company_id, $vendor->user_id);
|
||||||
|
$new_contact->vendor_id = $vendor->id;
|
||||||
|
$new_contact->contact_key = Str::random(40);
|
||||||
|
$new_contact->is_primary = true;
|
||||||
|
$new_contact->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$clients = Client::withTrashed()->where('company_id', $this->company->id)->doesntHave('contacts')->get();
|
||||||
|
|
||||||
|
foreach ($clients as $client) {
|
||||||
|
|
||||||
|
$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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function bootEngine(string $import_type)
|
private function bootEngine(string $import_type)
|
||||||
|
@ -374,6 +374,9 @@ class Import implements ShouldQueue
|
|||||||
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$data['email_sending_method'] = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
$rules = (new UpdateCompanyRequest())->rules();
|
$rules = (new UpdateCompanyRequest())->rules();
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ class MultiDB
|
|||||||
$current_db = config('database.default');
|
$current_db = config('database.default');
|
||||||
|
|
||||||
foreach (self::$dbs as $db) {
|
foreach (self::$dbs as $db) {
|
||||||
if (ClientContact::on($db)->whereRaw('BINARY `token`= ?', [$token])->exists()) {
|
if (ClientContact::on($db)->where('token', $token)->exists()) {
|
||||||
self::setDb($db);
|
self::setDb($db);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ class MultiDB
|
|||||||
$current_db = config('database.default');
|
$current_db = config('database.default');
|
||||||
|
|
||||||
foreach (self::$dbs as $db) {
|
foreach (self::$dbs as $db) {
|
||||||
if (CompanyToken::on($db)->whereRaw('BINARY `token`= ?', [$token])->exists()) {
|
if (CompanyToken::on($db)->where('token', $token)->exists()) {
|
||||||
self::setDb($db);
|
self::setDb($db);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,7 @@ class TemplateEmail extends Mailable
|
|||||||
'footer' => $this->build_email->getFooter(),
|
'footer' => $this->build_email->getFooter(),
|
||||||
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
|
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
|
'unsubscribe_link' => $this->invitation ? $this->invitation->getUnsubscribeLink() : '',
|
||||||
])
|
])
|
||||||
->view($template_name, [
|
->view($template_name, [
|
||||||
'greeting' => ctrans('texts.email_salutation', ['name' => $this->contact->present()->name()]),
|
'greeting' => ctrans('texts.email_salutation', ['name' => $this->contact->present()->name()]),
|
||||||
@ -110,6 +111,7 @@ class TemplateEmail extends Mailable
|
|||||||
'company' => $company,
|
'company' => $company,
|
||||||
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
|
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
|
||||||
'logo' => $this->company->present()->logo($settings),
|
'logo' => $this->company->present()->logo($settings),
|
||||||
|
'unsubscribe_link' => $this->invitation->getUnsubscribeLink(),
|
||||||
])
|
])
|
||||||
->withSwiftMessage(function ($message) use($company){
|
->withSwiftMessage(function ($message) use($company){
|
||||||
$message->getHeaders()->addTextHeader('Tag', $company->company_key);
|
$message->getHeaders()->addTextHeader('Tag', $company->company_key);
|
||||||
|
@ -149,6 +149,7 @@ class Gateway extends StaticModel
|
|||||||
GatewayType::BECS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']],
|
GatewayType::BECS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']],
|
||||||
GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']],
|
GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']],
|
||||||
GatewayType::ACSS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']],
|
GatewayType::ACSS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']],
|
||||||
|
GatewayType::FPX => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
case 57:
|
case 57:
|
||||||
|
@ -177,7 +177,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
|
|
||||||
}
|
}
|
||||||
elseif (request()->header('X-API-TOKEN')) {
|
elseif (request()->header('X-API-TOKEN')) {
|
||||||
$company_token = CompanyToken::with(['company'])->whereRaw('BINARY `token`= ?', [request()->header('X-API-TOKEN')])->first();
|
$company_token = CompanyToken::with(['company'])->where('token', request()->header('X-API-TOKEN'))->first();
|
||||||
|
|
||||||
return $company_token->company;
|
return $company_token->company;
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ class AuthorizeCreditCard
|
|||||||
|
|
||||||
private function processSuccessfulResponse($data, $request)
|
private function processSuccessfulResponse($data, $request)
|
||||||
{
|
{
|
||||||
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
|
$payment_hash = PaymentHash::where('hash', $request->input('payment_hash'))->firstOrFail();
|
||||||
$payment = $this->storePayment($payment_hash, $data);
|
$payment = $this->storePayment($payment_hash, $data);
|
||||||
|
|
||||||
$vars = [
|
$vars = [
|
||||||
|
@ -224,7 +224,7 @@ class PayFastPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$data['m_payment_id']])->first();
|
$payment_hash = PaymentHash::where('hash', $data['m_payment_id'])->first();
|
||||||
|
|
||||||
$this->setPaymentMethod(GatewayType::CREDIT_CARD)
|
$this->setPaymentMethod(GatewayType::CREDIT_CARD)
|
||||||
->setPaymentHash($payment_hash)
|
->setPaymentHash($payment_hash)
|
||||||
|
@ -47,7 +47,7 @@ class SEPA
|
|||||||
$data['country'] = $this->stripe->client->country->iso_3166_2;
|
$data['country'] = $this->stripe->client->country->iso_3166_2;
|
||||||
$data['payment_hash'] = $this->stripe->payment_hash->hash;
|
$data['payment_hash'] = $this->stripe->payment_hash->hash;
|
||||||
|
|
||||||
$intent = \Stripe\PaymentIntent::create([
|
$intent_data = [
|
||||||
'amount' => $data['stripe_amount'],
|
'amount' => $data['stripe_amount'],
|
||||||
'currency' => 'eur',
|
'currency' => 'eur',
|
||||||
'payment_method_types' => ['sepa_debit'],
|
'payment_method_types' => ['sepa_debit'],
|
||||||
@ -58,19 +58,12 @@ class SEPA
|
|||||||
'payment_hash' => $this->stripe->payment_hash->hash,
|
'payment_hash' => $this->stripe->payment_hash->hash,
|
||||||
'gateway_type_id' => GatewayType::SEPA,
|
'gateway_type_id' => GatewayType::SEPA,
|
||||||
],
|
],
|
||||||
], $this->stripe->stripe_connect_auth);
|
];
|
||||||
|
|
||||||
|
$intent = \Stripe\PaymentIntent::create($intent_data, $this->stripe->stripe_connect_auth);
|
||||||
|
|
||||||
$data['pi_client_secret'] = $intent->client_secret;
|
$data['pi_client_secret'] = $intent->client_secret;
|
||||||
|
|
||||||
if (count($data['tokens']) > 0) {
|
|
||||||
$setup_intent = $this->stripe->stripe->setupIntents->create([
|
|
||||||
'payment_method_types' => ['sepa_debit'],
|
|
||||||
'customer' => $this->stripe->findOrCreateCustomer()->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$data['si_client_secret'] = $setup_intent->client_secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
|
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
|
||||||
$this->stripe->payment_hash->save();
|
$this->stripe->payment_hash->save();
|
||||||
|
|
||||||
|
@ -321,7 +321,6 @@ https://developer.wepay.com/api/api-calls/checkout
|
|||||||
|
|
||||||
$amount = array_sum(array_column($this->wepay_payment_driver->payment_hash->invoices(), 'amount')) + $this->wepay_payment_driver->payment_hash->fee_total;
|
$amount = array_sum(array_column($this->wepay_payment_driver->payment_hash->invoices(), 'amount')) + $this->wepay_payment_driver->payment_hash->fee_total;
|
||||||
|
|
||||||
|
|
||||||
$app_fee = (config('ninja.wepay.fee_cc_multiplier') * $amount) + config('ninja.wepay.fee_fixed');
|
$app_fee = (config('ninja.wepay.fee_cc_multiplier') * $amount) + config('ninja.wepay.fee_fixed');
|
||||||
// charge the credit card
|
// charge the credit card
|
||||||
$response = $this->wepay_payment_driver->wepay->request('checkout/create', array(
|
$response = $this->wepay_payment_driver->wepay->request('checkout/create', array(
|
||||||
|
@ -142,7 +142,7 @@ class BaseRepository
|
|||||||
|
|
||||||
$invitation_class = sprintf('App\\Models\\%sInvitation', $resource);
|
$invitation_class = sprintf('App\\Models\\%sInvitation', $resource);
|
||||||
|
|
||||||
$invitation = $invitation_class::whereRaw('BINARY `key`= ?', [$invitation['key']])->first();
|
$invitation = $invitation_class::where('key', $invitation['key'])->first();
|
||||||
|
|
||||||
return $invitation;
|
return $invitation;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,6 @@ class CreditRepository extends BaseRepository
|
|||||||
|
|
||||||
public function getInvitationByKey($key) :?CreditInvitation
|
public function getInvitationByKey($key) :?CreditInvitation
|
||||||
{
|
{
|
||||||
return CreditInvitation::whereRaw('BINARY `key`= ?', [$key])->first();
|
return CreditInvitation::where('key', $key)->first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
|
|
||||||
public function getInvitationByKey($key) :?InvoiceInvitation
|
public function getInvitationByKey($key) :?InvoiceInvitation
|
||||||
{
|
{
|
||||||
return InvoiceInvitation::whereRaw('BINARY `key`= ?', [$key])->first();
|
return InvoiceInvitation::where('key', $key)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +68,7 @@ class PaymentRepository extends BaseRepository {
|
|||||||
{
|
{
|
||||||
|
|
||||||
$is_existing_payment = true;
|
$is_existing_payment = true;
|
||||||
|
$client = false;
|
||||||
|
|
||||||
//check currencies here and fill the exchange rate data if necessary
|
//check currencies here and fill the exchange rate data if necessary
|
||||||
if (! $payment->id) {
|
if (! $payment->id) {
|
||||||
@ -107,6 +108,10 @@ class PaymentRepository extends BaseRepository {
|
|||||||
$payment->is_manual = true;
|
$payment->is_manual = true;
|
||||||
$payment->status_id = Payment::STATUS_COMPLETED;
|
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||||
|
|
||||||
|
if (! $payment->currency_id && $client) {
|
||||||
|
$payment->currency_id = $client->company->settings->currency_id;
|
||||||
|
}
|
||||||
|
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
|
||||||
/*Save documents*/
|
/*Save documents*/
|
||||||
|
@ -26,6 +26,6 @@ class QuoteRepository extends BaseRepository
|
|||||||
|
|
||||||
public function getInvitationByKey($key) :?QuoteInvitation
|
public function getInvitationByKey($key) :?QuoteInvitation
|
||||||
{
|
{
|
||||||
return QuoteInvitation::whereRaw('BINARY `key`= ?', [$key])->first();
|
return QuoteInvitation::where('key', $key)->first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,6 @@ class RecurringInvoiceRepository extends BaseRepository
|
|||||||
|
|
||||||
public function getInvitationByKey($key) :?RecurringInvoiceInvitation
|
public function getInvitationByKey($key) :?RecurringInvoiceInvitation
|
||||||
{
|
{
|
||||||
return RecurringInvoiceInvitation::whereRaw('BINARY `key`= ?', [$key])->first();
|
return RecurringInvoiceInvitation::where('key', $key)->first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ class UserTransformer extends EntityTransformer
|
|||||||
public function includeCompanyUser(User $user)
|
public function includeCompanyUser(User $user)
|
||||||
{
|
{
|
||||||
if (!$user->company_id && request()->header('X-API-TOKEN')) {
|
if (!$user->company_id && request()->header('X-API-TOKEN')) {
|
||||||
$company_token = CompanyToken::whereRaw('BINARY `token`= ?', [request()->header('X-API-TOKEN')])->first();
|
$company_token = CompanyToken::where('token', request()->header('X-API-TOKEN'))->first();
|
||||||
$user->company_id = $company_token->company_id;
|
$user->company_id = $company_token->company_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,9 +263,7 @@ class Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
|
|
||||||
// $x = str_replace(["\n", "<br>"], ["\r", "<br>"], $value);
|
// $x = str_replace(["\n", "<br>"], ["\r", "<br>"], $value);
|
||||||
|
|
||||||
// return $x;
|
// return $x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@ class Number
|
|||||||
$decimal = $currency->decimal_separator;
|
$decimal = $currency->decimal_separator;
|
||||||
$precision = $currency->precision;
|
$precision = $currency->precision;
|
||||||
|
|
||||||
|
$precision = 10;
|
||||||
|
|
||||||
return rtrim(rtrim(number_format($value, $precision, $decimal, $thousand), "0"),$decimal);
|
return rtrim(rtrim(number_format($value, $precision, $decimal, $thousand), "0"),$decimal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ class Phantom
|
|||||||
$key = $entity.'_id';
|
$key = $entity.'_id';
|
||||||
|
|
||||||
$invitation_instance = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
$invitation_instance = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
||||||
$invitation = $invitation_instance::whereRaw('BINARY `key`= ?', [$invitation_key])->first();
|
$invitation = $invitation_instance::where('key', $invitation_key)->first();
|
||||||
|
|
||||||
$entity_obj = $invitation->{$entity};
|
$entity_obj = $invitation->{$entity};
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ class TemplateEngine
|
|||||||
if (strlen($this->entity) > 1 && strlen($this->entity_id) > 1) {
|
if (strlen($this->entity) > 1 && strlen($this->entity_id) > 1) {
|
||||||
$class = 'App\Models\\'.ucfirst($this->entity);
|
$class = 'App\Models\\'.ucfirst($this->entity);
|
||||||
$this->entity_obj = $class::withTrashed()->where('id', $this->decodePrimaryKey($this->entity_id))->company()->first();
|
$this->entity_obj = $class::withTrashed()->where('id', $this->decodePrimaryKey($this->entity_id))->company()->first();
|
||||||
|
nlog("the entity id = ".$this->entity_obj->id);
|
||||||
} else {
|
} else {
|
||||||
$this->mockEntity();
|
$this->mockEntity();
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,18 @@ trait Inviteable
|
|||||||
return $domain.'/client/pay/'.$this->key;
|
return $domain.'/client/pay/'.$this->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUnsubscribeLink()
|
||||||
|
{
|
||||||
|
if(Ninja::isHosted()){
|
||||||
|
$domain = $this->company->domain();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$domain = config('ninja.app_url');
|
||||||
|
|
||||||
|
return $domain.'/client/unsubscribe/'.$this->key;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function getLink() :string
|
public function getLink() :string
|
||||||
{
|
{
|
||||||
$entity_type = Str::snake(class_basename($this->entityType()));
|
$entity_type = Str::snake(class_basename($this->entityType()));
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
|
"afosto/yaac": "^1.4",
|
||||||
"asm/php-ansible": "dev-main",
|
"asm/php-ansible": "dev-main",
|
||||||
"authorizenet/authorizenet": "^2.0",
|
"authorizenet/authorizenet": "^2.0",
|
||||||
"bacon/bacon-qr-code": "^2.0",
|
"bacon/bacon-qr-code": "^2.0",
|
||||||
|
181
composer.lock
generated
181
composer.lock
generated
@ -4,8 +4,60 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "ebb191c91f4011a448605a0fd725faff",
|
"content-hash": "3071902abd0fe82991f6409ab7f5b4c0",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "afosto/yaac",
|
||||||
|
"version": "v1.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/afosto/yaac.git",
|
||||||
|
"reference": "ef131cfe9e6dc627968f2847a5a726e961a21cd3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/afosto/yaac/zipball/ef131cfe9e6dc627968f2847a5a726e961a21cd3",
|
||||||
|
"reference": "ef131cfe9e6dc627968f2847a5a726e961a21cd3",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"guzzlehttp/guzzle": "^6.3|^7.0",
|
||||||
|
"league/flysystem": "^1.0|^3.0"
|
||||||
|
},
|
||||||
|
"type": "package",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Afosto\\Acme\\": "./src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Afosto Team",
|
||||||
|
"homepage": "https://afosto.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Yet Another ACME client: a decoupled LetsEncrypt client",
|
||||||
|
"homepage": "https://afosto.com",
|
||||||
|
"keywords": [
|
||||||
|
"ACME",
|
||||||
|
"acmev2",
|
||||||
|
"afosto",
|
||||||
|
"encrypt",
|
||||||
|
"lets",
|
||||||
|
"v2"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/afosto/yaac/issues",
|
||||||
|
"source": "https://github.com/afosto/yaac/tree/v1.4.0"
|
||||||
|
},
|
||||||
|
"time": "2022-02-18T15:18:06+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "apimatic/jsonmapper",
|
"name": "apimatic/jsonmapper",
|
||||||
"version": "v2.0.3",
|
"version": "v2.0.3",
|
||||||
@ -5120,71 +5172,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2022-01-21T13:39:10+00:00"
|
"time": "2022-01-21T13:39:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "maennchen/zipstream-php",
|
|
||||||
"version": "1.2.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/maennchen/ZipStream-PHP.git",
|
|
||||||
"reference": "6373eefe0b3274d7b702d81f2c99aa977ff97dc2"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/6373eefe0b3274d7b702d81f2c99aa977ff97dc2",
|
|
||||||
"reference": "6373eefe0b3274d7b702d81f2c99aa977ff97dc2",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"myclabs/php-enum": "^1.5",
|
|
||||||
"php": ">= 7.1",
|
|
||||||
"psr/http-message": "^1.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"ext-zip": "*",
|
|
||||||
"guzzlehttp/guzzle": ">= 6.3",
|
|
||||||
"mikey179/vfsstream": "^1.6",
|
|
||||||
"phpunit/phpunit": ">= 7.5"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"ZipStream\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Paul Duncan",
|
|
||||||
"email": "pabs@pablotron.org"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jesse Donat",
|
|
||||||
"email": "donatj@gmail.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jonatan Männchen",
|
|
||||||
"email": "jonatan@maennchen.ch"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "András Kolesár",
|
|
||||||
"email": "kolesar@kolesar.hu"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
|
|
||||||
"keywords": [
|
|
||||||
"stream",
|
|
||||||
"zip"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
|
|
||||||
"source": "https://github.com/maennchen/ZipStream-PHP/tree/master"
|
|
||||||
},
|
|
||||||
"time": "2019-07-17T11:01:58+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "mollie/mollie-api-php",
|
"name": "mollie/mollie-api-php",
|
||||||
"version": "v2.40.1",
|
"version": "v2.40.1",
|
||||||
@ -5522,66 +5509,6 @@
|
|||||||
},
|
},
|
||||||
"time": "2021-06-14T00:11:39+00:00"
|
"time": "2021-06-14T00:11:39+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "myclabs/php-enum",
|
|
||||||
"version": "1.8.3",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/myclabs/php-enum.git",
|
|
||||||
"reference": "b942d263c641ddb5190929ff840c68f78713e937"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/b942d263c641ddb5190929ff840c68f78713e937",
|
|
||||||
"reference": "b942d263c641ddb5190929ff840c68f78713e937",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-json": "*",
|
|
||||||
"php": "^7.3 || ^8.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "^9.5",
|
|
||||||
"squizlabs/php_codesniffer": "1.*",
|
|
||||||
"vimeo/psalm": "^4.6.2"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"MyCLabs\\Enum\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "PHP Enum contributors",
|
|
||||||
"homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PHP Enum implementation",
|
|
||||||
"homepage": "http://github.com/myclabs/php-enum",
|
|
||||||
"keywords": [
|
|
||||||
"enum"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/myclabs/php-enum/issues",
|
|
||||||
"source": "https://github.com/myclabs/php-enum/tree/1.8.3"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://github.com/mnapoli",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2021-07-05T08:18:36+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "nelexa/zip",
|
"name": "nelexa/zip",
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
@ -15724,5 +15651,5 @@
|
|||||||
"platform-dev": {
|
"platform-dev": {
|
||||||
"php": "^7.3|^7.4|^8.0"
|
"php": "^7.3|^7.4|^8.0"
|
||||||
},
|
},
|
||||||
"plugin-api-version": "2.0.0"
|
"plugin-api-version": "2.1.0"
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ return [
|
|||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||||
'app_version' => '5.3.61',
|
'app_version' => '5.3.62',
|
||||||
'app_tag' => '5.3.61',
|
'app_tag' => '5.3.62',
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', ''),
|
'api_secret' => env('API_SECRET', ''),
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\CompanyGateway;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class UpdateStripeAppleDomainConfig extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
|
||||||
|
CompanyGateway::whereIn('gateway_key', ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'])->cursor()->each(function($cg){
|
||||||
|
|
||||||
|
$config = $cg->getConfig();
|
||||||
|
|
||||||
|
if(!property_exists($config, 'appleDomainVerification')){
|
||||||
|
|
||||||
|
$config->appleDomainVerification = "";
|
||||||
|
$cg->setConfig($config);
|
||||||
|
$cg->save();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,10 @@ CREATE TABLE `accounts` (
|
|||||||
`is_onboarding` tinyint(1) NOT NULL DEFAULT '0',
|
`is_onboarding` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
`onboarding` mediumtext COLLATE utf8mb4_unicode_ci,
|
`onboarding` mediumtext COLLATE utf8mb4_unicode_ci,
|
||||||
`is_migrated` tinyint(1) NOT NULL DEFAULT '0',
|
`is_migrated` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`platform` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||||
|
`hosted_client_count` int(10) unsigned DEFAULT NULL,
|
||||||
|
`hosted_company_count` int(10) unsigned DEFAULT NULL,
|
||||||
|
`inapp_transaction_id` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `accounts_payment_id_index` (`payment_id`)
|
KEY `accounts_payment_id_index` (`payment_id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
|
||||||
@ -385,6 +389,7 @@ CREATE TABLE `companies` (
|
|||||||
`use_comma_as_decimal_place` tinyint(1) NOT NULL DEFAULT '0',
|
`use_comma_as_decimal_place` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
`report_include_drafts` tinyint(1) NOT NULL DEFAULT '0',
|
`report_include_drafts` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
`client_registration_fields` mediumtext COLLATE utf8mb4_unicode_ci,
|
`client_registration_fields` mediumtext COLLATE utf8mb4_unicode_ci,
|
||||||
|
`convert_rate_to_client` tinyint(1) NOT NULL DEFAULT '1',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `companies_company_key_unique` (`company_key`),
|
UNIQUE KEY `companies_company_key_unique` (`company_key`),
|
||||||
KEY `companies_industry_id_foreign` (`industry_id`),
|
KEY `companies_industry_id_foreign` (`industry_id`),
|
||||||
@ -2116,3 +2121,12 @@ INSERT INTO `migrations` VALUES (113,'2021_11_08_131308_onboarding',6);
|
|||||||
INSERT INTO `migrations` VALUES (114,'2021_11_09_115919_update_designs',6);
|
INSERT INTO `migrations` VALUES (114,'2021_11_09_115919_update_designs',6);
|
||||||
INSERT INTO `migrations` VALUES (115,'2021_11_10_184847_add_is_migrate_column_to_accounts_table',6);
|
INSERT INTO `migrations` VALUES (115,'2021_11_10_184847_add_is_migrate_column_to_accounts_table',6);
|
||||||
INSERT INTO `migrations` VALUES (116,'2021_11_11_163121_add_instant_bank_transfer',7);
|
INSERT INTO `migrations` VALUES (116,'2021_11_11_163121_add_instant_bank_transfer',7);
|
||||||
|
INSERT INTO `migrations` VALUES (117,'2021_12_20_095542_add_serbian_language_translations',8);
|
||||||
|
INSERT INTO `migrations` VALUES (118,'2022_01_02_022421_add_slovak_language',8);
|
||||||
|
INSERT INTO `migrations` VALUES (119,'2022_01_06_061231_add_app_domain_id_to_gateways_table',8);
|
||||||
|
INSERT INTO `migrations` VALUES (120,'2022_01_18_004856_add_estonian_language',8);
|
||||||
|
INSERT INTO `migrations` VALUES (121,'2022_01_19_085907_add_platform_column_to_accounts_table',8);
|
||||||
|
INSERT INTO `migrations` VALUES (122,'2022_01_19_232436_add_kyd_currency',8);
|
||||||
|
INSERT INTO `migrations` VALUES (123,'2022_01_27_223617_add_client_count_to_accounts_table',8);
|
||||||
|
INSERT INTO `migrations` VALUES (124,'2022_02_06_091629_add_client_currency_conversion_to_companies_table',8);
|
||||||
|
INSERT INTO `migrations` VALUES (125,'2022_02_25_015411_update_stripe_apple_domain_config',9);
|
||||||
|
Binary file not shown.
6
public/flutter_service_worker.js
vendored
6
public/flutter_service_worker.js
vendored
@ -26,13 +26,13 @@ const RESOURCES = {
|
|||||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "015400679694f1f51047e46da0e1dc98",
|
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "015400679694f1f51047e46da0e1dc98",
|
||||||
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
|
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
|
||||||
"assets/NOTICES": "9a4bf0423a5e265f38c4df37f7a0a913",
|
"assets/NOTICES": "9a4bf0423a5e265f38c4df37f7a0a913",
|
||||||
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
|
"assets/fonts/MaterialIcons-Regular.otf": "7e7a6cccddf6d7b20012a548461d5d81",
|
||||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||||
"/": "0c9a98bf00406e79990693094969f3be",
|
"/": "a10a76fa9beabc958dfdeda4f1be38c8",
|
||||||
"version.json": "a00481850d5c63ba5df4e22636643438",
|
"version.json": "a00481850d5c63ba5df4e22636643438",
|
||||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||||
"main.dart.js": "b1de67644e0f666d4674fa21e80da5d1",
|
"main.dart.js": "2c4d2723a1998a9cfe695f465288e5e8",
|
||||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||||
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
|
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
|
||||||
|
2
public/js/clients/payments/stripe-sepa.js
vendored
2
public/js/clients/payments/stripe-sepa.js
vendored
@ -1,2 +1,2 @@
|
|||||||
/*! For license information please see stripe-sepa.js.LICENSE.txt */
|
/*! For license information please see stripe-sepa.js.LICENSE.txt */
|
||||||
(()=>{var e,t,n,o;function a(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var c=function(){function e(t,n){var o=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),r(this,"setupStripe",(function(){o.stripeConnect?o.stripe=Stripe(o.key,{stripeAccount:o.stripeConnect}):o.stripe=Stripe(o.key);var e=o.stripe.elements(),t={style:{base:{color:"#32325d",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',fontSmoothing:"antialiased",fontSize:"16px","::placeholder":{color:"#aab7c4"},":-webkit-autofill":{color:"#32325d"}},invalid:{color:"#fa755a",iconColor:"#fa755a",":-webkit-autofill":{color:"#fa755a"}}},supportedCountries:["SEPA"],placeholderCountry:document.querySelector('meta[name="country"]').content};return o.iban=e.create("iban",t),o.iban.mount("#sepa-iban"),o})),r(this,"handle",(function(){var e=document.getElementById("errors");Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach((function(e){return e.addEventListener("click",(function(e){document.getElementById("stripe--payment-container").classList.add("hidden"),document.getElementById("save-card--container").style.display="none",document.querySelector("input[name=token]").value=e.target.dataset.token}))})),document.getElementById("toggle-payment-with-new-bank-account").addEventListener("click",(function(e){document.getElementById("stripe--payment-container").classList.remove("hidden"),document.getElementById("save-card--container").style.display="grid",document.querySelector("input[name=token]").value=""})),document.getElementById("pay-now").addEventListener("click",(function(t){return 0!==document.querySelector("input[name=token]").value.length?(document.querySelector("#errors").hidden=!0,document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),void o.stripe.confirmSepaDebitSetup(document.querySelector("meta[name=si-client-secret").content,{payment_method:document.querySelector("input[name=token]").value}).then((function(e){if(!e.error)return document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.setupIntent),document.querySelector("#server-response").submit();console.error(error)})).catch((function(t){e.textContent=t,e.hidden=!1}))):""===document.getElementById("sepa-name").value?(document.getElementById("sepa-name").focus(),e.textContent=document.querySelector("meta[name=translation-name-required]").content,void(e.hidden=!1)):""===document.getElementById("sepa-email-address").value?(document.getElementById("sepa-email-address").focus(),e.textContent=document.querySelector("meta[name=translation-email-required]").content,void(e.hidden=!1)):document.getElementById("sepa-mandate-acceptance").checked?(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),void o.stripe.confirmSepaDebitPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{sepa_debit:o.iban,billing_details:{name:document.getElementById("sepa-name").value,email:document.getElementById("sepa-email-address").value}}}).then((function(e){return e.error?o.handleFailure(e.error.message):o.handleSuccess(e)}))):(e.textContent=document.querySelector("meta[name=translation-terms-required]").content,e.hidden=!1,void console.log("Terms"))}))})),this.key=t,this.errors=document.getElementById("errors"),this.stripeConnect=n}var t,n,o;return t=e,(n=[{key:"handleSuccess",value:function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.paymentIntent);var t=document.querySelector('input[name="token-billing-checkbox"]:checked');t&&(document.querySelector('input[name="store_card"]').value=t.value),document.getElementById("server-response").submit()}},{key:"handleFailure",value:function(e){var t=document.getElementById("errors");t.textContent="",t.textContent=e,t.hidden=!1,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden")}}])&&a(t.prototype,n),o&&a(t,o),e}();new c(null!==(e=null===(t=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===t?void 0:t.content)&&void 0!==e?e:"",null!==(n=null===(o=document.querySelector('meta[name="stripe-account-id"]'))||void 0===o?void 0:o.content)&&void 0!==n?n:"").setupStripe().handle()})();
|
(()=>{var e,t,n,a;function o(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var c=function(){function e(t,n){var a=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),r(this,"setupStripe",(function(){a.stripeConnect?a.stripe=Stripe(a.key,{stripeAccount:a.stripeConnect}):a.stripe=Stripe(a.key);var e=a.stripe.elements(),t={style:{base:{color:"#32325d",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',fontSmoothing:"antialiased",fontSize:"16px","::placeholder":{color:"#aab7c4"},":-webkit-autofill":{color:"#32325d"}},invalid:{color:"#fa755a",iconColor:"#fa755a",":-webkit-autofill":{color:"#fa755a"}}},supportedCountries:["SEPA"],placeholderCountry:document.querySelector('meta[name="country"]').content};return a.iban=e.create("iban",t),a.iban.mount("#sepa-iban"),document.getElementById("sepa-name").value=document.querySelector("meta[name=client_name]").content,document.getElementById("sepa-email-address").value=document.querySelector("meta[name=client_email]").content,a})),r(this,"handle",(function(){var e=document.getElementById("errors");Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach((function(e){return e.addEventListener("click",(function(e){document.getElementById("stripe--payment-container").classList.add("hidden"),document.getElementById("save-card--container").style.display="none",document.querySelector("input[name=token]").value=e.target.dataset.token}))})),document.getElementById("toggle-payment-with-new-bank-account").addEventListener("click",(function(e){document.getElementById("stripe--payment-container").classList.remove("hidden"),document.getElementById("save-card--container").style.display="grid",document.querySelector("input[name=token]").value=""})),document.getElementById("pay-now").addEventListener("click",(function(t){if(console.log(document.querySelector("input[name=token]").value),0!==document.querySelector("input[name=token]").value.length)document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),a.stripe.confirmSepaDebitPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:document.querySelector("input[name=token]").value}).then((function(e){return e.error?a.handleFailure(e.error.message):a.handleSuccess(e)}));else{if(""===document.getElementById("sepa-name").value)return document.getElementById("sepa-name").focus(),e.textContent=document.querySelector("meta[name=translation-name-required]").content,void(e.hidden=!1);if(""===document.getElementById("sepa-email-address").value)return document.getElementById("sepa-email-address").focus(),e.textContent=document.querySelector("meta[name=translation-email-required]").content,void(e.hidden=!1);if(!document.getElementById("sepa-mandate-acceptance").checked)return e.textContent=document.querySelector("meta[name=translation-terms-required]").content,void(e.hidden=!1);document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),a.stripe.confirmSepaDebitPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{sepa_debit:a.iban,billing_details:{name:document.getElementById("sepa-name").value,email:document.getElementById("sepa-email-address").value}}}).then((function(e){return e.error?a.handleFailure(e.error.message):a.handleSuccess(e)}))}}))})),this.key=t,this.errors=document.getElementById("errors"),this.stripeConnect=n}var t,n,a;return t=e,(n=[{key:"handleSuccess",value:function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.paymentIntent);var t=document.querySelector('input[name="token-billing-checkbox"]:checked');t&&(document.querySelector('input[name="store_card"]').value=t.value),document.getElementById("server-response").submit()}},{key:"handleFailure",value:function(e){var t=document.getElementById("errors");t.textContent="",t.textContent=e,t.hidden=!1,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden")}}])&&o(t.prototype,n),a&&o(t,a),e}();new c(null!==(e=null===(t=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===t?void 0:t.content)&&void 0!==e?e:"",null!==(n=null===(a=document.querySelector('meta[name="stripe-account-id"]'))||void 0===a?void 0:a.content)&&void 0!==n?n:"").setupStripe().handle()})();
|
192036
public/main.dart.js
vendored
192036
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
186151
public/main.foss.dart.js
vendored
186151
public/main.foss.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
185386
public/main.html.dart.js
vendored
185386
public/main.html.dart.js
vendored
File diff suppressed because one or more lines are too long
187849
public/main.next.dart.js
vendored
187849
public/main.next.dart.js
vendored
File diff suppressed because one or more lines are too long
10410
public/main.profile.dart.js
vendored
10410
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -27,7 +27,7 @@
|
|||||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=8f05ce6bd2d6cae7e5f2",
|
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=8f05ce6bd2d6cae7e5f2",
|
||||||
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=4ed4c8a09803ddd0a9a7",
|
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=4ed4c8a09803ddd0a9a7",
|
||||||
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=c36ab5621413ef1de7c8",
|
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=c36ab5621413ef1de7c8",
|
||||||
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=2daa1a70aa5f8e6988f5",
|
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=da7b16ffaf5645535c7c",
|
||||||
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js?id=61becda97682c7909f29",
|
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js?id=61becda97682c7909f29",
|
||||||
"/js/clients/payments/stripe-giropay.js": "/js/clients/payments/stripe-giropay.js?id=2a973971ed2b890524ee",
|
"/js/clients/payments/stripe-giropay.js": "/js/clients/payments/stripe-giropay.js?id=2a973971ed2b890524ee",
|
||||||
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js?id=41367f4e80e52a0ab436",
|
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js?id=41367f4e80e52a0ab436",
|
||||||
|
174
resources/js/clients/payments/stripe-sepa.js
vendored
174
resources/js/clients/payments/stripe-sepa.js
vendored
@ -17,26 +17,21 @@ class ProcessSEPA {
|
|||||||
|
|
||||||
setupStripe = () => {
|
setupStripe = () => {
|
||||||
|
|
||||||
if (this.stripeConnect){
|
if (this.stripeConnect) {
|
||||||
// this.stripe.stripeAccount = this.stripeConnect;
|
|
||||||
|
this.stripe = Stripe(this.key, {
|
||||||
this.stripe = Stripe(this.key, {
|
stripeAccount: this.stripeConnect,
|
||||||
stripeAccount: this.stripeConnect,
|
});
|
||||||
});
|
|
||||||
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.stripe = Stripe(this.key);
|
this.stripe = Stripe(this.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const elements = this.stripe.elements();
|
const elements = this.stripe.elements();
|
||||||
var style = {
|
var style = {
|
||||||
base: {
|
base: {
|
||||||
color: '#32325d',
|
color: '#32325d',
|
||||||
fontFamily:
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
||||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
|
||||||
fontSmoothing: 'antialiased',
|
fontSmoothing: 'antialiased',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
'::placeholder': {
|
'::placeholder': {
|
||||||
@ -65,6 +60,10 @@ class ProcessSEPA {
|
|||||||
};
|
};
|
||||||
this.iban = elements.create('iban', options);
|
this.iban = elements.create('iban', options);
|
||||||
this.iban.mount('#sepa-iban');
|
this.iban.mount('#sepa-iban');
|
||||||
|
|
||||||
|
document.getElementById('sepa-name').value = document.querySelector('meta[name=client_name]').content;
|
||||||
|
document.getElementById('sepa-email-address').value = document.querySelector('meta[name=client_email]').content;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,107 +96,92 @@ class ProcessSEPA {
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('pay-now').addEventListener('click', (e) => {
|
document.getElementById('pay-now').addEventListener('click', (e) => {
|
||||||
if (
|
|
||||||
document.querySelector('input[name=token]').value.length !== 0
|
console.log(document.querySelector('input[name=token]').value);
|
||||||
) {
|
|
||||||
document.querySelector('#errors').hidden = true;
|
if (document.querySelector('input[name=token]').value.length !== 0) {
|
||||||
|
|
||||||
document.getElementById('pay-now').disabled = true;
|
document.getElementById('pay-now').disabled = true;
|
||||||
document
|
document.querySelector('#pay-now > svg').classList.remove('hidden');
|
||||||
.querySelector('#pay-now > svg')
|
document.querySelector('#pay-now > span').classList.add('hidden');
|
||||||
.classList.remove('hidden');
|
|
||||||
document
|
|
||||||
.querySelector('#pay-now > span')
|
|
||||||
.classList.add('hidden');
|
|
||||||
|
|
||||||
this.stripe
|
this.stripe
|
||||||
.confirmSepaDebitSetup(
|
.confirmSepaDebitPayment(
|
||||||
document.querySelector('meta[name=si-client-secret')
|
document.querySelector('meta[name=pi-client-secret')
|
||||||
.content,
|
.content, {
|
||||||
{
|
payment_method: document.querySelector('input[name=token]').value
|
||||||
payment_method: document.querySelector(
|
|
||||||
'input[name=token]'
|
|
||||||
).value,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
console.error(error);
|
return this.handleFailure(result.error.message);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector(
|
return this.handleSuccess(result);
|
||||||
'input[name="gateway_response"]'
|
|
||||||
).value = JSON.stringify(result.setupIntent);
|
|
||||||
|
|
||||||
return document
|
|
||||||
.querySelector('#server-response')
|
|
||||||
.submit();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
errors.textContent = error;
|
|
||||||
errors.hidden = false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
if (document.getElementById('sepa-name').value === '') {
|
if (document.getElementById('sepa-name').value === '') {
|
||||||
document.getElementById('sepa-name').focus();
|
document.getElementById('sepa-name').focus();
|
||||||
errors.textContent = document.querySelector(
|
errors.textContent = document.querySelector(
|
||||||
'meta[name=translation-name-required]'
|
'meta[name=translation-name-required]'
|
||||||
).content;
|
).content;
|
||||||
errors.hidden = false;
|
errors.hidden = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.getElementById('sepa-email-address').value === '') {
|
if (document.getElementById('sepa-email-address').value === '') {
|
||||||
document.getElementById('sepa-email-address').focus();
|
document.getElementById('sepa-email-address').focus();
|
||||||
errors.textContent = document.querySelector(
|
errors.textContent = document.querySelector(
|
||||||
'meta[name=translation-email-required]'
|
'meta[name=translation-email-required]'
|
||||||
).content;
|
).content;
|
||||||
errors.hidden = false;
|
errors.hidden = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!document.getElementById('sepa-mandate-acceptance').checked) {
|
if (!document.getElementById('sepa-mandate-acceptance').checked) {
|
||||||
errors.textContent = document.querySelector(
|
errors.textContent = document.querySelector(
|
||||||
'meta[name=translation-terms-required]'
|
'meta[name=translation-terms-required]'
|
||||||
).content;
|
).content;
|
||||||
errors.hidden = false;
|
errors.hidden = false;
|
||||||
console.log('Terms');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('pay-now').disabled = true;
|
return;
|
||||||
document.querySelector('#pay-now > svg').classList.remove('hidden');
|
}
|
||||||
document.querySelector('#pay-now > span').classList.add('hidden');
|
|
||||||
|
|
||||||
this.stripe
|
|
||||||
.confirmSepaDebitPayment(
|
document.getElementById('pay-now').disabled = true;
|
||||||
document.querySelector('meta[name=pi-client-secret')
|
document.querySelector('#pay-now > svg').classList.remove('hidden');
|
||||||
.content,
|
document.querySelector('#pay-now > span').classList.add('hidden');
|
||||||
{
|
|
||||||
payment_method: {
|
|
||||||
sepa_debit: this.iban,
|
|
||||||
billing_details: {
|
this.stripe
|
||||||
name: document.getElementById('sepa-name')
|
.confirmSepaDebitPayment(
|
||||||
.value,
|
document.querySelector('meta[name=pi-client-secret')
|
||||||
email: document.getElementById(
|
.content, {
|
||||||
'sepa-email-address'
|
payment_method: {
|
||||||
).value,
|
sepa_debit: this.iban,
|
||||||
|
billing_details: {
|
||||||
|
name: document.getElementById('sepa-name')
|
||||||
|
.value,
|
||||||
|
email: document.getElementById(
|
||||||
|
'sepa-email-address'
|
||||||
|
).value,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
)
|
||||||
)
|
.then((result) => {
|
||||||
.then((result) => {
|
if (result.error) {
|
||||||
if (result.error) {
|
return this.handleFailure(result.error.message);
|
||||||
return this.handleFailure(result.error.message);
|
}
|
||||||
}
|
|
||||||
|
return this.handleSuccess(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return this.handleSuccess(result);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4545,6 +4545,9 @@ $LANG = array(
|
|||||||
'activity_124' => ':user restored recurring expense :recurring_expense',
|
'activity_124' => ':user restored recurring expense :recurring_expense',
|
||||||
'fpx' => "FPX",
|
'fpx' => "FPX",
|
||||||
'to_view_entity_set_password' => 'To view the :entity you need to set password.',
|
'to_view_entity_set_password' => 'To view the :entity you need to set password.',
|
||||||
|
'unsubscribe' => 'Unsubscribe',
|
||||||
|
'unsubscribed' => 'Unsubscribed',
|
||||||
|
'unsubscribed_text' => 'You have been removed from notifications for this document'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -177,6 +177,9 @@
|
|||||||
</p>
|
</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@if(isset($unsubscribe_link))
|
||||||
|
<p><a href="{{$unsubscribe_link}}">{{ ctrans('texts.unsubscribe') }}</a></p>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -29,3 +29,6 @@
|
|||||||
</p>
|
</p>
|
||||||
@endif
|
@endif
|
||||||
@endisset
|
@endisset
|
||||||
|
@if(isset($unsubscribe_link))
|
||||||
|
<p><a href="{{$unsubscribe_link}}">{{ ctrans('texts.unsubscribe') }}</a></p>
|
||||||
|
@endif
|
@ -6,6 +6,8 @@
|
|||||||
<meta name="amount" content="{{ $stripe_amount }}">
|
<meta name="amount" content="{{ $stripe_amount }}">
|
||||||
<meta name="country" content="{{ $country }}">
|
<meta name="country" content="{{ $country }}">
|
||||||
<meta name="customer" content="{{ $customer }}">
|
<meta name="customer" content="{{ $customer }}">
|
||||||
|
<meta name="client_name" content="{{ $client->present()->name() }}">
|
||||||
|
<meta name="client_email" content="{{ $client->present()->email() }}">
|
||||||
<meta name="pi-client-secret" content="{{ $pi_client_secret }}">
|
<meta name="pi-client-secret" content="{{ $pi_client_secret }}">
|
||||||
<meta name="si-client-secret" content="{{ $si_client_secret ?? '' }}">
|
<meta name="si-client-secret" content="{{ $si_client_secret ?? '' }}">
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
@extends('portal.ninja2020.layout.clean')
|
||||||
|
@section('meta_title', ctrans('texts.unsubscribed'))
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
|
||||||
|
<div class="flex h-screen">
|
||||||
|
<div class="m-auto md:w-1/3 lg:w-1/5">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<img src="{{ $logo }}" class="border-b border-gray-100 h-18 pb-4" alt="Invoice Ninja logo">
|
||||||
|
<h1 class="text-center text-3xl mt-10">{{ ctrans('texts.unsubscribed') }}</h1>
|
||||||
|
<p class="text-center opacity-75">{{ ctrans('texts.unsubscribed_text') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@push('footer')
|
||||||
|
|
||||||
|
@endpush
|
286
resources/views/portal/ninja2020/plan/trial.blade.php
Normal file
286
resources/views/portal/ninja2020/plan/trial.blade.php
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
@extends('portal.ninja2020.layout.app')
|
||||||
|
@section('meta_title', ctrans('texts.account_management'))
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
|
||||||
|
<meta name="stripe-publishable-key" content="{{ $gateway->getPublishableKey()}}">
|
||||||
|
<meta name="client-postal-code" content="{{ $client->postal_code }}">
|
||||||
|
<meta name="client-name" content="{{ $client->present()->name() }}">
|
||||||
|
|
||||||
|
<div class="flex flex-wrap overflow-hidden">
|
||||||
|
|
||||||
|
<div class="w-1/2 overflow-hidden">
|
||||||
|
<h1 style="font-size:24px;">Start your 14 day Pro Trial!</h1>
|
||||||
|
<p class="mt-6">Enjoy 14 days of our Pro Plan</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="list-decimal mx-20 w-100">
|
||||||
|
<li>Unlimited clients, invoices and quotes</li>
|
||||||
|
<li>Remove "Created by Invoice Ninja" from invoices</li>
|
||||||
|
<li>Enable emails to be sent from your GMail</li>
|
||||||
|
<li>Create subscriptions: Recurring & Auto-billing</li>
|
||||||
|
<li>API integration with 3rd party apps & platforms</li>
|
||||||
|
<li>Custom reminders</li>
|
||||||
|
<li>Attach PDF's to client emails</li>
|
||||||
|
<li>Display clients e-signature on invoices and quotes</li>
|
||||||
|
<li>Enable clients to "Approve Terms' checkbox</li>
|
||||||
|
<li>Bulk emailing of invoices and quotes</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2 overflow-hidden">
|
||||||
|
|
||||||
|
<form id="card-form" action="{{ route('client.trial.response') }}" method="post">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="gateway_response">
|
||||||
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<input type="text" class="form-control block
|
||||||
|
w-full
|
||||||
|
px-3
|
||||||
|
py-2
|
||||||
|
text-base
|
||||||
|
font-normal
|
||||||
|
text-gray-700
|
||||||
|
bg-white bg-clip-padding
|
||||||
|
border border-solid border-gray-300
|
||||||
|
rounded
|
||||||
|
transition
|
||||||
|
ease-in-out
|
||||||
|
m-0
|
||||||
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="name"
|
||||||
|
placeholder="{{ ctrans('texts.name') }}"
|
||||||
|
name="name"
|
||||||
|
value="{{$client->present()->name()}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<input type="text" class="form-control block
|
||||||
|
w-full
|
||||||
|
px-3
|
||||||
|
py-2
|
||||||
|
text-base
|
||||||
|
font-normal
|
||||||
|
text-gray-700
|
||||||
|
bg-white bg-clip-padding
|
||||||
|
border border-solid border-gray-300
|
||||||
|
rounded
|
||||||
|
transition
|
||||||
|
ease-in-out
|
||||||
|
m-0
|
||||||
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="address1"
|
||||||
|
placeholder="{{ ctrans('texts.address1') }}"
|
||||||
|
name="address1"
|
||||||
|
value="{{$client->address1}}">
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<input type="text" class="form-control block
|
||||||
|
w-full
|
||||||
|
px-3
|
||||||
|
py-2
|
||||||
|
text-base
|
||||||
|
font-normal
|
||||||
|
text-gray-700
|
||||||
|
bg-white bg-clip-padding
|
||||||
|
border border-solid border-gray-300
|
||||||
|
rounded
|
||||||
|
transition
|
||||||
|
ease-in-out
|
||||||
|
m-0
|
||||||
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="address2"
|
||||||
|
placeholder="{{ ctrans('texts.address2') }}"
|
||||||
|
name="address2"
|
||||||
|
value="{{$client->address2}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex form-group mb-2">
|
||||||
|
|
||||||
|
<div class="w-full gap-x-2 md:w-1/3">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control block
|
||||||
|
w-full
|
||||||
|
px-3
|
||||||
|
py-2
|
||||||
|
text-base
|
||||||
|
font-normal
|
||||||
|
text-gray-700
|
||||||
|
bg-white bg-clip-padding
|
||||||
|
border border-solid border-gray-300
|
||||||
|
rounded
|
||||||
|
transition
|
||||||
|
ease-in-out
|
||||||
|
m-0
|
||||||
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="city"
|
||||||
|
placeholder="{{ ctrans('texts.city') }}"
|
||||||
|
name="city"
|
||||||
|
value="{{$client->city}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full gap-x-2 md:w-1/3">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control block
|
||||||
|
w-full
|
||||||
|
px-3
|
||||||
|
py-2
|
||||||
|
text-base
|
||||||
|
font-normal
|
||||||
|
text-gray-700
|
||||||
|
bg-white bg-clip-padding
|
||||||
|
border border-solid border-gray-300
|
||||||
|
rounded
|
||||||
|
transition
|
||||||
|
ease-in-out
|
||||||
|
m-0
|
||||||
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="state"
|
||||||
|
placeholder="{{ ctrans('texts.state') }}"
|
||||||
|
name="state"
|
||||||
|
value="{{$client->state}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full gap-x-2 md:w-1/3">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control block
|
||||||
|
w-full
|
||||||
|
px-3
|
||||||
|
py-2
|
||||||
|
text-base
|
||||||
|
font-normal
|
||||||
|
text-gray-700
|
||||||
|
bg-white bg-clip-padding
|
||||||
|
border border-solid border-gray-300
|
||||||
|
rounded
|
||||||
|
transition
|
||||||
|
ease-in-out
|
||||||
|
m-0
|
||||||
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="postal_code"
|
||||||
|
placeholder="{{ ctrans('texts.postal_code') }}"
|
||||||
|
name="postal_code"
|
||||||
|
value="{{$client->postal_code}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<select name="country" id="country" class="form-select w-full py-2 text-gray-700">
|
||||||
|
<option value="{{ $client->country->id}}" selected>{{ $client->country->iso_3166_2 }} ({{ $client->country->name }})</option>
|
||||||
|
@foreach($countries as $country)
|
||||||
|
<option value="{{ $country->id }}">{{ $country->iso_3166_2 }} ({{ $country->name }})></option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div id="card-element" class="border p-4 rounded
|
||||||
|
text-base
|
||||||
|
font-normal
|
||||||
|
text-gray-700
|
||||||
|
bg-white bg-clip-padding
|
||||||
|
border border-solid border-gray-300
|
||||||
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button
|
||||||
|
@isset($form) form="{{ $form }}" @endisset
|
||||||
|
type="{{ $type ?? 'button' }}"
|
||||||
|
id="{{ $id ?? 'pay-now' }}"
|
||||||
|
@isset($data) @foreach($data as $prop => $value) data-{{ $prop }}="{{ $value }}" @endforeach @endisset
|
||||||
|
class="button button-primary bg-primary {{ $class ?? '' }}"
|
||||||
|
{{ isset($disabled) && $disabled === true ? 'disabled' : '' }}>
|
||||||
|
<svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
<span>{{ $slot ?? ctrans('texts.trial_call_to_action') }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end mt-5">
|
||||||
|
<span class="text-gray-700" style="font-size:12px;">* At the end of your 14 day trial your card will be charged $10/month. Cancel anytime.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('footer')
|
||||||
|
<script src="https://js.stripe.com/v3/"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var stripe = Stripe('{{ $gateway->getPublishableKey()}}');
|
||||||
|
var client_secret = '{{ $intent->client_secret }}';
|
||||||
|
|
||||||
|
var elements = stripe.elements({
|
||||||
|
clientSecret: client_secret,
|
||||||
|
});
|
||||||
|
|
||||||
|
var cardElement = elements.create('card', {
|
||||||
|
value: {
|
||||||
|
postalCode: document.querySelector('input[name=postal_code]').content,
|
||||||
|
name: document.querySelector('input[name=name]').content
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cardElement.mount('#card-element');
|
||||||
|
|
||||||
|
const form = document.getElementById('card-form');
|
||||||
|
|
||||||
|
var e = document.getElementById("country");
|
||||||
|
var country_value = e.options[e.selectedIndex].value;
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById('pay-now')
|
||||||
|
.addEventListener('click', () => {
|
||||||
|
|
||||||
|
let payNowButton = document.getElementById('pay-now');
|
||||||
|
payNowButton = payNowButton;
|
||||||
|
payNowButton.disabled = true;
|
||||||
|
payNowButton.querySelector('svg').classList.remove('hidden');
|
||||||
|
payNowButton.querySelector('span').classList.add('hidden');
|
||||||
|
|
||||||
|
stripe.handleCardSetup(this.client_secret, cardElement, {
|
||||||
|
payment_method_data: {
|
||||||
|
billing_details: {
|
||||||
|
name: document.querySelector('input[name=name]').content,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result.error) {
|
||||||
|
|
||||||
|
let errors = document.getElementById('errors');
|
||||||
|
let payNowButton = document.getElementById('pay-now');
|
||||||
|
|
||||||
|
errors.textContent = '';
|
||||||
|
errors.textContent = result.error.message;
|
||||||
|
errors.hidden = false;
|
||||||
|
|
||||||
|
payNowButton.disabled = false;
|
||||||
|
payNowButton.querySelector('svg').classList.add('hidden');
|
||||||
|
payNowButton.querySelector('span').classList.remove('hidden');
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector(
|
||||||
|
'input[name="gateway_response"]'
|
||||||
|
).value = JSON.stringify(result.setupIntent);
|
||||||
|
|
||||||
|
document.getElementById('card-form').submit();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@endpush
|
@ -11,3 +11,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
Dropzone.prototype.defaultOptions.dictDefaultMessage = '{!! ctrans('texts.dropzone_default_message') !!}';
|
||||||
|
|
||||||
|
</script>
|
@ -28,6 +28,7 @@ Route::get('documents/{document_hash}', 'ClientPortal\DocumentController@publicD
|
|||||||
Route::get('error', 'ClientPortal\ContactHashLoginController@errorPage')->name('client.error');
|
Route::get('error', 'ClientPortal\ContactHashLoginController@errorPage')->name('client.error');
|
||||||
Route::get('client/payment/{contact_key}/{payment_id}', 'ClientPortal\InvitationController@paymentRouter')->middleware(['domain_db','contact_key_login']);
|
Route::get('client/payment/{contact_key}/{payment_id}', 'ClientPortal\InvitationController@paymentRouter')->middleware(['domain_db','contact_key_login']);
|
||||||
Route::get('client/ninja/{contact_key}/{company_key}', 'ClientPortal\NinjaPlanController@index')->name('client.ninja_contact_login')->middleware(['domain_db']);
|
Route::get('client/ninja/{contact_key}/{company_key}', 'ClientPortal\NinjaPlanController@index')->name('client.ninja_contact_login')->middleware(['domain_db']);
|
||||||
|
Route::post('client/ninja/trial_confirmation', 'ClientPortal\NinjaPlanController@trial_confirmation')->name('client.trial.response')->middleware(['domain_db']);
|
||||||
|
|
||||||
Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_client_existence'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_client_existence'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||||
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
||||||
@ -112,6 +113,9 @@ Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'clie
|
|||||||
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_invitation_key');
|
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_invitation_key');
|
||||||
Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
|
Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
|
||||||
Route::get('pay/{invitation_key}', 'ClientPortal\InvitationController@payInvoice')->name('pay.invoice');
|
Route::get('pay/{invitation_key}', 'ClientPortal\InvitationController@payInvoice')->name('pay.invoice');
|
||||||
|
|
||||||
|
Route::get('unsubscribe/{invitation_key}', 'ClientPortal\InvitationController@unsubscribe')->name('unsubscribe');
|
||||||
|
|
||||||
// Route::get('{entity}/{client_hash}/{invitation_key}', 'ClientPortal\InvitationController@routerForIframe')->name('invoice.client_hash_and_invitation_key'); //should never need this
|
// Route::get('{entity}/{client_hash}/{invitation_key}', 'ClientPortal\InvitationController@routerForIframe')->name('invoice.client_hash_and_invitation_key'); //should never need this
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -121,7 +121,7 @@ class MultiPaymentDeleteTest extends TestCase
|
|||||||
$this->assertEquals(0, $invoice->balance);
|
$this->assertEquals(0, $invoice->balance);
|
||||||
//mark sent
|
//mark sent
|
||||||
|
|
||||||
$invoice = $invoice->service()->markSent()->save();
|
$invoice = $invoice->service()->markSent()->createInvitations()->save();
|
||||||
|
|
||||||
$invoice->fresh();
|
$invoice->fresh();
|
||||||
$invoice->client->fresh();
|
$invoice->client->fresh();
|
||||||
|
@ -297,7 +297,7 @@ class PaymentTest extends TestCase
|
|||||||
|
|
||||||
$this->invoice = $this->invoice_calc->getInvoice();
|
$this->invoice = $this->invoice_calc->getInvoice();
|
||||||
$this->invoice->save();
|
$this->invoice->save();
|
||||||
$this->invoice->service()->markSent()->save();
|
$this->invoice->service()->markSent()->createInvitations()->save();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'amount' => 2.0,
|
'amount' => 2.0,
|
||||||
|
@ -62,20 +62,87 @@ class NumberTest extends TestCase
|
|||||||
$this->assertEquals(7.99, $converted_amount);
|
$this->assertEquals(7.99, $converted_amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public function testParsingFloats()
|
public function testRoundingDecimalsTwo()
|
||||||
// {
|
{
|
||||||
// Currency::all()->each(function ($currency) {
|
$currency = Currency::find(1);
|
||||||
// $amount = 123456789.12;
|
|
||||||
|
|
||||||
// $formatted_amount = Number::formatValue($amount, $currency);
|
$x = Number::formatValueNoTrailingZeroes(0.05, $currency);
|
||||||
|
|
||||||
// $float_amount = Number::parseFloat($formatted_amount);
|
$this->assertEquals(0.05, $x);
|
||||||
|
}
|
||||||
|
|
||||||
// if ($currency->precision == 0) {
|
public function testRoundingDecimalsThree()
|
||||||
// $this->assertEquals(123456789, $float_amount);
|
{
|
||||||
// } else {
|
$currency = Currency::find(1);
|
||||||
// $this->assertEquals($amount, $float_amount);
|
|
||||||
// }
|
$x = Number::formatValueNoTrailingZeroes(0.005, $currency);
|
||||||
// });
|
|
||||||
// }
|
$this->assertEquals(0.005, $x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRoundingDecimalsFour()
|
||||||
|
{
|
||||||
|
$currency = Currency::find(1);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(0.0005, $currency);
|
||||||
|
|
||||||
|
$this->assertEquals(0.0005, $x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRoundingDecimalsFive()
|
||||||
|
{
|
||||||
|
$currency = Currency::find(1);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(0.00005, $currency);
|
||||||
|
|
||||||
|
$this->assertEquals(0.00005, $x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRoundingDecimalsSix()
|
||||||
|
{
|
||||||
|
$currency = Currency::find(1);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(0.000005, $currency);
|
||||||
|
|
||||||
|
$this->assertEquals(0.000005, $x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRoundingDecimalsSeven()
|
||||||
|
{
|
||||||
|
$currency = Currency::find(1);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(0.0000005, $currency);
|
||||||
|
|
||||||
|
$this->assertEquals(0.0000005, $x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRoundingDecimalsEight()
|
||||||
|
{
|
||||||
|
$currency = Currency::find(1);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(0.00000005, $currency);
|
||||||
|
|
||||||
|
$this->assertEquals(0.00000005, $x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testRoundingPositive()
|
||||||
|
{
|
||||||
|
$currency = Currency::find(1);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(1.5, $currency);
|
||||||
|
$this->assertEquals(1.5, $x);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(1.50, $currency);
|
||||||
|
$this->assertEquals(1.5, $x);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(1.500, $currency);
|
||||||
|
$this->assertEquals(1.5, $x);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(1.50005, $currency);
|
||||||
|
$this->assertEquals(1.50005, $x);
|
||||||
|
|
||||||
|
$x = Number::formatValueNoTrailingZeroes(1.50000005, $currency);
|
||||||
|
$this->assertEquals(1.50000005, $x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user