mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 20:00:33 -04:00
commit
b81b2b5798
@ -1 +1 @@
|
||||
5.3.18
|
||||
5.3.19
|
@ -50,7 +50,7 @@ class PostUpdate extends Command
|
||||
info("I wasn't able to migrate the data.");
|
||||
}
|
||||
|
||||
nlog("finished migrating");
|
||||
info("finished migrating");
|
||||
|
||||
$output = [];
|
||||
|
||||
|
@ -63,7 +63,7 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping();
|
||||
|
||||
$schedule->job(new RecurringExpensesCron)->dailyAt('23:45')->withoutOverlapping();
|
||||
$schedule->job(new RecurringExpensesCron)->dailyAt('00:10')->withoutOverlapping();
|
||||
|
||||
$schedule->job(new AutoBillCron)->dailyAt('00:30')->withoutOverlapping();
|
||||
|
||||
|
@ -137,7 +137,11 @@ class InvitationController extends Controller
|
||||
|
||||
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
||||
|
||||
$invitation = $entity_obj::whereRaw('BINARY `key`= ?', [$invitation_key])
|
||||
// $invitation = $entity_obj::whereRaw('BINARY `key`= ?', [$invitation_key])
|
||||
// ->with('contact.client')
|
||||
// ->firstOrFail();
|
||||
|
||||
$invitation = $entity_obj::where('key', $invitation_key)
|
||||
->with('contact.client')
|
||||
->firstOrFail();
|
||||
|
||||
|
@ -15,6 +15,7 @@ namespace App\Http\Controllers\ClientPortal;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ClientPortal\Uploads\StoreUploadRequest;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Account;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Utils\Ninja;
|
||||
@ -26,15 +27,19 @@ use Illuminate\Support\Facades\Auth;
|
||||
class NinjaPlanController extends Controller
|
||||
{
|
||||
|
||||
public function index(string $contact_key, string $company_key)
|
||||
public function index(string $contact_key, string $account_or_company_key)
|
||||
{
|
||||
MultiDB::findAndSetDbByCompanyKey($company_key);
|
||||
$company = Company::where('company_key', $company_key)->first();
|
||||
|
||||
nlog("Ninja Plan Controller Company key found {$company->company_key}");
|
||||
MultiDB::findAndSetDbByCompanyKey($account_or_company_key);
|
||||
$company = Company::where('company_key', $account_or_company_key)->first();
|
||||
|
||||
if(!$company){
|
||||
MultiDB::findAndSetDbByAccountKey($account_or_company_key);
|
||||
$account = Account::where('key', $account_or_company_key)->first();
|
||||
}
|
||||
else
|
||||
$account = $company->account;
|
||||
|
||||
|
||||
if (MultiDB::findAndSetDbByContactKey($contact_key) && $client_contact = ClientContact::where('contact_key', $contact_key)->first())
|
||||
{
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\DataMapper\Analytics\EmailBounce;
|
||||
use App\DataMapper\Analytics\Mail\EmailBounce;
|
||||
use App\DataMapper\Analytics\Mail\EmailSpam;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
|
@ -278,7 +278,7 @@ class SetupController extends Controller
|
||||
private function testPhantom()
|
||||
{
|
||||
try {
|
||||
$key = config('ninja.phantomjs_pdf_generation');
|
||||
$key = config('ninja.phantomjs_key');
|
||||
$url = 'https://www.invoiceninja.org/';
|
||||
|
||||
$phantom_url = "https://phantomjscloud.com/api/browser/v2/{$key}/?request=%7Burl:%22{$url}%22,renderType:%22pdf%22%7D";
|
||||
|
@ -39,6 +39,7 @@ class CreditsTable extends Component
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->where('status_id', '<>', Credit::STATUS_DRAFT)
|
||||
->where('is_deleted', 0)
|
||||
->where(function ($query){
|
||||
$query->whereDate('due_date', '<=', now())
|
||||
->orWhereNull('due_date');
|
||||
|
@ -41,6 +41,7 @@ class PaymentsTable extends Component
|
||||
{
|
||||
$query = Payment::query()
|
||||
->with('type', 'client')
|
||||
->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED])
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
|
63
app/Jobs/Cron/AutoBill.php
Normal file
63
app/Jobs/Cron/AutoBill.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Cron;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
|
||||
|
||||
class AutoBill
|
||||
{
|
||||
use Dispatchable;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public Invoice $invoice;
|
||||
|
||||
public string $db;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Invoice $invoice, ?string $db)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle() : void
|
||||
{
|
||||
set_time_limit(0);
|
||||
|
||||
if($this->db)
|
||||
MultiDB::setDb($this->db);
|
||||
|
||||
try{
|
||||
|
||||
$this->invoice->service()->autoBill()->save();
|
||||
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
nlog("Failed to capture payment for {$this->invoice->company_id} - {$this->invoice->number} ->" . $e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Jobs\Cron;
|
||||
|
||||
use App\Jobs\Cron\AutoBill;
|
||||
use App\Jobs\RecurringInvoice\SendRecurring;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Invoice;
|
||||
@ -52,12 +53,15 @@ class AutoBillCron
|
||||
->where('auto_bill_enabled', true)
|
||||
->where('balance', '>', 0)
|
||||
->where('is_deleted', false)
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('company');
|
||||
|
||||
nlog($auto_bill_partial_invoices->count(). " partial invoices to auto bill");
|
||||
|
||||
$auto_bill_partial_invoices->cursor()->each(function ($invoice){
|
||||
$this->runAutoBiller($invoice, false);
|
||||
AutoBill::dispatch($invoice, false);
|
||||
});
|
||||
|
||||
$auto_bill_invoices = Invoice::whereDate('due_date', '<=', now())
|
||||
@ -65,12 +69,16 @@ class AutoBillCron
|
||||
->where('auto_bill_enabled', true)
|
||||
->where('balance', '>', 0)
|
||||
->where('is_deleted', false)
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('company');
|
||||
|
||||
nlog($auto_bill_invoices->count(). " full invoices to auto bill");
|
||||
|
||||
|
||||
$auto_bill_invoices->cursor()->each(function ($invoice){
|
||||
$this->runAutoBiller($invoice, false);
|
||||
AutoBill::dispatch($invoice, false);
|
||||
});
|
||||
|
||||
|
||||
@ -85,12 +93,15 @@ class AutoBillCron
|
||||
->where('auto_bill_enabled', true)
|
||||
->where('balance', '>', 0)
|
||||
->where('is_deleted', false)
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('company');
|
||||
|
||||
nlog($auto_bill_partial_invoices->count(). " partial invoices to auto bill db = {$db}");
|
||||
|
||||
$auto_bill_partial_invoices->cursor()->each(function ($invoice) use($db){
|
||||
$this->runAutoBiller($invoice, $db);
|
||||
AutoBill::dispatch($invoice, $db);
|
||||
});
|
||||
|
||||
$auto_bill_invoices = Invoice::whereDate('due_date', '<=', now())
|
||||
@ -98,32 +109,19 @@ class AutoBillCron
|
||||
->where('auto_bill_enabled', true)
|
||||
->where('balance', '>', 0)
|
||||
->where('is_deleted', false)
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('company');
|
||||
|
||||
nlog($auto_bill_invoices->count(). " full invoices to auto bill db = {$db}");
|
||||
|
||||
$auto_bill_invoices->cursor()->each(function ($invoice) use($db){
|
||||
$this->runAutoBiller($invoice, $db);
|
||||
AutoBill::dispatch($invoice, $db);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function runAutoBiller(Invoice $invoice, $db)
|
||||
{
|
||||
info("Firing autobill for {$invoice->company_id} - {$invoice->number}");
|
||||
|
||||
try{
|
||||
|
||||
if($db)
|
||||
MultiDB::setDB($db);
|
||||
|
||||
$invoice->service()->autoBill()->save();
|
||||
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
nlog("Failed to capture payment for {$invoice->company_id} - {$invoice->number} ->" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,9 @@ class RecurringExpensesCron
|
||||
->whereNull('deleted_at')
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('company')
|
||||
->cursor();
|
||||
|
||||
|
@ -53,15 +53,19 @@ class RecurringInvoicesCron
|
||||
$query->where('is_deleted',0)
|
||||
->where('deleted_at', NULL);
|
||||
})
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('company')
|
||||
->cursor();
|
||||
|
||||
nlog(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count());
|
||||
|
||||
$recurring_invoices->each(function ($recurring_invoice, $key) {
|
||||
|
||||
nlog("Current date = " . now()->format("Y-m-d") . " Recurring date = " .$recurring_invoice->next_send_date);
|
||||
|
||||
if (!$recurring_invoice->company->is_disabled) {
|
||||
nlog("Trying to send {$recurring_invoice->number}");
|
||||
|
||||
try{
|
||||
SendRecurring::dispatchNow($recurring_invoice, $recurring_invoice->company->db);
|
||||
@ -69,7 +73,7 @@ class RecurringInvoicesCron
|
||||
catch(\Exception $e){
|
||||
nlog("Unable to sending recurring invoice {$recurring_invoice->id}");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
//multiDB environment, need to
|
||||
@ -86,6 +90,9 @@ class RecurringInvoicesCron
|
||||
$query->where('is_deleted',0)
|
||||
->where('deleted_at', NULL);
|
||||
})
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('company')
|
||||
->cursor();
|
||||
|
||||
@ -94,7 +101,7 @@ class RecurringInvoicesCron
|
||||
$recurring_invoices->each(function ($recurring_invoice, $key) {
|
||||
nlog("Current date = " . now()->format("Y-m-d") . " Recurring date = " .$recurring_invoice->next_send_date ." Recurring #id = ". $recurring_invoice->id);
|
||||
|
||||
if (!$recurring_invoice->company->is_disabled) {
|
||||
nlog("Trying to send {$recurring_invoice->number}");
|
||||
|
||||
try{
|
||||
SendRecurring::dispatchNow($recurring_invoice, $recurring_invoice->company->db);
|
||||
@ -102,7 +109,7 @@ class RecurringInvoicesCron
|
||||
catch(\Exception $e){
|
||||
nlog("Unable to sending recurring invoice {$recurring_invoice->id}");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,11 @@ class SendRecurring implements ShouldQueue
|
||||
// Generate Standard Invoice
|
||||
$invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice, $this->recurring_invoice->client);
|
||||
|
||||
if($this->recurring_invoice->auto_bill == "always")
|
||||
$invoice->auto_bill_enabled = true;
|
||||
elseif($this->recurring_invoice->auto_bill == "off")
|
||||
$invoice->auto_bill_enabled = false;
|
||||
|
||||
$invoice->date = now()->format('Y-m-d');
|
||||
$invoice->due_date = $this->recurring_invoice->calculateDueDate(now()->format('Y-m-d'));
|
||||
$invoice->recurring_id = $this->recurring_invoice->id;
|
||||
|
@ -70,6 +70,9 @@ class ReminderJob implements ShouldQueue
|
||||
$query->where('is_deleted',0)
|
||||
->where('deleted_at', NULL);
|
||||
})
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled',0);
|
||||
})
|
||||
->with('invitations')->cursor()->each(function ($invoice) {
|
||||
|
||||
if ($invoice->isPayable()) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Libraries;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
@ -178,7 +179,7 @@ class MultiDB
|
||||
$current_db = config('database.default');
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($ct = ClientContact::on($db)->whereRaw('BINARY `token`= ?', [$token])->first()) {
|
||||
if (ClientContact::on($db)->whereRaw('BINARY `token`= ?', [$token])->exists()) {
|
||||
self::setDb($db);
|
||||
return true;
|
||||
}
|
||||
@ -230,8 +231,8 @@ class MultiDB
|
||||
$current_db = config('database.default');
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($ct = CompanyToken::on($db)->whereRaw('BINARY `token`= ?', [$token])->first()) {
|
||||
self::setDb($ct->company->db);
|
||||
if (CompanyToken::on($db)->whereRaw('BINARY `token`= ?', [$token])->exists()) {
|
||||
self::setDb($db);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -246,8 +247,24 @@ class MultiDB
|
||||
$current_db = config('database.default');
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($company = Company::on($db)->where('company_key', $company_key)->first()) {
|
||||
self::setDb($company->db);
|
||||
if (Company::on($db)->where('company_key', $company_key)->exists()) {
|
||||
self::setDb($db);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
self::setDB($current_db);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function findAndSetDbByAccountKey($account_key) :bool
|
||||
{
|
||||
$current_db = config('database.default');
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if (Account::on($db)->where('key', $account_key)->exists()) {
|
||||
self::setDb($db);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -262,8 +279,8 @@ class MultiDB
|
||||
$current_db = config('database.default');
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($client_contact = ClientContact::on($db)->where('contact_key', $contact_key)->first()) {
|
||||
self::setDb($client_contact->company->db);
|
||||
if (ClientContact::on($db)->where('contact_key', $contact_key)->exists()) {
|
||||
self::setDb($db);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -278,8 +295,8 @@ class MultiDB
|
||||
$current_db = config('database.default');
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($client = Client::on($db)->where('client_hash', $client_hash)->first()) {
|
||||
self::setDb($client->company->db);
|
||||
if (Client::on($db)->where('client_hash', $client_hash)->exists()) {
|
||||
self::setDb($db);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -299,7 +316,7 @@ class MultiDB
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($company = Company::on($db)->where($query_array)->first()) {
|
||||
self::setDb($company->db);
|
||||
self::setDb($db);
|
||||
return $company;
|
||||
}
|
||||
}
|
||||
@ -315,7 +332,7 @@ class MultiDB
|
||||
$current_db = config('database.default');
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
if ($invite = $class::on($db)->whereRaw('BINARY `key`= ?', [$invitation_key])->first()) {
|
||||
if ($invite = $class::on($db)->whereRaw('BINARY `key`= ?', [$invitation_key])->exists()) {
|
||||
self::setDb($db);
|
||||
return true;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ class SupportMessageSent extends Mailable
|
||||
$db = str_replace("db-ninja-", "", $company->db);
|
||||
$is_large = $company->is_large ? "L" : "S";
|
||||
$platform = array_key_exists('platform', $this->data) ? $this->data['platform'] : "U";
|
||||
$migrated = strlen($company->company_key) == 32 ? "M" : "";
|
||||
$migrated = strlen($company->company_key) == 32 ? "M" : "T";
|
||||
|
||||
if(Ninja::isHosted())
|
||||
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated} :: {$plan} :: ".date('M jS, g:ia');
|
||||
@ -75,7 +75,7 @@ class SupportMessageSent extends Mailable
|
||||
->replyTo($user->email, $user->present()->name())
|
||||
->subject($subject)
|
||||
->view('email.support.message', [
|
||||
'support_message' => $this->data['support_message'],
|
||||
'support_message' => $this->data['message'],
|
||||
'system_info' => $system_info,
|
||||
'laravel_log' => $log_lines,
|
||||
'logo' => $company->present()->logo(),
|
||||
|
@ -271,9 +271,12 @@ class Account extends BaseModel
|
||||
|
||||
$trial_active = false;
|
||||
|
||||
//14 day trial
|
||||
$duration = 60*60*24*14;
|
||||
|
||||
if ($trial_plan && $include_trial) {
|
||||
$trial_started = $this->trial_started;
|
||||
$trial_expires = Carbon::parse($this->trial_started)->addSeconds($this->trial_duration);
|
||||
$trial_expires = Carbon::parse($this->trial_started)->addSeconds($duration);
|
||||
|
||||
if($trial_expires->greaterThan(now())){
|
||||
$trial_active = true;
|
||||
|
@ -41,6 +41,16 @@ class ClientPresenter extends EntityPresenter
|
||||
return $contact_name;
|
||||
}
|
||||
|
||||
public function first_name()
|
||||
{
|
||||
return $this->entity->primary_contact->first() !== null ? $this->entity->primary_contact->first()->first_name : $this->entity->contacts()->first()->first_name;
|
||||
}
|
||||
|
||||
public function last_name()
|
||||
{
|
||||
return $this->entity->primary_contact->first() !== null ? $this->entity->primary_contact->first()->last_name : $this->entity->contacts()->first()->last_name;
|
||||
}
|
||||
|
||||
public function primary_contact_name()
|
||||
{
|
||||
return $this->entity->primary_contact->first() !== null ? $this->entity->primary_contact->first()->first_name.' '.$this->entity->primary_contact->first()->last_name : 'No primary contact set';
|
||||
|
@ -204,6 +204,9 @@ class RecurringExpense extends BaseModel
|
||||
|
||||
public function nextDateByFrequency($date)
|
||||
{
|
||||
$offset = 0;
|
||||
|
||||
if($this->client)
|
||||
$offset = $this->client->timezone_offset();
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
|
@ -34,6 +34,8 @@ class InvoiceObserver
|
||||
->where('event_id', Webhook::EVENT_CREATE_INVOICE)
|
||||
->exists();
|
||||
|
||||
$invoice->load('client');
|
||||
|
||||
if ($subscriptions) {
|
||||
WebhookHandler::dispatch(Webhook::EVENT_CREATE_INVOICE, $invoice, $invoice->company);
|
||||
}
|
||||
@ -51,6 +53,9 @@ class InvoiceObserver
|
||||
->where('event_id', Webhook::EVENT_UPDATE_INVOICE)
|
||||
->exists();
|
||||
|
||||
$invoice->load('client');
|
||||
|
||||
|
||||
if ($subscriptions) {
|
||||
WebhookHandler::dispatch(Webhook::EVENT_UPDATE_INVOICE, $invoice, $invoice->company);
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ class QuoteObserver
|
||||
->where('event_id', Webhook::EVENT_CREATE_QUOTE)
|
||||
->exists();
|
||||
|
||||
$quote->load('client');
|
||||
|
||||
if ($subscriptions) {
|
||||
WebhookHandler::dispatch(Webhook::EVENT_CREATE_QUOTE, $quote, $quote->company);
|
||||
}
|
||||
@ -47,6 +49,9 @@ class QuoteObserver
|
||||
->where('event_id', Webhook::EVENT_UPDATE_QUOTE)
|
||||
->exists();
|
||||
|
||||
$quote->load('client');
|
||||
|
||||
|
||||
if ($subscriptions) {
|
||||
WebhookHandler::dispatch(Webhook::EVENT_UPDATE_QUOTE, $quote, $quote->company);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class BasePaymentDriver
|
||||
protected $refundable = false;
|
||||
|
||||
/* Token billing */
|
||||
protected $token_billing = false;
|
||||
public $token_billing = false;
|
||||
|
||||
/* Authorise payment methods */
|
||||
protected $can_authorise_credit_card = false;
|
||||
|
@ -124,11 +124,29 @@ class CreditCard
|
||||
public function paymentView($data)
|
||||
{
|
||||
$data['gateway'] = $this->square_driver;
|
||||
|
||||
$data['amount'] = $this->square_driver->payment_hash->data->amount_with_fee;
|
||||
$data['currencyCode'] = $this->square_driver->client->getCurrencyCode();
|
||||
$data['square_contact'] = $this->buildClientObject();
|
||||
|
||||
return render('gateways.square.credit_card.pay', $data);
|
||||
}
|
||||
|
||||
private function buildClientObject()
|
||||
{
|
||||
$client = new \stdClass;
|
||||
|
||||
$client->addressLines = [ $this->square_driver->client->address1 ?: '', $this->square_driver->client->address2 ?: ''];
|
||||
$client->givenName = $this->square_driver->client->present()->first_name();
|
||||
$client->familyName = $this->square_driver->client->present()->last_name();
|
||||
$client->email = $this->square_driver->client->present()->email;
|
||||
$client->phone = $this->square_driver->client->phone;
|
||||
$client->city = $this->square_driver->client->city;
|
||||
$client->region = $this->square_driver->client->state;
|
||||
$client->country = $this->square_driver->client->country->iso_3166_2;
|
||||
|
||||
return (array)$client;
|
||||
}
|
||||
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
{
|
||||
$token = $request->sourceId;
|
||||
@ -152,6 +170,9 @@ class CreditCard
|
||||
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
|
||||
$body->setReferenceId(Str::random(16));
|
||||
|
||||
if($request->has('verificationToken') && $request->input('verificationToken'))
|
||||
$body->setVerificationToken($request->input('verificationToken'));
|
||||
|
||||
if ($request->shouldUseToken()) {
|
||||
$body->setCustomerId($cgt->gateway_customer_reference);
|
||||
}
|
||||
@ -174,10 +195,19 @@ class CreditCard
|
||||
{
|
||||
$payment = \json_decode($response->getBody());
|
||||
|
||||
$billing_address = new \Square\Models\Address();
|
||||
$billing_address->setAddressLine1($this->square_driver->client->address1);
|
||||
$billing_address->setAddressLine2($this->square_driver->client->address2);
|
||||
$billing_address->setLocality($this->square_driver->client->city);
|
||||
$billing_address->setAdministrativeDistrictLevel1($this->square_driver->client->state);
|
||||
$billing_address->setPostalCode($this->square_driver->client->postal_code);
|
||||
$billing_address->setCountry($this->square_driver->client->country->iso_3166_2);
|
||||
|
||||
$card = new \Square\Models\Card();
|
||||
$card->setCardholderName($this->square_driver->client->present()->name());
|
||||
$card->setCardholderName($this->square_driver->client->present()->first_name(). " " .$this->square_driver->client->present()->last_name());
|
||||
$card->setCustomerId($this->findOrCreateClient());
|
||||
$card->setReferenceId(Str::random(8));
|
||||
$card->setBillingAddress($billing_address);
|
||||
|
||||
$body = new \Square\Models\CreateCardRequest(Str::random(32), $payment->payment->id, $card);
|
||||
|
||||
@ -270,11 +300,16 @@ class CreditCard
|
||||
if ($api_response->isSuccess()) {
|
||||
$customers = $api_response->getBody();
|
||||
$customers = json_decode($customers);
|
||||
|
||||
if(count(array($api_response->getBody(),1)) == 0)
|
||||
$customers = false;
|
||||
|
||||
} else {
|
||||
$errors = $api_response->getErrors();
|
||||
}
|
||||
|
||||
if ($customers) {
|
||||
|
||||
if (property_exists($customers, 'customers')) {
|
||||
return $customers->customers[0]->id;
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,16 @@ class ACH
|
||||
'method' => '1',
|
||||
*/
|
||||
|
||||
try{
|
||||
$response = $this->wepay_payment_driver->wepay->request('payment_bank/persist', [
|
||||
'client_id' => config('ninja.wepay.client_id'),
|
||||
'client_secret' => config('ninja.wepay.client_secret'),
|
||||
'payment_bank_id' => (int)$data['bank_account_id'],
|
||||
]);
|
||||
|
||||
}
|
||||
catch(\Exception $e){
|
||||
throw new PaymentFailed($e->getMessage(), 400);
|
||||
}
|
||||
// display the response
|
||||
// nlog($response);
|
||||
|
||||
@ -202,6 +206,7 @@ class ACH
|
||||
|
||||
$app_fee = (config('ninja.wepay.fee_ach_multiplier') * $this->wepay_payment_driver->payment_hash->data->amount_with_fee) + config('ninja.wepay.fee_fixed');
|
||||
|
||||
try{
|
||||
$response = $this->wepay_payment_driver->wepay->request('checkout/create', array(
|
||||
// 'callback_uri' => route('payment_webhook', ['company_key' => $this->wepay_payment_driver->company_gateway->company->company_key, 'company_gateway_id' => $this->wepay_payment_driver->company_gateway->hashed_id]),
|
||||
'unique_id' => Str::random(40),
|
||||
@ -221,6 +226,10 @@ class ACH
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
catch(\Exception $e){
|
||||
throw new PaymentFailed($e->getMessage(), 500);
|
||||
}
|
||||
|
||||
/* Merge all data and store in the payment hash*/
|
||||
$state = [
|
||||
|
@ -84,7 +84,7 @@ class AutoBillInvoice extends AbstractService
|
||||
$gateway_token = $this->getGateway($amount);
|
||||
|
||||
/* Bail out if no payment methods available */
|
||||
if (! $gateway_token || ! $gateway_token->gateway->driver($this->client)->token_billing){
|
||||
if (! $gateway_token || ! $gateway_token->gateway || ! $gateway_token->gateway->driver($this->client)->token_billing){
|
||||
nlog("Bailing out - no suitable gateway token found.");
|
||||
return $this->invoice;
|
||||
}
|
||||
@ -291,23 +291,13 @@ class AutoBillInvoice extends AbstractService
|
||||
* @param float $amount The amount to charge
|
||||
* @return ClientGatewayToken The client gateway token
|
||||
*/
|
||||
// private function
|
||||
// {
|
||||
// $gateway_tokens = $this->client->gateway_tokens()->orderBy('is_default', 'DESC')->get();
|
||||
|
||||
// foreach ($gateway_tokens as $gateway_token) {
|
||||
// if ($this->validGatewayLimits($gateway_token, $amount)) {
|
||||
// return $gateway_token;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public function getGateway($amount)
|
||||
{
|
||||
|
||||
//get all client gateway tokens and set the is_default one to the first record
|
||||
//$gateway_tokens = $this->client->gateway_tokens()->orderBy('is_default', 'DESC');
|
||||
$gateway_tokens = $this->client->gateway_tokens;
|
||||
$gateway_tokens = $this->client->gateway_tokens()->orderBy('is_default', 'DESC');
|
||||
// $gateway_tokens = $this->client->gateway_tokens;
|
||||
|
||||
$filtered_gateways = $gateway_tokens->filter(function ($gateway_token) use($amount) {
|
||||
|
||||
|
@ -242,6 +242,7 @@ class RefundPayment
|
||||
|
||||
$invoice->service()->updateBalance($refunded_invoice['amount'])->save();
|
||||
$invoice->ledger()->updateInvoiceBalance($refunded_invoice['amount'], "Refund of payment # {$this->payment->number}")->save();
|
||||
$invoice->paid_to_date -= $refunded_invoice['amount'];
|
||||
|
||||
if ($invoice->amount == $invoice->balance) {
|
||||
$invoice->service()->setStatus(Invoice::STATUS_SENT);
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.3.18',
|
||||
'app_tag' => '5.3.18',
|
||||
'app_version' => '5.3.19',
|
||||
'app_tag' => '5.3.19',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
4
public/flutter_service_worker.js
vendored
4
public/flutter_service_worker.js
vendored
@ -4,7 +4,7 @@ const TEMP = 'flutter-temp-cache';
|
||||
const CACHE_NAME = 'flutter-app-cache';
|
||||
const RESOURCES = {
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"/": "046e0fcccb3cc2bf087c3ca7100aab14",
|
||||
"/": "0d9690c2b925c794b94e0778817e5c19",
|
||||
"assets/NOTICES": "9eb7e2eb2888ea5bae5f536720db37cd",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
|
||||
@ -34,7 +34,7 @@ const RESOURCES = {
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"main.dart.js": "cad794ed29ee69bb27294af52f923f50"
|
||||
"main.dart.js": "9542568225b6ad9e1ffbc87c3e6f74a2"
|
||||
};
|
||||
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
File diff suppressed because one or more lines are too long
135292
public/main.dart.js
vendored
135292
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
137962
public/main.foss.dart.js
vendored
137962
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
136995
public/main.last.dart.js
vendored
136995
public/main.last.dart.js
vendored
File diff suppressed because one or more lines are too long
150000
public/main.next.dart.js
vendored
150000
public/main.next.dart.js
vendored
File diff suppressed because one or more lines are too long
510
public/main.profile.dart.js
vendored
510
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
134306
public/main.wasm.dart.js
vendored
134306
public/main.wasm.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -15,7 +15,7 @@
|
||||
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=08ea84e9451abd434cff",
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=73b66e88e2daabcd6549",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=c2b5f7831e1a46dd5fb2",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=994c79534ee0a7391f69",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=070c86b293b532c5a56c",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=81c2623fc1e5769b51c7",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=665ddf663500767f1a17",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=a30464874dee84678344",
|
||||
|
@ -43,12 +43,62 @@ class SquareCreditCard {
|
||||
}
|
||||
}
|
||||
|
||||
// ,
|
||||
// function(err,verification) {
|
||||
// if (err == null) {
|
||||
// console.log("no error");
|
||||
// console.log(verification);
|
||||
// verificationToken = verificationResults.token;
|
||||
|
||||
// }
|
||||
|
||||
// console.log(err);
|
||||
|
||||
// die("verify buyer");
|
||||
// }
|
||||
|
||||
|
||||
async completePaymentWithoutToken(e) {
|
||||
document.getElementById('errors').hidden = true;
|
||||
e.target.parentElement.disabled = true;
|
||||
|
||||
let result = await this.card.tokenize();
|
||||
|
||||
console.log("square token = " + result.token);
|
||||
|
||||
/* SCA */
|
||||
let verificationToken;
|
||||
|
||||
try {
|
||||
const verificationDetails = {
|
||||
amount: document.querySelector('meta[name=amount]').content,
|
||||
billingContact: JSON.parse(document.querySelector('meta[name=square_contact]').content),
|
||||
currencyCode: document.querySelector('meta[name=currencyCode]').content,
|
||||
intent: 'CHARGE'
|
||||
};
|
||||
|
||||
console.log(verificationDetails);
|
||||
|
||||
const verificationResults = await this.payments.verifyBuyer(
|
||||
result.token,
|
||||
verificationDetails
|
||||
);
|
||||
|
||||
verificationToken = verificationResults.token;
|
||||
}
|
||||
catch(typeError){
|
||||
console.log(typeError);
|
||||
die("failed in the catch");
|
||||
}
|
||||
// console.log(" verification tokem = " + verificationToken.token);
|
||||
|
||||
// verificationToken = verificationResults.token;
|
||||
|
||||
console.debug('Verification Token:', verificationToken);
|
||||
|
||||
document.querySelector('input[name="verificationToken"]').value =
|
||||
verificationToken;
|
||||
|
||||
if (result.status === 'OK') {
|
||||
document.getElementById('sourceId').value = result.token;
|
||||
|
||||
@ -77,6 +127,28 @@ class SquareCreditCard {
|
||||
return document.getElementById('server_response').submit();
|
||||
}
|
||||
|
||||
/* SCA */
|
||||
async verifyBuyer(token) {
|
||||
|
||||
console.log("in verify buyer");
|
||||
|
||||
const verificationDetails = {
|
||||
amount: document.querySelector('meta[name=amount]').content,
|
||||
billingContact: document.querySelector('meta[name=square_contact]').content,
|
||||
currencyCode: document.querySelector('meta[name=currencyCode]').content,
|
||||
intent: 'CHARGE'
|
||||
};
|
||||
|
||||
const verificationResults = await this.payments.verifyBuyer(
|
||||
token,
|
||||
verificationDetails
|
||||
);
|
||||
|
||||
console.log(" verification toke = " + verificationResults.token);
|
||||
|
||||
return verificationResults.token;
|
||||
}
|
||||
|
||||
async handle() {
|
||||
await this.init();
|
||||
|
||||
|
5
resources/views/errors/guest.blade.php
Normal file
5
resources/views/errors/guest.blade.php
Normal file
@ -0,0 +1,5 @@
|
||||
@extends('portal.ninja2020.layout.error')
|
||||
|
||||
@section('title', __('Server Error'))
|
||||
@section('code', '500')
|
||||
@section('message', __($message) ?: 'System Error')
|
@ -4,6 +4,10 @@
|
||||
@section('gateway_head')
|
||||
<meta name="square-appId" content="{{ $gateway->company_gateway->getConfigField('applicationId') }}">
|
||||
<meta name="square-locationId" content="{{ $gateway->company_gateway->getConfigField('locationId') }}">
|
||||
<meta name="square_contact" content="{{ json_encode($square_contact) }}">
|
||||
<meta name="amount" content="{{ $amount }}">
|
||||
<meta name="currencyCode" content="{{ $currencyCode }}">
|
||||
|
||||
@endsection
|
||||
|
||||
@section('gateway_content')
|
||||
@ -17,6 +21,7 @@
|
||||
|
||||
<input type="hidden" name="token">
|
||||
<input type="hidden" name="sourceId" id="sourceId">
|
||||
<input type="hidden" name="verificationToken" id="verificationToken">
|
||||
</form>
|
||||
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user